diff --git a/CHANGELOG.md b/CHANGELOG.md index ce95c5fdd..7a85ee34e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 2022-03-21 CORE 8.2.0 + +* core-gui + * improved failed starts to trigger runtime to allow node investigation +* core-daemon + * improved default service loading to use a full import path + * updated session instantiation to always set to a runtime state +* core-cli + * \#672 - fixed xml loading + * \#578 - restored json flag and added geo output to session overview +* Documentation + * updated emane example and documentation + * improved table markdown + ## 2022-02-18 CORE 8.1.0 * Installation diff --git a/README.md b/README.md index 3cd4ae9ee..8dbe4e561 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ source ~/.bashrc # Ubuntu inv install # CentOS -./install.sh -p /usr +inv install -p /usr ``` ## Documentation & Support diff --git a/configure.ac b/configure.ac index a3d61abc5..78980b563 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. # this defines the CORE version number, must be static for AC_INIT -AC_INIT(core, 8.1.0) +AC_INIT(core, 8.2.0) # autoconf and automake initialization AC_CONFIG_SRCDIR([netns/version.h.in]) diff --git a/daemon/core/api/grpc/wrappers.py b/daemon/core/api/grpc/wrappers.py index ffeb67933..94a1598c7 100644 --- a/daemon/core/api/grpc/wrappers.py +++ b/daemon/core/api/grpc/wrappers.py @@ -637,6 +637,15 @@ def from_proto(cls, proto: core_pb2.SessionSummary) -> "SessionSummary": dir=proto.dir, ) + def to_proto(self) -> core_pb2.SessionSummary: + return core_pb2.SessionSummary( + id=self.id, + state=self.state.value, + nodes=self.nodes, + file=self.file, + dir=self.dir, + ) + @dataclass class Hook: diff --git a/daemon/core/configservice/base.py b/daemon/core/configservice/base.py index 6e1dc8598..e74b0567a 100644 --- a/daemon/core/configservice/base.py +++ b/daemon/core/configservice/base.py @@ -43,6 +43,10 @@ class ConfigServiceBootError(Exception): pass +class ConfigServiceTemplateError(Exception): + pass + + @dataclass class ShadowDir: path: str @@ -316,7 +320,13 @@ def get_templates(self) -> Dict[str, str]: elif self.templates.has_template(template_path): template = self.templates.get_template(template_path).source else: - template = self.get_text_template(file) + try: + template = self.get_text_template(file) + except Exception as e: + raise ConfigServiceTemplateError( + f"node({self.node.name}) service({self.name}) file({file}) " + f"failure getting template: {e}" + ) template = self.clean_text(template) templates[file] = template return templates @@ -340,7 +350,13 @@ def create_files(self) -> None: elif self.templates.has_template(template_path): rendered = self.render_template(template_path, data) else: - text = self.get_text_template(file) + try: + text = self.get_text_template(file) + except Exception as e: + raise ConfigServiceTemplateError( + f"node({self.node.name}) service({self.name}) file({file}) " + f"failure getting template: {e}" + ) rendered = self.render_text(text, data) self.node.create_file(file_path, rendered) @@ -429,20 +445,20 @@ def render_text(self, text: str, data: Dict[str, Any] = None) -> str: f"{exceptions.text_error_template().render_unicode()}" ) - def render_template(self, basename: str, data: Dict[str, Any] = None) -> str: + def render_template(self, template_path: str, data: Dict[str, Any] = None) -> str: """ Renders file based template providing all associated data to template. - :param basename: base name for file to render + :param template_path: path of file to render :param data: service specific defined data for template :return: rendered template """ try: - template = self.templates.get_template(basename) + template = self.templates.get_template(template_path) return self._render(template, data) except Exception: raise CoreError( - f"node({self.node.name}) service({self.name}) " + f"node({self.node.name}) service({self.name}) file({template_path})" f"{exceptions.text_error_template().render_template()}" ) diff --git a/daemon/core/emulator/coreemu.py b/daemon/core/emulator/coreemu.py index 179faf9cc..9baadb545 100644 --- a/daemon/core/emulator/coreemu.py +++ b/daemon/core/emulator/coreemu.py @@ -6,7 +6,6 @@ from pathlib import Path from typing import Dict, List, Type -import core.services from core import utils from core.configservice.manager import ConfigServiceManager from core.emane.modelmanager import EmaneModelManager @@ -92,7 +91,7 @@ def _load_services(self) -> None: :return: nothing """ # load default services - self.service_errors = core.services.load() + self.service_errors = ServiceManager.load_locals() # load custom services service_paths = self.config.get("custom_services_dir") logger.debug("custom service paths: %s", service_paths) diff --git a/daemon/core/emulator/session.py b/daemon/core/emulator/session.py index 46f9a04f1..219555d52 100644 --- a/daemon/core/emulator/session.py +++ b/daemon/core/emulator/session.py @@ -694,7 +694,11 @@ def add_hook( self.run_hook(hook) def add_node_file( - self, node_id: int, src_path: Path, file_path: Path, data: str + self, + node_id: int, + src_path: Optional[Path], + file_path: Path, + data: Optional[str], ) -> None: """ Add a file to a node. @@ -707,7 +711,7 @@ def add_node_file( """ node = self.get_node(node_id, CoreNode) if src_path is not None: - node.addfile(src_path, file_path) + node.copy_file(src_path, file_path) elif data is not None: node.create_file(file_path, data) @@ -1173,34 +1177,30 @@ def instantiate(self) -> List[Exception]: :return: list of service boot errors during startup """ + if self.state == EventTypes.RUNTIME_STATE: + logger.warning("ignoring instantiate, already in runtime state") + return [] # write current nodes out to session directory file self.write_nodes() - # create control net interfaces and network tunnels # which need to exist for emane to sync on location events # in distributed scenarios self.add_remove_control_net(0, remove=False) - # initialize distributed tunnels self.distributed.start() - # instantiate will be invoked again upon emane configure if self.emane.startup() == EmaneState.NOT_READY: return [] - # boot node services and then start mobility exceptions = self.boot_nodes() if not exceptions: self.mobility.startup() - # notify listeners that instantiation is complete event = EventData(event_type=EventTypes.INSTANTIATION_COMPLETE) self.broadcast_event(event) - - # assume either all nodes have booted already, or there are some - # nodes on slave servers that will be booted and those servers will - # send a node status response message - self.check_runtime() + # startup event loop + self.event_loop.run() + self.set_state(EventTypes.RUNTIME_STATE, send_event=True) return exceptions def get_node_count(self) -> int: @@ -1222,28 +1222,6 @@ def get_node_count(self) -> int: count += 1 return count - def check_runtime(self) -> None: - """ - Check if we have entered the runtime state, that all nodes have been - started and the emulation is running. Start the event loop once we - have entered runtime (time=0). - - :return: nothing - """ - # this is called from instantiate() after receiving an event message - # for the instantiation state - logger.debug( - "session(%s) checking if not in runtime state, current state: %s", - self.id, - self.state.name, - ) - if self.state == EventTypes.RUNTIME_STATE: - logger.info("valid runtime state found, returning") - return - # start event loop and set to runtime - self.event_loop.run() - self.set_state(EventTypes.RUNTIME_STATE, send_event=True) - def data_collect(self) -> None: """ Tear down a running session. Stop the event loop and any running diff --git a/daemon/core/errors.py b/daemon/core/errors.py index 20ffc3a9a..83d252b89 100644 --- a/daemon/core/errors.py +++ b/daemon/core/errors.py @@ -11,7 +11,7 @@ class CoreCommandError(subprocess.CalledProcessError): def __str__(self) -> str: return ( - f"Command({self.cmd}), Status({self.returncode}):\n" + f"command({self.cmd}), status({self.returncode}):\n" f"stdout: {self.output}\nstderr: {self.stderr}" ) diff --git a/daemon/core/gui/toolbar.py b/daemon/core/gui/toolbar.py index faf8ab361..7392071dd 100644 --- a/daemon/core/gui/toolbar.py +++ b/daemon/core/gui/toolbar.py @@ -304,16 +304,13 @@ def click_start(self) -> None: task.start() def start_callback(self, result: bool, exceptions: List[str]) -> None: - if result: - self.set_runtime() - self.app.core.show_mobility_players() - else: - enable_buttons(self.design_frame, enabled=True) - if exceptions: - message = "\n".join(exceptions) - self.app.show_exception_data( - "Start Exception", "Session failed to start", message - ) + self.set_runtime() + self.app.core.show_mobility_players() + if not result and exceptions: + message = "\n".join(exceptions) + self.app.show_exception_data( + "Start Exception", "Session failed to start", message + ) def set_runtime(self) -> None: enable_buttons(self.runtime_frame, enabled=True) diff --git a/daemon/core/nodes/base.py b/daemon/core/nodes/base.py index 3b5cd04e2..34bf66018 100644 --- a/daemon/core/nodes/base.py +++ b/daemon/core/nodes/base.py @@ -16,8 +16,7 @@ from core.emulator.data import InterfaceData, LinkData from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes from core.errors import CoreCommandError, CoreError -from core.executables import MOUNT, TEST, VNODED -from core.nodes.client import VnodeClient +from core.executables import BASH, MOUNT, TEST, VCMD, VNODED from core.nodes.interface import DEFAULT_MTU, CoreInterface, TunTap, Veth from core.nodes.netclient import LinuxNetClient, get_net_client @@ -271,18 +270,6 @@ def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None: """ raise NotImplementedError - @abc.abstractmethod - def addfile(self, src_path: Path, file_path: Path) -> None: - """ - Add a file. - - :param src_path: source file path - :param file_path: file name to add - :return: nothing - :raises CoreCommandError: when a non-zero exit status occurs - """ - raise NotImplementedError - @abc.abstractmethod def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: """ @@ -516,7 +503,6 @@ def __init__( super().__init__(session, _id, name, server) self.directory: Optional[Path] = directory self.ctrlchnlname: Path = self.session.directory / self.name - self.client: Optional[VnodeClient] = None self.pid: Optional[int] = None self.lock: RLock = RLock() self._mounts: List[Tuple[Path, Path]] = [] @@ -558,7 +544,6 @@ def startup(self) -> None: self.makenodedir() if self.up: raise ValueError("starting a node that is already up") - # create a new namespace for this node using vnoded vnoded = ( f"{VNODED} -v -c {self.ctrlchnlname} -l {self.ctrlchnlname}.log " @@ -569,25 +554,17 @@ def startup(self) -> None: env = self.session.get_environment(state=False) env["NODE_NUMBER"] = str(self.id) env["NODE_NAME"] = str(self.name) - output = self.host_cmd(vnoded, env=env) self.pid = int(output) logger.debug("node(%s) pid: %s", self.name, self.pid) - - # create vnode client - self.client = VnodeClient(self.name, self.ctrlchnlname) - # bring up the loopback interface logger.debug("bringing up loopback interface") self.node_net_client.device_up("lo") - # set hostname for node logger.debug("setting hostname: %s", self.name) self.node_net_client.set_hostname(self.name) - # mark node as up self.up = True - # create private directories for dir_path in PRIVATE_DIRS: self.create_dir(dir_path) @@ -621,13 +598,24 @@ def shutdown(self) -> None: logger.exception("error removing node directory") # clear interface data, close client, and mark self and not up self.ifaces.clear() - self.client.close() self.up = False except OSError: logger.exception("error during shutdown") finally: self.rmnodedir() + def _create_cmd(self, args: str, shell: bool = False) -> str: + """ + Create command used to run commands within the context of a node. + + :param args: command arguments + :param shell: True to run shell like, False otherwise + :return: node command + """ + if shell: + args = f'{BASH} -c "{args}"' + return f"{VCMD} -c {self.ctrlchnlname} -- {args}" + def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: """ Runs a command that is used to configure and setup the network within a @@ -639,10 +627,10 @@ def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: :return: combined stdout and stderr :raises CoreCommandError: when a non-zero exit status occurs """ + args = self._create_cmd(args, shell) if self.server is None: - return self.client.check_cmd(args, wait=wait, shell=shell) + return utils.cmd(args, wait=wait, shell=shell) else: - args = self.client.create_cmd(args, shell) return self.server.remote_cmd(args, wait=wait) def path_exists(self, path: str) -> bool: @@ -665,7 +653,7 @@ def termcmdstring(self, sh: str = "/bin/sh") -> str: :param sh: shell to execute command in :return: str """ - terminal = self.client.create_cmd(sh) + terminal = self._create_cmd(sh) if self.server is None: return terminal else: @@ -847,28 +835,9 @@ def new_iface( self.ifup(iface_id) return self.get_iface(iface_id) - def addfile(self, src_path: Path, file_path: Path) -> None: - """ - Add a file. - - :param src_path: source file path - :param file_path: file name to add - :return: nothing - :raises CoreCommandError: when a non-zero exit status occurs - """ - logger.info("adding file from %s to %s", src_path, file_path) - directory = file_path.parent - if self.server is None: - self.client.check_cmd(f"mkdir -p {directory}") - self.client.check_cmd(f"mv {src_path} {file_path}") - self.client.check_cmd("sync") - else: - self.host_cmd(f"mkdir -p {directory}") - self.server.remote_put(src_path, file_path) - def _find_parent_path(self, path: Path) -> Optional[Path]: """ - Check if there is an existing mounted parent directory created for this node. + Check if there is a mounted parent directory created for this node. :param path: existing parent path to use :return: exist parent path if exists, None otherwise @@ -1000,7 +969,15 @@ def linknet(self, net: "CoreNetworkBase") -> CoreInterface: """ raise NotImplementedError + @abc.abstractmethod def custom_iface(self, node: CoreNode, iface_data: InterfaceData) -> CoreInterface: + """ + Defines custom logic for creating an interface, if required. + + :param node: node to create interface for + :param iface_data: data for creating interface + :return: created interface + """ raise NotImplementedError def get_linked_iface(self, net: "CoreNetworkBase") -> Optional[CoreInterface]: diff --git a/daemon/core/nodes/client.py b/daemon/core/nodes/client.py deleted file mode 100644 index c3afb9073..000000000 --- a/daemon/core/nodes/client.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -client.py: implementation of the VnodeClient class for issuing commands -over a control channel to the vnoded process running in a network namespace. -The control channel can be accessed via calls using the vcmd shell. -""" -from pathlib import Path - -from core import utils -from core.executables import BASH, VCMD - - -class VnodeClient: - """ - Provides client functionality for interacting with a virtual node. - """ - - def __init__(self, name: str, ctrlchnlname: Path) -> None: - """ - Create a VnodeClient instance. - - :param name: name for client - :param ctrlchnlname: control channel name - """ - self.name: str = name - self.ctrlchnlname: Path = ctrlchnlname - - def _verify_connection(self) -> None: - """ - Checks that the vcmd client is properly connected. - - :return: nothing - :raises IOError: when not connected - """ - if not self.connected(): - raise IOError("vcmd not connected") - - def connected(self) -> bool: - """ - Check if node is connected or not. - - :return: True if connected, False otherwise - """ - return True - - def close(self) -> None: - """ - Close the client connection. - - :return: nothing - """ - pass - - def create_cmd(self, args: str, shell: bool = False) -> str: - if shell: - args = f'{BASH} -c "{args}"' - return f"{VCMD} -c {self.ctrlchnlname} -- {args}" - - def check_cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: - """ - Run command and return exit status and combined stdout and stderr. - - :param args: command to run - :param wait: True to wait for command status, False otherwise - :param shell: True to use shell, False otherwise - :return: combined stdout and stderr - :raises core.CoreCommandError: when there is a non-zero exit status - """ - self._verify_connection() - args = self.create_cmd(args, shell) - return utils.cmd(args, wait=wait, shell=shell) diff --git a/daemon/core/nodes/network.py b/daemon/core/nodes/network.py index 4337daa88..262d422c0 100644 --- a/daemon/core/nodes/network.py +++ b/daemon/core/nodes/network.py @@ -22,7 +22,7 @@ ) from core.errors import CoreCommandError, CoreError from core.executables import NFTABLES -from core.nodes.base import CoreNetworkBase +from core.nodes.base import CoreNetworkBase, CoreNode from core.nodes.interface import CoreInterface, GreTap, Veth from core.nodes.netclient import get_net_client @@ -436,6 +436,9 @@ def add_ips(self, ips: List[str]) -> None: for ip in ips: self.net_client.create_address(self.brname, ip) + def custom_iface(self, node: CoreNode, iface_data: InterfaceData) -> CoreInterface: + raise CoreError(f"{type(self).__name__} does not support, custom interfaces") + class GreTapBridge(CoreNetwork): """ diff --git a/daemon/core/nodes/physical.py b/daemon/core/nodes/physical.py index 5c1cfe2eb..0a686da8e 100644 --- a/daemon/core/nodes/physical.py +++ b/daemon/core/nodes/physical.py @@ -187,21 +187,17 @@ def umount(self, target_path: Path) -> None: except CoreCommandError: logger.exception("unmounting failed for %s", target_path) - def nodefile(self, file_path: Path, contents: str, mode: int = 0o644) -> None: - host_path = self.host_path(file_path) - directory = host_path.parent - if not directory.is_dir(): - directory.mkdir(parents=True, mode=0o755) - with host_path.open("w") as f: - f.write(contents) - host_path.chmod(mode) - logger.info("created nodefile: '%s'; mode: 0%o", host_path, mode) - def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: return self.host_cmd(args, wait=wait) - def addfile(self, src_path: str, file_path: str) -> None: - raise CoreError("physical node does not support addfile") + def create_dir(self, dir_path: Path) -> None: + raise CoreError("physical node does not support creating directories") + + def create_file(self, file_path: Path, contents: str, mode: int = 0o644) -> None: + raise CoreError("physical node does not support creating files") + + def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None: + raise CoreError("physical node does not support copying files") class Rj45Node(CoreNodeBase): @@ -430,12 +426,6 @@ def setposition(self, x: float = None, y: float = None, z: float = None) -> None def termcmdstring(self, sh: str) -> str: raise CoreError("rj45 does not support terminal commands") - def addfile(self, src_path: str, file_path: str) -> None: - raise CoreError("rj45 does not support addfile") - - def nodefile(self, file_path: str, contents: str, mode: int = 0o644) -> None: - raise CoreError("rj45 does not support nodefile") - def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str: raise CoreError("rj45 does not support cmds") diff --git a/daemon/core/services/__init__.py b/daemon/core/services/__init__.py index 4d9b90a29..e69de29bb 100644 --- a/daemon/core/services/__init__.py +++ b/daemon/core/services/__init__.py @@ -1,20 +0,0 @@ -""" -Services - -Services available to nodes can be put in this directory. Everything listed in -__all__ is automatically loaded by the main core module. -""" -from pathlib import Path - -from core.services.coreservices import ServiceManager - -_PATH: Path = Path(__file__).resolve().parent - - -def load(): - """ - Loads all services from the modules that reside under core.services. - - :return: list of services that failed to load - """ - return ServiceManager.add_services(_PATH) diff --git a/daemon/core/services/coreservices.py b/daemon/core/services/coreservices.py index b12f21c43..8d611d4b9 100644 --- a/daemon/core/services/coreservices.py +++ b/daemon/core/services/coreservices.py @@ -9,6 +9,7 @@ import enum import logging +import pkgutil import time from pathlib import Path from typing import ( @@ -23,6 +24,7 @@ Union, ) +from core import services as core_services from core import utils from core.emulator.data import FileData from core.emulator.enumerations import ExceptionLevels, MessageFlags, RegisterTlvs @@ -181,6 +183,8 @@ def setvalue(cls, service: "CoreService", key: str, value: str) -> None: if value: if key == "startidx": value = int(value) + elif key == "starttime": + value = float(value) elif key == "meta": value = str(value) else: @@ -231,25 +235,25 @@ def add(cls, service: Type["CoreService"]) -> None: """ name = service.name logger.debug("loading service: class(%s) name(%s)", service.__name__, name) - + # avoid services with no name + if name is None: + logger.debug("not loading class(%s) with no name", service.__name__) + return # avoid duplicate services if name in cls.services: - raise ValueError("duplicate service being added: %s" % name) - + raise ValueError(f"duplicate service being added: {name}") # validate dependent executables are present for executable in service.executables: try: utils.which(executable, required=True) except CoreError as e: raise CoreError(f"service({name}): {e}") - # validate service on load succeeds try: service.on_load() except Exception as e: logger.exception("error during service(%s) on load", service.name) raise ValueError(e) - # make service available cls.services[name] = service @@ -286,6 +290,21 @@ def add_services(cls, path: Path) -> List[str]: logger.debug("not loading service(%s): %s", service.name, e) return service_errors + @classmethod + def load_locals(cls) -> List[str]: + errors = [] + for module_info in pkgutil.walk_packages( + core_services.__path__, f"{core_services.__name__}." + ): + services = utils.load_module(module_info.name, CoreService) + for service in services: + try: + cls.add(service) + except CoreError as e: + errors.append(service.name) + logger.debug("not loading service(%s): %s", service.name, e) + return errors + class CoreServices: """ diff --git a/daemon/core/utils.py b/daemon/core/utils.py index fcc378428..c9604f087 100644 --- a/daemon/core/utils.py +++ b/daemon/core/utils.py @@ -227,6 +227,7 @@ def cmd( execute is not found """ logger.debug("command cwd(%s) wait(%s): %s", cwd, wait, args) + input_args = args if shell is False: args = shlex.split(args) try: @@ -238,13 +239,13 @@ def cmd( stderr = stderr.decode("utf-8").strip() status = p.wait() if status != 0: - raise CoreCommandError(status, args, stdout, stderr) + raise CoreCommandError(status, input_args, stdout, stderr) return stdout else: return "" except OSError as e: logger.error("cmd error: %s", e.strerror) - raise CoreCommandError(1, args, "", e.strerror) + raise CoreCommandError(1, input_args, "", e.strerror) def file_munge(pathname: str, header: str, text: str) -> None: diff --git a/daemon/pyproject.toml b/daemon/pyproject.toml index a92cc994a..9e11d3f6f 100644 --- a/daemon/pyproject.toml +++ b/daemon/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "core" -version = "8.1.0" +version = "8.2.0" description = "CORE Common Open Research Emulator" authors = ["Boeing Research and Technology"] license = "BSD-2-Clause" diff --git a/daemon/scripts/core-cli b/daemon/scripts/core-cli index fbbe6ede6..6f2c1f5ba 100755 --- a/daemon/scripts/core-cli +++ b/daemon/scripts/core-cli @@ -1,22 +1,24 @@ #!/usr/bin/env python3 +import json import sys from argparse import ( ArgumentDefaultsHelpFormatter, ArgumentParser, ArgumentTypeError, Namespace, - _SubParsersAction, ) from functools import wraps from pathlib import Path -from typing import Optional, Tuple +from typing import Any, Dict, Optional, Tuple import grpc import netaddr +from google.protobuf.json_format import MessageToDict from netaddr import EUI, AddrFormatError, IPNetwork from core.api.grpc.client import CoreGrpcClient from core.api.grpc.wrappers import ( + ConfigOption, Geo, Interface, Link, @@ -29,6 +31,15 @@ from core.api.grpc.wrappers import ( NODE_TYPES = [x for x in NodeType if x != NodeType.PEER_TO_PEER] +def protobuf_to_json(message: Any) -> Dict[str, Any]: + return MessageToDict(message, including_default_value_fields=True, preserving_proto_field_name=True) + + +def print_json(data: Any) -> None: + data = json.dumps(data, indent=2) + print(data) + + def coreclient(func): @wraps(func) def wrapper(*args, **kwargs): @@ -94,11 +105,11 @@ def geo_type(value: str) -> Tuple[float, float, float]: return lon, lat, alt -def file_type(value: str) -> str: +def file_type(value: str) -> Path: path = Path(value) if not path.is_file(): raise ArgumentTypeError(f"invalid file: {value}") - return str(path.absolute()) + return path def get_current_session(core: CoreGrpcClient, session_id: Optional[int]) -> int: @@ -140,12 +151,15 @@ def print_iface(iface: Interface) -> None: def get_wlan_config(core: CoreGrpcClient, args: Namespace) -> None: session_id = get_current_session(core, args.session) config = core.get_wlan_config(session_id, args.node) - size = 0 - for option in config.values(): - size = max(size, len(option.name)) - print(f"{'Name':<{size}.{size}} | Value") - for option in config.values(): - print(f"{option.name:<{size}.{size}} | {option.value}") + if args.json: + print_json(ConfigOption.to_dict(config)) + else: + size = 0 + for option in config.values(): + size = max(size, len(option.name)) + print(f"{'Name':<{size}.{size}} | Value") + for option in config.values(): + print(f"{option.name:<{size}.{size}} | {option.value}") @coreclient @@ -163,80 +177,102 @@ def set_wlan_config(core: CoreGrpcClient, args: Namespace) -> None: if args.range: config["range"] = str(args.range) result = core.set_wlan_config(session_id, args.node, config) - print(f"set wlan config: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"set wlan config: {result}") @coreclient def open_xml(core: CoreGrpcClient, args: Namespace) -> None: result, session_id = core.open_xml(args.file, args.start) - print(f"opened xml: {result},{session_id}") + if args.json: + print_json(dict(result=result, session_id=session_id)) + else: + print(f"opened xml: {result},{session_id}") @coreclient def query_sessions(core: CoreGrpcClient, args: Namespace) -> None: sessions = core.get_sessions() - print("Session ID | Session State | Nodes") - for session in sessions: - print(f"{session.id:<10} | {session.state.name:<13} | {session.nodes}") + if args.json: + sessions = [protobuf_to_json(x.to_proto()) for x in sessions] + print_json(sessions) + else: + print("Session ID | Session State | Nodes") + for session in sessions: + print(f"{session.id:<10} | {session.state.name:<13} | {session.nodes}") @coreclient def query_session(core: CoreGrpcClient, args: Namespace) -> None: session = core.get_session(args.id) - print("Nodes") - print("Node ID | Node Name | Node Type") - for node in session.nodes.values(): - print(f"{node.id:<7} | {node.name:<9} | {node.type.name}") - print("\nLinks") - for link in session.links: - n1 = session.nodes[link.node1_id].name - n2 = session.nodes[link.node2_id].name - print(f"Node | ", end="") - print_iface_header() - print(f"{n1:<6} | ", end="") - if link.iface1: - print_iface(link.iface1) - else: - print() - print(f"{n2:<6} | ", end="") - if link.iface2: - print_iface(link.iface2) - else: + if args.json: + session = protobuf_to_json(session.to_proto()) + print_json(session) + else: + print("Nodes") + print("ID | Name | Type | XY | Geo") + for node in session.nodes.values(): + xy_pos = f"{int(node.position.x)},{int(node.position.y)}" + geo_pos = f"{node.geo.lon:.7f},{node.geo.lat:.7f},{node.geo.alt:f}" + print(f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}") + print("\nLinks") + for link in session.links: + n1 = session.nodes[link.node1_id].name + n2 = session.nodes[link.node2_id].name + print(f"Node | ", end="") + print_iface_header() + print(f"{n1:<6} | ", end="") + if link.iface1: + print_iface(link.iface1) + else: + print() + print(f"{n2:<6} | ", end="") + if link.iface2: + print_iface(link.iface2) + else: + print() print() - print() @coreclient def query_node(core: CoreGrpcClient, args: Namespace) -> None: session = core.get_session(args.id) node, ifaces, _ = core.get_node(args.id, args.node) - print("ID | Name | Type | XY") - xy_pos = f"{int(node.position.x)},{int(node.position.y)}" - print(f"{node.id:<4} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos}") - if node.geo: - print("Geo") - print(f"{node.geo.lon:.7f},{node.geo.lat:.7f},{node.geo.alt:f}") - if ifaces: - print("Interfaces") - print("Connected To | ", end="") - print_iface_header() - for iface in ifaces: - if iface.net_id == node.id: - if iface.node_id: - name = session.nodes[iface.node_id].name + if args.json: + node = protobuf_to_json(node.to_proto()) + ifaces = [protobuf_to_json(x.to_proto()) for x in ifaces] + print_json(dict(node=node, ifaces=ifaces)) + else: + print("ID | Name | Type | XY | Geo") + xy_pos = f"{int(node.position.x)},{int(node.position.y)}" + geo_pos = f"{node.geo.lon:.7f},{node.geo.lat:.7f},{node.geo.alt:f}" + print(f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}") + if ifaces: + print("Interfaces") + print("Connected To | ", end="") + print_iface_header() + for iface in ifaces: + if iface.net_id == node.id: + if iface.node_id: + name = session.nodes[iface.node_id].name + else: + name = session.nodes[iface.net2_id].name else: - name = session.nodes[iface.net2_id].name - else: - net_node = session.nodes.get(iface.net_id) - name = net_node.name if net_node else "" - print(f"{name:<12} | ", end="") - print_iface(iface) + net_node = session.nodes.get(iface.net_id) + name = net_node.name if net_node else "" + print(f"{name:<12} | ", end="") + print_iface(iface) @coreclient def delete_session(core: CoreGrpcClient, args: Namespace) -> None: result = core.delete_session(args.id) - print(f"delete session({args.id}): {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"delete session({args.id}): {result}") @coreclient @@ -263,14 +299,20 @@ def add_node(core: CoreGrpcClient, args: Namespace) -> None: geo=geo, ) node_id = core.add_node(session_id, node) - print(f"created node: {node_id}") + if args.json: + print_json(dict(node_id=node_id)) + else: + print(f"created node: {node_id}") @coreclient def edit_node(core: CoreGrpcClient, args: Namespace) -> None: session_id = get_current_session(core, args.session) result = core.edit_node(session_id, args.id, args.icon) - print(f"edit node: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"edit node: {result}") @coreclient @@ -285,14 +327,20 @@ def move_node(core: CoreGrpcClient, args: Namespace) -> None: lon, lat, alt = args.geo geo = Geo(lon=lon, lat=lat, alt=alt) result = core.move_node(session_id, args.id, pos, geo) - print(f"move node: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"move node: {result}") @coreclient def delete_node(core: CoreGrpcClient, args: Namespace) -> None: session_id = get_current_session(core, args.session) result = core.delete_node(session_id, args.id) - print(f"deleted node: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"deleted node: {result}") @coreclient @@ -313,8 +361,13 @@ def add_link(core: CoreGrpcClient, args: Namespace) -> None: unidirectional=args.uni, ) link = Link(args.node1, args.node2, iface1=iface1, iface2=iface2, options=options) - result, _, _ = core.add_link(session_id, link) - print(f"add link: {result}") + result, iface1, iface2 = core.add_link(session_id, link) + if args.json: + iface1 = protobuf_to_json(iface1.to_proto()) + iface2 = protobuf_to_json(iface2.to_proto()) + print_json(dict(result=result, iface1=iface1, iface2=iface2)) + else: + print(f"add link: {result}") @coreclient @@ -332,7 +385,10 @@ def edit_link(core: CoreGrpcClient, args: Namespace) -> None: iface2 = Interface(args.iface2) link = Link(args.node1, args.node2, iface1=iface1, iface2=iface2, options=options) result = core.edit_link(session_id, link) - print(f"edit link: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"edit link: {result}") @coreclient @@ -342,10 +398,13 @@ def delete_link(core: CoreGrpcClient, args: Namespace) -> None: iface2 = Interface(args.iface2) link = Link(args.node1, args.node2, iface1=iface1, iface2=iface2) result = core.delete_link(session_id, link) - print(f"delete link: {result}") + if args.json: + print_json(dict(result=result)) + else: + print(f"delete link: {result}") -def setup_sessions_parser(parent: _SubParsersAction) -> None: +def setup_sessions_parser(parent) -> None: parser = parent.add_parser("session", help="session interactions") parser.formatter_class = ArgumentDefaultsHelpFormatter parser.add_argument("-i", "--id", type=int, help="session id to use", required=True) @@ -358,7 +417,7 @@ def setup_sessions_parser(parent: _SubParsersAction) -> None: delete_parser.set_defaults(func=delete_session) -def setup_node_parser(parent: _SubParsersAction) -> None: +def setup_node_parser(parent) -> None: parser = parent.add_parser("node", help="node interactions") parser.formatter_class = ArgumentDefaultsHelpFormatter parser.add_argument("-s", "--session", type=int, help="session to interact with") @@ -402,7 +461,7 @@ def setup_node_parser(parent: _SubParsersAction) -> None: delete_parser.set_defaults(func=delete_node) -def setup_link_parser(parent: _SubParsersAction) -> None: +def setup_link_parser(parent) -> None: parser = parent.add_parser("link", help="link interactions") parser.formatter_class = ArgumentDefaultsHelpFormatter parser.add_argument("-s", "--session", type=int, help="session to interact with") @@ -455,7 +514,7 @@ def setup_link_parser(parent: _SubParsersAction) -> None: delete_parser.set_defaults(func=delete_link) -def setup_query_parser(parent: _SubParsersAction) -> None: +def setup_query_parser(parent) -> None: parser = parent.add_parser("query", help="query interactions") subparsers = parser.add_subparsers(help="query commands") subparsers.required = True @@ -477,7 +536,7 @@ def setup_query_parser(parent: _SubParsersAction) -> None: node_parser.set_defaults(func=query_node) -def setup_xml_parser(parent: _SubParsersAction) -> None: +def setup_xml_parser(parent) -> None: parser = parent.add_parser("xml", help="open session xml") parser.formatter_class = ArgumentDefaultsHelpFormatter parser.add_argument("-f", "--file", type=file_type, help="xml file to open", required=True) @@ -485,7 +544,7 @@ def setup_xml_parser(parent: _SubParsersAction) -> None: parser.set_defaults(func=open_xml) -def setup_wlan_parser(parent: _SubParsersAction) -> None: +def setup_wlan_parser(parent) -> None: parser = parent.add_parser("wlan", help="wlan specific interactions") parser.formatter_class = ArgumentDefaultsHelpFormatter parser.add_argument("-s", "--session", type=int, help="session to interact with") @@ -511,6 +570,9 @@ def setup_wlan_parser(parent: _SubParsersAction) -> None: def main() -> None: parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) + parser.add_argument( + "-js", "--json", action="store_true", help="print responses to terminal as json" + ) subparsers = parser.add_subparsers(help="supported commands") subparsers.required = True subparsers.dest = "command" diff --git a/daemon/tests/test_core.py b/daemon/tests/test_core.py index d7a834520..3fbd91cb2 100644 --- a/daemon/tests/test_core.py +++ b/daemon/tests/test_core.py @@ -63,39 +63,6 @@ def test_wired_ping( status = ping(node1, node2, ip_prefixes) assert not status - def test_vnode_client(self, request, session: Session, ip_prefixes: IpPrefixes): - """ - Test vnode client methods. - - :param request: pytest request - :param session: session for test - :param ip_prefixes: generates ip addresses for nodes - """ - # create ptp - ptp_node = session.add_node(PtpNet) - - # create nodes - node1 = session.add_node(CoreNode) - node2 = session.add_node(CoreNode) - - # link nodes to ptp net - for node in [node1, node2]: - iface_data = ip_prefixes.create_iface(node) - session.add_link(node.id, ptp_node.id, iface1_data=iface_data) - - # get node client for testing - client = node1.client - - # instantiate session - session.instantiate() - - # check we are connected - assert client.connected() - - # validate command - if not request.config.getoption("mock"): - assert client.check_cmd("echo hello") == "hello" - def test_iface(self, session: Session, ip_prefixes: IpPrefixes): """ Test interface methods. diff --git a/docs/configservices.md b/docs/configservices.md index 4ff8a87c1..f0fa7bddd 100644 --- a/docs/configservices.md +++ b/docs/configservices.md @@ -27,27 +27,27 @@ will allow quickly dragging and dropping that node type during creation. ## Available Services -| Service Group | Services | -|---|---| -|[BIRD](services/bird.md)|BGP, OSPF, RADV, RIP, Static| -|[EMANE](services/emane.md)|Transport Service| -|[FRR](services/frr.md)|BABEL, BGP, OSPFv2, OSPFv3, PIMD, RIP, RIPNG, Zebra| -|[NRL](services/nrl.md)|arouted, MGEN Sink, MGEN Actor, NHDP, OLSR, OLSRORG, OLSRv2, SMF| -|[Quagga](services/quagga.md)|BABEL, BGP, OSPFv2, OSPFv3, OSPFv3 MDR, RIP, RIPNG, XPIMD, Zebra| -|[SDN](services/sdn.md)|OVS, RYU| -|[Security](services/security.md)|Firewall, IPsec, NAT, VPN Client, VPN Server| -|[Utility](services/utility.md)|ATD, Routing Utils, DHCP, FTP, IP Forward, PCAP, RADVD, SSF, UCARP| -|[XORP](services/xorp.md)|BGP, OLSR, OSPFv2, OSPFv3, PIMSM4, PIMSM6, RIP, RIPNG, Router Manager| +| Service Group | Services | +|----------------------------------|-----------------------------------------------------------------------| +| [BIRD](services/bird.md) | BGP, OSPF, RADV, RIP, Static | +| [EMANE](services/emane.md) | Transport Service | +| [FRR](services/frr.md) | BABEL, BGP, OSPFv2, OSPFv3, PIMD, RIP, RIPNG, Zebra | +| [NRL](services/nrl.md) | arouted, MGEN Sink, MGEN Actor, NHDP, OLSR, OLSRORG, OLSRv2, SMF | +| [Quagga](services/quagga.md) | BABEL, BGP, OSPFv2, OSPFv3, OSPFv3 MDR, RIP, RIPNG, XPIMD, Zebra | +| [SDN](services/sdn.md) | OVS, RYU | +| [Security](services/security.md) | Firewall, IPsec, NAT, VPN Client, VPN Server | +| [Utility](services/utility.md) | ATD, Routing Utils, DHCP, FTP, IP Forward, PCAP, RADVD, SSF, UCARP | +| [XORP](services/xorp.md) | BGP, OLSR, OSPFv2, OSPFv3, PIMSM4, PIMSM6, RIP, RIPNG, Router Manager | ## Node Types and Default Services Here are the default node types and their services: -| Node Type | Services | -|---|---| -| *router* | zebra, OSFPv2, OSPFv3, and IPForward services for IGP link-state routing. | -| *PC* | DefaultRoute service for having a default route when connected directly to a router. | -| *mdr* | zebra, OSPFv3MDR, and IPForward services for wireless-optimized MANET Designated Router routing. | +| Node Type | Services | +|-----------|--------------------------------------------------------------------------------------------------------------------------------------------| +| *router* | zebra, OSFPv2, OSPFv3, and IPForward services for IGP link-state routing. | +| *PC* | DefaultRoute service for having a default route when connected directly to a router. | +| *mdr* | zebra, OSPFv3MDR, and IPForward services for wireless-optimized MANET Designated Router routing. | | *prouter* | a physical router, having the same default services as the *router* node type; for incorporating Linux testbed machines into an emulation. | Configuration files can be automatically generated by each service. For diff --git a/docs/devguide.md b/docs/devguide.md index e3b0ad189..f8524da42 100644 --- a/docs/devguide.md +++ b/docs/devguide.md @@ -9,13 +9,13 @@ The CORE source consists of several different programming languages for historical reasons. Current development focuses on the Python modules and daemon. Here is a brief description of the source directories. -| Directory | Description | -|---|---| -|daemon|Python CORE daemon code that handles receiving API calls and creating containers| -|docs|Markdown Documentation currently hosted on GitHub| -|gui|Tcl/Tk GUI| -|man|Template files for creating man pages for various CORE command line utilities| -|netns|C program for creating CORE containers| +| Directory | Description | +|-----------|--------------------------------------------------------------------------------------| +| daemon | Python CORE daemon/gui code that handles receiving API calls and creating containers | +| docs | Markdown Documentation currently hosted on GitHub | +| gui | Tcl/Tk GUI | +| man | Template files for creating man pages for various CORE command line utilities | +| netns | C program for creating CORE containers | ## Getting started diff --git a/docs/emane.md b/docs/emane.md index 9e2e5b0ba..d4f4e42cc 100644 --- a/docs/emane.md +++ b/docs/emane.md @@ -33,7 +33,7 @@ user space socket to the TAP device for sending and receiving data from CORE. An EMANE instance sends and receives OTA (Over-The-Air) traffic to and from other EMANE instances via a control port (e.g. *ctrl0*, *ctrl1*). It also sends and receives Events to and from the Event Service using the same or a -different control port. EMANE models are configured through CORE's WLAN +different control port. EMANE models are configured through the GUI's configuration dialog. A corresponding EmaneModel Python class is sub-classed for each supported EMANE model, to provide configuration items and their mapping to XML files. This way new models can be easily supported. When @@ -62,13 +62,13 @@ Every topic below assumes CORE, EMANE, and OSPF MDR have been installed. > **WARNING:** demo files will be found within the new `core-pygui` -|Topic|Model|Description| -|---|---|---| -|[XML Files](emane/files.md)|RF Pipe|Overview of generated XML files used to drive EMANE| -|[GPSD](emane/gpsd.md)|RF Pipe|Overview of running and integrating gpsd with EMANE| -|[Precomputed](emane/precomputed.md)|RF Pipe|Overview of using the precomputed propagation model| -|[EEL](emane/eel.md)|RF Pipe|Overview of using the Emulation Event Log (EEL) Generator| -|[Antenna Profiles](emane/antenna.md)|RF Pipe|Overview of using antenna profiles in EMANE| +| Topic | Model | Description | +|--------------------------------------|---------|-----------------------------------------------------------| +| [XML Files](emane/files.md) | RF Pipe | Overview of generated XML files used to drive EMANE | +| [GPSD](emane/gpsd.md) | RF Pipe | Overview of running and integrating gpsd with EMANE | +| [Precomputed](emane/precomputed.md) | RF Pipe | Overview of using the precomputed propagation model | +| [EEL](emane/eel.md) | RF Pipe | Overview of using the Emulation Event Log (EEL) Generator | +| [Antenna Profiles](emane/antenna.md) | RF Pipe | Overview of using antenna profiles in EMANE | ## EMANE Configuration @@ -201,27 +201,21 @@ EMANE. Using the primary control channel prevents your emulation session from sending multicast traffic on your local network and interfering with other EMANE users. -EMANE is configured through a WLAN node, because it is all about emulating -wireless radio networks. Once a node is linked to a WLAN cloud configured -with an EMANE model, the radio interface on that node may also be configured +EMANE is configured through an EMANE node. Once a node is linked to an EMANE +cloud, the radio interface on that node may also be configured separately (apart from the cloud.) -Double-click on a WLAN node to invoke the WLAN configuration dialog. Click -the *EMANE* tab; when EMANE has been properly installed, EMANE wireless modules -should be listed in the *EMANE Models* list. (You may need to restart the +Right click on an EMANE node and select EMANE Config to open the configuration dialog. +The EMANE models should be listed here for selection. (You may need to restart the CORE daemon if it was running prior to installing the EMANE Python bindings.) -Click on a model name to enable it. -When an EMANE model is selected in the *EMANE Models* list, clicking on the -*model options* button causes the GUI to query the CORE daemon for -configuration items. Each model will have different parameters, refer to the +When an EMANE model is selected, you can click on the models option button +causing the GUI to query the CORE daemon for configuration items. +Each model will have different parameters, refer to the EMANE documentation for an explanation of each item. The defaults values are -presented in the dialog. Clicking *Apply* and *Apply* again will store the +presented in the dialog. Clicking *Apply* and *Apply* again will store the EMANE model selections. -The *EMANE options* button allows specifying some global parameters for -EMANE, some of which are necessary for distributed operation. - The RF-PIPE and IEEE 802.11abg models use a Universal PHY that supports geographic location information for determining pathloss between nodes. A default latitude and longitude location is provided by CORE and this @@ -241,21 +235,12 @@ used to achieve geo-location accuracy in this situation. Clicking the green *Start* button launches the emulation and causes TAP devices to be created in the virtual nodes that are linked to the EMANE WLAN. These devices appear with interface names such as eth0, eth1, etc. The EMANE processes -should now be running in each namespace. For a four node scenario: +should now be running in each namespace. -```shell -ps -aef | grep emane -root 1063 969 0 11:46 ? 00:00:00 emane -d --logl 3 -r -f /tmp/pycore.59992/emane4.log /tmp/pycore.59992/platform4.xml -root 1117 959 0 11:46 ? 00:00:00 emane -d --logl 3 -r -f /tmp/pycore.59992/emane2.log /tmp/pycore.59992/platform2.xml -root 1179 942 0 11:46 ? 00:00:00 emane -d --logl 3 -r -f /tmp/pycore.59992/emane1.log /tmp/pycore.59992/platform1.xml -root 1239 979 0 11:46 ? 00:00:00 emane -d --logl 3 -r -f /tmp/pycore.59992/emane5.log /tmp/pycore.59992/platform5.xml -``` - -The example above shows the EMANE processes started by CORE. To view the -configuration generated by CORE, look in the */tmp/pycore.nnnnn/* session -directory for a *platform.xml* file and other XML files. One easy way to view -this information is by double-clicking one of the virtual nodes, and typing -*cd ..* in the shell to go up to the session directory. +To view the configuration generated by CORE, look in the */tmp/pycore.nnnnn/* session +directory to find the generated EMANE xml files. One easy way to view +this information is by double-clicking one of the virtual nodes and listing the files +in the shell. ![](static/single-pc-emane.png) @@ -278,55 +263,40 @@ within a node. **IMPORTANT: If an auxiliary control network is used, an interface on the host has to be assigned to that network.** -Each machine that will act as an emulation server needs to have CORE and EMANE -installed. +Each machine that will act as an emulation server needs to have CORE distributed +and EMANE installed. As well as be setup to work for CORE distributed mode. -The IP addresses of the available servers are configured from the CORE emulation -servers dialog box (choose *Session* then *Emulation servers...*). This list of -servers is stored in a *~/.core/servers.conf* file. The dialog shows available +The IP addresses of the available servers are configured from the CORE +servers dialog box. The dialog shows available servers, some or all of which may be assigned to nodes on the canvas. -Nodes need to be assigned to emulation servers. Select several nodes, -right-click them, and choose *Assign to* and the name of the desired server. -When a node is not assigned to any emulation server, it will be emulated -locally. The local machine that the GUI connects with is considered the -"master" machine, which in turn connects to the other emulation server -"slaves". Public key SSH should be configured from the master to the slaves. - -Under the *EMANE* tab of the EMANE WLAN, click on the *EMANE options* button. -This brings up the emane configuration dialog. The *enable OTA Manager channel* -should be set to *on*. The *OTA Manager device* and *Event Service device* -should be set to a control network device. For example, if you have a primary -and auxiliary control network (i.e. controlnet and controlnet1), and you want -the OTA traffic to have its dedicated network, set the OTA Manager device to -*ctrl1* and the Event Service device to *ctrl0*. The EMANE models can be -configured. Click *Apply* to save these settings. +Nodes need to be assigned to servers and can be done so using the node +configuration dialog. When a node is not assigned to any emulation server, +it will be emulated locally. + +Using the EMANE node configuration dialog. You can change the EMANE model +being used, along with changing any configuration setting from their defaults. ![](static/distributed-emane-configuration.png) > **NOTE:** Here is a quick checklist for distributed emulation with EMANE. 1. Follow the steps outlined for normal CORE. - 2. Under the *EMANE* tab of the EMANE WLAN, click on *EMANE options*. - 3. Turn on the *OTA Manager channel* and set the *OTA Manager device*. - Also set the *Event Service device*. - 4. Select groups of nodes, right-click them, and assign them to servers - using the *Assign to* menu. - 5. Synchronize your machine's clocks prior to starting the emulation, + 2. Assign nodes to desired servers + 3. Synchronize your machine's clocks prior to starting the emulation, using *ntp* or *ptp*. Some EMANE models are sensitive to timing. - 6. Press the *Start* button to launch the distributed emulation. + 4. Press the *Start* button to launch the distributed emulation. Now when the Start button is used to instantiate the emulation, the local CORE -Python daemon will connect to other emulation servers that have been assigned +daemon will connect to other emulation servers that have been assigned to nodes. Each server will have its own session directory where the *platform.xml* file and other EMANE XML files are generated. The NEM IDs are -automatically coordinated across servers so there is no overlap. Each server -also gets its own Platform ID. +automatically coordinated across servers so there is no overlap. An Ethernet device is used for disseminating multicast EMANE events, as specified in the *configure emane* dialog. EMANE's Event Service can be run -with mobility or pathloss scripts as described in :ref:`Single_PC_with_EMANE`. +with mobility or pathloss scripts. If CORE is not subscribed to location events, it will generate them as nodes are moved on the canvas. diff --git a/docs/gui.md b/docs/gui.md index 6a333752a..d59f30c54 100644 --- a/docs/gui.md +++ b/docs/gui.md @@ -93,46 +93,46 @@ the left side of the CORE window. Below are brief descriptions for each toolbar item, starting from the top. Most of the tools are grouped into related sub-menus, which appear when you click on their group icon. -| Icon | Name | Description | -|---|---|---| -| ![](static/gui/select.gif) | Selection Tool | Tool for selecting, moving, configuring nodes. | -| ![](static/gui/start.gif) | Start Button | Starts Execute mode, instantiates the emulation. | -| ![](static/gui/link.gif) | Link | Allows network links to be drawn between two nodes by clicking and dragging the mouse. | +| Icon | Name | Description | +|----------------------------|----------------|----------------------------------------------------------------------------------------| +| ![](static/gui/select.gif) | Selection Tool | Tool for selecting, moving, configuring nodes. | +| ![](static/gui/start.gif) | Start Button | Starts Execute mode, instantiates the emulation. | +| ![](static/gui/link.gif) | Link | Allows network links to be drawn between two nodes by clicking and dragging the mouse. | ### CORE Nodes These nodes will create a new node container and run associated services. -| Icon | Name | Description | -|---|---|---| -| ![](static/gui/router.gif) | Router | Runs Quagga OSPFv2 and OSPFv3 routing to forward packets. | -| ![](static/gui/host.gif) | Host | Emulated server machine having a default route, runs SSH server. | -| ![](static/gui/pc.gif) | PC | Basic emulated machine having a default route, runs no processes by default. | -| ![](static/gui/mdr.gif) | MDR | Runs Quagga OSPFv3 MDR routing for MANET-optimized routing. | -| ![](static/gui/router_green.gif) | PRouter | Physical router represents a real testbed machine. | -| ![](static/gui/document-properties.gif) | Edit | Bring up the custom node dialog. | +| Icon | Name | Description | +|-----------------------------------------|---------|------------------------------------------------------------------------------| +| ![](static/gui/router.gif) | Router | Runs Quagga OSPFv2 and OSPFv3 routing to forward packets. | +| ![](static/gui/host.gif) | Host | Emulated server machine having a default route, runs SSH server. | +| ![](static/gui/pc.gif) | PC | Basic emulated machine having a default route, runs no processes by default. | +| ![](static/gui/mdr.gif) | MDR | Runs Quagga OSPFv3 MDR routing for MANET-optimized routing. | +| ![](static/gui/router_green.gif) | PRouter | Physical router represents a real testbed machine. | +| ![](static/gui/document-properties.gif) | Edit | Bring up the custom node dialog. | ### Network Nodes These nodes are mostly used to create a Linux bridge that serves the purpose described below. -| Icon | Name | Description | -|---|---|---| -| ![](static/gui/hub.gif) | Hub | Ethernet hub forwards incoming packets to every connected node. | -| ![](static/gui/lanswitch.gif) | Switch | Ethernet switch intelligently forwards incoming packets to attached hosts using an Ethernet address hash table. | -| ![](static/gui/wlan.gif) | Wireless LAN | When routers are connected to this WLAN node, they join a wireless network and an antenna is drawn instead of a connecting line; the WLAN node typically controls connectivity between attached wireless nodes based on the distance between them. | -| ![](static/gui/rj45.gif) | RJ45 | RJ45 Physical Interface Tool, emulated nodes can be linked to real physical interfaces; using this tool, real networks and devices can be physically connected to the live-running emulation. | -| ![](static/gui/tunnel.gif) | Tunnel | Tool allows connecting together more than one CORE emulation using GRE tunnels. | +| Icon | Name | Description | +|-------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](static/gui/hub.gif) | Hub | Ethernet hub forwards incoming packets to every connected node. | +| ![](static/gui/lanswitch.gif) | Switch | Ethernet switch intelligently forwards incoming packets to attached hosts using an Ethernet address hash table. | +| ![](static/gui/wlan.gif) | Wireless LAN | When routers are connected to this WLAN node, they join a wireless network and an antenna is drawn instead of a connecting line; the WLAN node typically controls connectivity between attached wireless nodes based on the distance between them. | +| ![](static/gui/rj45.gif) | RJ45 | RJ45 Physical Interface Tool, emulated nodes can be linked to real physical interfaces; using this tool, real networks and devices can be physically connected to the live-running emulation. | +| ![](static/gui/tunnel.gif) | Tunnel | Tool allows connecting together more than one CORE emulation using GRE tunnels. | ### Annotation Tools -| Icon | Name | Description | -|---|---|---| -| ![](static/gui/marker.gif) | Marker | For drawing marks on the canvas. | -| ![](static/gui/oval.gif) | Oval | For drawing circles on the canvas that appear in the background. | +| Icon | Name | Description | +|-------------------------------|-----------|---------------------------------------------------------------------| +| ![](static/gui/marker.gif) | Marker | For drawing marks on the canvas. | +| ![](static/gui/oval.gif) | Oval | For drawing circles on the canvas that appear in the background. | | ![](static/gui/rectangle.gif) | Rectangle | For drawing rectangles on the canvas that appear in the background. | -| ![](static/gui/text.gif) | Text | For placing text captions on the canvas. | +| ![](static/gui/text.gif) | Text | For placing text captions on the canvas. | ### Execution Toolbar @@ -140,14 +140,14 @@ When the Start button is pressed, CORE switches to Execute mode, and the Edit toolbar on the left of the CORE window is replaced with the Execution toolbar Below are the items on this toolbar, starting from the top. -| Icon | Name | Description | -|---|---|---| -| ![](static/gui/select.gif) | Selection Tool | In Execute mode, the Selection Tool can be used for moving nodes around the canvas, and double-clicking on a node will open a shell window for that node; right-clicking on a node invokes a pop-up menu of run-time options for that node. | -| ![](static/gui/stop.gif) | Stop Button | Stops Execute mode, terminates the emulation, returns CORE to edit mode. | -| ![](static/gui/observe.gif) | Observer Widgets Tool | Clicking on this magnifying glass icon invokes a menu for easily selecting an Observer Widget. The icon has a darker gray background when an Observer Widget is active, during which time moving the mouse over a node will pop up an information display for that node. | -| ![](static/gui/marker.gif) | Marker | For drawing freehand lines on the canvas, useful during demonstrations; markings are not saved. | -| ![](static/gui/twonode.gif) | Two-node Tool | Click to choose a starting and ending node, and run a one-time *traceroute* between those nodes or a continuous *ping -R* between nodes. The output is displayed in real time in a results box, while the IP addresses are parsed and the complete network path is highlighted on the CORE display. | -| ![](static/gui/run.gif) | Run Tool | This tool allows easily running a command on all or a subset of all nodes. A list box allows selecting any of the nodes. A text entry box allows entering any command. The command should return immediately, otherwise the display will block awaiting response. The *ping* command, for example, with no parameters, is not a good idea. The result of each command is displayed in a results box. The first occurrence of the special text "NODE" will be replaced with the node name. The command will not be attempted to run on nodes that are not routers, PCs, or hosts, even if they are selected. | +| Icon | Name | Description | +|-----------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](static/gui/select.gif) | Selection Tool | In Execute mode, the Selection Tool can be used for moving nodes around the canvas, and double-clicking on a node will open a shell window for that node; right-clicking on a node invokes a pop-up menu of run-time options for that node. | +| ![](static/gui/stop.gif) | Stop Button | Stops Execute mode, terminates the emulation, returns CORE to edit mode. | +| ![](static/gui/observe.gif) | Observer Widgets Tool | Clicking on this magnifying glass icon invokes a menu for easily selecting an Observer Widget. The icon has a darker gray background when an Observer Widget is active, during which time moving the mouse over a node will pop up an information display for that node. | +| ![](static/gui/marker.gif) | Marker | For drawing freehand lines on the canvas, useful during demonstrations; markings are not saved. | +| ![](static/gui/twonode.gif) | Two-node Tool | Click to choose a starting and ending node, and run a one-time *traceroute* between those nodes or a continuous *ping -R* between nodes. The output is displayed in real time in a results box, while the IP addresses are parsed and the complete network path is highlighted on the CORE display. | +| ![](static/gui/run.gif) | Run Tool | This tool allows easily running a command on all or a subset of all nodes. A list box allows selecting any of the nodes. A text entry box allows entering any command. The command should return immediately, otherwise the display will block awaiting response. The *ping* command, for example, with no parameters, is not a good idea. The result of each command is displayed in a results box. The first occurrence of the special text "NODE" will be replaced with the node name. The command will not be attempted to run on nodes that are not routers, PCs, or hosts, even if they are selected. | ## Menu @@ -160,95 +160,95 @@ menu, by clicking the dashed line at the top. The File menu contains options for manipulating the **.imn** Configuration Files. Generally, these menu items should not be used in Execute mode. -| Option | Description | -|---|---| -| New | This starts a new file with an empty canvas. | -| Open | Invokes the File Open dialog box for selecting a new **.imn** or XML file to open. You can change the default path used for this dialog in the Preferences Dialog. | -| Save | Saves the current topology. If you have not yet specified a file name, the Save As dialog box is invoked. | -| Save As XML | Invokes the Save As dialog box for selecting a new **.xml** file for saving the current configuration in the XML file. | -| Save As imn | Invokes the Save As dialog box for selecting a new **.imn** topology file for saving the current configuration. Files are saved in the *IMUNES network configuration* file. | -| Export Python script | Prints Python snippets to the console, for inclusion in a CORE Python script. | -| Execute XML or Python script | Invokes a File Open dialog box for selecting an XML file to run or a Python script to run and automatically connect to. If a Python script, the script must create a new CORE Session and add this session to the daemon's list of sessions in order for this to work. | +| Option | Description | +|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| New | This starts a new file with an empty canvas. | +| Open | Invokes the File Open dialog box for selecting a new **.imn** or XML file to open. You can change the default path used for this dialog in the Preferences Dialog. | +| Save | Saves the current topology. If you have not yet specified a file name, the Save As dialog box is invoked. | +| Save As XML | Invokes the Save As dialog box for selecting a new **.xml** file for saving the current configuration in the XML file. | +| Save As imn | Invokes the Save As dialog box for selecting a new **.imn** topology file for saving the current configuration. Files are saved in the *IMUNES network configuration* file. | +| Export Python script | Prints Python snippets to the console, for inclusion in a CORE Python script. | +| Execute XML or Python script | Invokes a File Open dialog box for selecting an XML file to run or a Python script to run and automatically connect to. If a Python script, the script must create a new CORE Session and add this session to the daemon's list of sessions in order for this to work. | | Execute Python script with options | Invokes a File Open dialog box for selecting a Python script to run and automatically connect to. After a selection is made, a Python Script Options dialog box is invoked to allow for command-line options to be added. The Python script must create a new CORE Session and add this session to the daemon's list of sessions in order for this to work. | -| Open current file in editor | This opens the current topology file in the **vim** text editor. First you need to save the file. Once the file has been edited with a text editor, you will need to reload the file to see your changes. The text editor can be changed from the Preferences Dialog. | -| Print | This uses the Tcl/Tk postscript command to print the current canvas to a printer. A dialog is invoked where you can specify a printing command, the default being **lpr**. The postscript output is piped to the print command. | -| Save screenshot | Saves the current canvas as a postscript graphic file. | -| Recently used files | Above the Quit menu command is a list of recently use files, if any have been opened. You can clear this list in the Preferences dialog box. You can specify the number of files to keep in this list from the Preferences dialog. Click on one of the file names listed to open that configuration file. | -| Quit | The Quit command should be used to exit the CORE GUI. CORE may prompt for termination if you are currently in Execute mode. Preferences and the recently-used files list are saved. | +| Open current file in editor | This opens the current topology file in the **vim** text editor. First you need to save the file. Once the file has been edited with a text editor, you will need to reload the file to see your changes. The text editor can be changed from the Preferences Dialog. | +| Print | This uses the Tcl/Tk postscript command to print the current canvas to a printer. A dialog is invoked where you can specify a printing command, the default being **lpr**. The postscript output is piped to the print command. | +| Save screenshot | Saves the current canvas as a postscript graphic file. | +| Recently used files | Above the Quit menu command is a list of recently use files, if any have been opened. You can clear this list in the Preferences dialog box. You can specify the number of files to keep in this list from the Preferences dialog. Click on one of the file names listed to open that configuration file. | +| Quit | The Quit command should be used to exit the CORE GUI. CORE may prompt for termination if you are currently in Execute mode. Preferences and the recently-used files list are saved. | ### Edit Menu -| Option | Description | -|---|---| -| Undo | Attempts to undo the last edit in edit mode. | -| Redo | Attempts to redo an edit that has been undone. | -| Cut, Copy, Paste | Used to cut, copy, and paste a selection. When nodes are pasted, their node numbers are automatically incremented, and existing links are preserved with new IP addresses assigned. Services and their customizations are copied to the new node, but care should be taken as node IP addresses have changed with possibly old addresses remaining in any custom service configurations. Annotations may also be copied and pasted. -| Select All | Selects all items on the canvas. Selected items can be moved as a group. | -| Select Adjacent | Select all nodes that are linked to the already selected node(s). For wireless nodes this simply selects the WLAN node(s) that the wireless node belongs to. You can use this by clicking on a node and pressing CTRL+N to select the adjacent nodes. | -| Find... | Invokes the *Find* dialog box. The Find dialog can be used to search for nodes by name or number. Results are listed in a table that includes the node or link location and details such as IP addresses or link parameters. Clicking on a result will focus the canvas on that node or link, switching canvases if necessary. | -| Clear marker | Clears any annotations drawn with the marker tool. Also clears any markings used to indicate a node's status. | -| Preferences... | Invokes the Preferences dialog box. | +| Option | Description | +|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Undo | Attempts to undo the last edit in edit mode. | +| Redo | Attempts to redo an edit that has been undone. | +| Cut, Copy, Paste | Used to cut, copy, and paste a selection. When nodes are pasted, their node numbers are automatically incremented, and existing links are preserved with new IP addresses assigned. Services and their customizations are copied to the new node, but care should be taken as node IP addresses have changed with possibly old addresses remaining in any custom service configurations. Annotations may also be copied and pasted. | +| Select All | Selects all items on the canvas. Selected items can be moved as a group. | +| Select Adjacent | Select all nodes that are linked to the already selected node(s). For wireless nodes this simply selects the WLAN node(s) that the wireless node belongs to. You can use this by clicking on a node and pressing CTRL+N to select the adjacent nodes. | +| Find... | Invokes the *Find* dialog box. The Find dialog can be used to search for nodes by name or number. Results are listed in a table that includes the node or link location and details such as IP addresses or link parameters. Clicking on a result will focus the canvas on that node or link, switching canvases if necessary. | +| Clear marker | Clears any annotations drawn with the marker tool. Also clears any markings used to indicate a node's status. | +| Preferences... | Invokes the Preferences dialog box. | ### Canvas Menu The canvas menu provides commands for adding, removing, changing, and switching to different editing canvases. -| Option | Description | -|---|---| -| New | Creates a new empty canvas at the right of all existing canvases. | -| Manage... | Invokes the *Manage Canvases* dialog box, where canvases may be renamed and reordered, and you can easily switch to one of the canvases by selecting it. | -| Delete | Deletes the current canvas and all items that it contains. | -| Size/scale... | Invokes a Canvas Size and Scale dialog that allows configuring the canvas size, scale, and geographic reference point. The size controls allow changing the width and height of the current canvas, in pixels or meters. The scale allows specifying how many meters are equivalent to 100 pixels. The reference point controls specify the latitude, longitude, and altitude reference point used to convert between geographic and Cartesian coordinate systems. By clicking the *Save as default* option, all new canvases will be created with these properties. The default canvas size can also be changed in the Preferences dialog box. -| Wallpaper... | Used for setting the canvas background image. | -| Previous, Next, First, Last | Used for switching the active canvas to the first, last, or adjacent canvas. | +| Option | Description | +|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| New | Creates a new empty canvas at the right of all existing canvases. | +| Manage... | Invokes the *Manage Canvases* dialog box, where canvases may be renamed and reordered, and you can easily switch to one of the canvases by selecting it. | +| Delete | Deletes the current canvas and all items that it contains. | +| Size/scale... | Invokes a Canvas Size and Scale dialog that allows configuring the canvas size, scale, and geographic reference point. The size controls allow changing the width and height of the current canvas, in pixels or meters. The scale allows specifying how many meters are equivalent to 100 pixels. The reference point controls specify the latitude, longitude, and altitude reference point used to convert between geographic and Cartesian coordinate systems. By clicking the *Save as default* option, all new canvases will be created with these properties. The default canvas size can also be changed in the Preferences dialog box. | +| Wallpaper... | Used for setting the canvas background image. | +| Previous, Next, First, Last | Used for switching the active canvas to the first, last, or adjacent canvas. | ### View Menu The View menu features items for controlling what is displayed on the drawing canvas. -| Option | Description | -|---|---| -| Show | Opens a submenu of items that can be displayed or hidden, such as interface names, addresses, and labels. Use these options to help declutter the display. These options are generally saved in the topology files, so scenarios have a more consistent look when copied from one computer to another. | -| Show hidden nodes | Reveal nodes that have been hidden. Nodes are hidden by selecting one or more nodes, right-clicking one and choosing *hide*. | -| Locked | Toggles locked view; when the view is locked, nodes cannot be moved around on the canvas with the mouse. This could be useful when sharing the topology with someone and you do not expect them to change things. | -| 3D GUI... | Launches a 3D GUI by running the command defined under Preferences, *3D GUI command*. This is typically a script that runs the SDT3D display. SDT is the Scripted Display Tool from NRL that is based on NASA's Java-based WorldWind virtual globe software. | -| Zoom In | Magnifies the display. You can also zoom in by clicking *zoom 100%* label in the status bar, or by pressing the **+** (plus) key. | -| Zoom Out | Reduces the size of the display. You can also zoom out by right-clicking *zoom 100%* label in the status bar or by pressing the **-** (minus) key. | +| Option | Description | +|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Show | Opens a submenu of items that can be displayed or hidden, such as interface names, addresses, and labels. Use these options to help declutter the display. These options are generally saved in the topology files, so scenarios have a more consistent look when copied from one computer to another. | +| Show hidden nodes | Reveal nodes that have been hidden. Nodes are hidden by selecting one or more nodes, right-clicking one and choosing *hide*. | +| Locked | Toggles locked view; when the view is locked, nodes cannot be moved around on the canvas with the mouse. This could be useful when sharing the topology with someone and you do not expect them to change things. | +| 3D GUI... | Launches a 3D GUI by running the command defined under Preferences, *3D GUI command*. This is typically a script that runs the SDT3D display. SDT is the Scripted Display Tool from NRL that is based on NASA's Java-based WorldWind virtual globe software. | +| Zoom In | Magnifies the display. You can also zoom in by clicking *zoom 100%* label in the status bar, or by pressing the **+** (plus) key. | +| Zoom Out | Reduces the size of the display. You can also zoom out by right-clicking *zoom 100%* label in the status bar or by pressing the **-** (minus) key. | ### Tools Menu The tools menu lists different utility functions. -| Option | Description | -|---|---| -| Autorearrange all | Automatically arranges all nodes on the canvas. Nodes having a greater number of links are moved to the center. This mode can continue to run while placing nodes. To turn off this autorearrange mode, click on a blank area of the canvas with the select tool, or choose this menu option again. | -| Autorearrange selected | Automatically arranges the selected nodes on the canvas. | -| Align to grid | Moves nodes into a grid formation, starting with the smallest-numbered node in the upper-left corner of the canvas, arranging nodes in vertical columns. | -| Traffic... | Invokes the CORE Traffic Flows dialog box, which allows configuring, starting, and stopping MGEN traffic flows for the emulation. | -| IP addresses... | Invokes the IP Addresses dialog box for configuring which IPv4/IPv6 prefixes are used when automatically addressing new interfaces. | -| MAC addresses... | Invokes the MAC Addresses dialog box for configuring the starting number used as the lowest byte when generating each interface MAC address. This value should be changed when tunneling between CORE emulations to prevent MAC address conflicts. | -| Build hosts file... | Invokes the Build hosts File dialog box for generating **/etc/hosts** file entries based on IP addresses used in the emulation. | -| Renumber nodes... | Invokes the Renumber Nodes dialog box, which allows swapping one node number with another in a few clicks. | -| Experimental... | Menu of experimental options, such as a tool to convert ns-2 scripts to IMUNES imn topologies, supporting only basic ns-2 functionality, and a tool for automatically dividing up a topology into partitions. | -| Topology generator | Opens a submenu of topologies to generate. You can first select the type of node that the topology should consist of, or routers will be chosen by default. Nodes may be randomly placed, aligned in grids, or various other topology patterns. All of the supported patterns are listed in the table below. | -| Debugger... | Opens the CORE Debugger window for executing arbitrary Tcl/Tk commands. | +| Option | Description | +|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Autorearrange all | Automatically arranges all nodes on the canvas. Nodes having a greater number of links are moved to the center. This mode can continue to run while placing nodes. To turn off this autorearrange mode, click on a blank area of the canvas with the select tool, or choose this menu option again. | +| Autorearrange selected | Automatically arranges the selected nodes on the canvas. | +| Align to grid | Moves nodes into a grid formation, starting with the smallest-numbered node in the upper-left corner of the canvas, arranging nodes in vertical columns. | +| Traffic... | Invokes the CORE Traffic Flows dialog box, which allows configuring, starting, and stopping MGEN traffic flows for the emulation. | +| IP addresses... | Invokes the IP Addresses dialog box for configuring which IPv4/IPv6 prefixes are used when automatically addressing new interfaces. | +| MAC addresses... | Invokes the MAC Addresses dialog box for configuring the starting number used as the lowest byte when generating each interface MAC address. This value should be changed when tunneling between CORE emulations to prevent MAC address conflicts. | +| Build hosts file... | Invokes the Build hosts File dialog box for generating **/etc/hosts** file entries based on IP addresses used in the emulation. | +| Renumber nodes... | Invokes the Renumber Nodes dialog box, which allows swapping one node number with another in a few clicks. | +| Experimental... | Menu of experimental options, such as a tool to convert ns-2 scripts to IMUNES imn topologies, supporting only basic ns-2 functionality, and a tool for automatically dividing up a topology into partitions. | +| Topology generator | Opens a submenu of topologies to generate. You can first select the type of node that the topology should consist of, or routers will be chosen by default. Nodes may be randomly placed, aligned in grids, or various other topology patterns. All of the supported patterns are listed in the table below. | +| Debugger... | Opens the CORE Debugger window for executing arbitrary Tcl/Tk commands. | #### Topology Generator -| Pattern | Description | -|---|---| -| Random | Nodes are randomly placed about the canvas, but are not linked together. This can be used in conjunction with a WLAN node to quickly create a wireless network. | -| Grid | Nodes are placed in horizontal rows starting in the upper-left corner, evenly spaced to the right; nodes are not linked to each other. | -| Connected Grid | Nodes are placed in an N x M (width and height) rectangular grid, and each node is linked to the node above, below, left and right of itself. | -| Chain | Nodes are linked together one after the other in a chain. | -| Star | One node is placed in the center with N nodes surrounding it in a circular pattern, with each node linked to the center node. | -| Cycle | Nodes are arranged in a circular pattern with every node connected to its neighbor to form a closed circular path. | -| Wheel | The wheel pattern links nodes in a combination of both Star and Cycle patterns. | -| Cube | Generate a cube graph of nodes. | -| Clique | Creates a clique graph of nodes, where every node is connected to every other node. | -| Bipartite | Creates a bipartite graph of nodes, having two disjoint sets of vertices. | +| Pattern | Description | +|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Random | Nodes are randomly placed about the canvas, but are not linked together. This can be used in conjunction with a WLAN node to quickly create a wireless network. | +| Grid | Nodes are placed in horizontal rows starting in the upper-left corner, evenly spaced to the right; nodes are not linked to each other. | +| Connected Grid | Nodes are placed in an N x M (width and height) rectangular grid, and each node is linked to the node above, below, left and right of itself. | +| Chain | Nodes are linked together one after the other in a chain. | +| Star | One node is placed in the center with N nodes surrounding it in a circular pattern, with each node linked to the center node. | +| Cycle | Nodes are arranged in a circular pattern with every node connected to its neighbor to form a closed circular path. | +| Wheel | The wheel pattern links nodes in a combination of both Star and Cycle patterns. | +| Cube | Generate a cube graph of nodes. | +| Clique | Creates a clique graph of nodes, where every node is connected to every other node. | +| Bipartite | Creates a bipartite graph of nodes, having two disjoint sets of vertices. | ### Widgets Menu @@ -306,36 +306,36 @@ The Session Menu has entries for starting, stopping, and managing sessions, in addition to global options such as node types, comments, hooks, servers, and options. -| Option | Description | -|---|---| -| Start or Stop | This starts or stops the emulation, performing the same function as the green Start or red Stop button. | -| Change sessions... | Invokes the CORE Sessions dialog box containing a list of active CORE sessions in the daemon. Basic session information such as name, node count, start time, and a thumbnail are displayed. This dialog allows connecting to different sessions, shutting them down, or starting a new session. | -| Node types... | Invokes the CORE Node Types dialog, performing the same function as the Edit button on the Network-Layer Nodes toolbar. | -| Comments... | Invokes the CORE Session Comments window where optional text comments may be specified. These comments are saved at the top of the configuration file, and can be useful for describing the topology or how to use the network. | -| Hooks... | Invokes the CORE Session Hooks window where scripts may be configured for a particular session state. The session states are defined in the [table](#session-states) below. The top of the window has a list of configured hooks, and buttons on the bottom left allow adding, editing, and removing hook scripts. The new or edit button will open a hook script editing window. A hook script is a shell script invoked on the host (not within a virtual node). | -| Reset node positions | If you have moved nodes around using the mouse or by using a mobility module, choosing this item will reset all nodes to their original position on the canvas. The node locations are remembered when you first press the Start button. | -| Emulation servers... | Invokes the CORE emulation servers dialog for configuring. | -| Change Sessions... | Invokes the Sessions dialog for switching between different running sessions. This dialog is presented during startup when one or more sessions are already running. | -| Options... | Presents per-session options, such as the IPv4 prefix to be used, if any, for a control network the ability to preserve the session directory; and an on/off switch for SDT3D support. | +| Option | Description | +|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Start or Stop | This starts or stops the emulation, performing the same function as the green Start or red Stop button. | +| Change sessions... | Invokes the CORE Sessions dialog box containing a list of active CORE sessions in the daemon. Basic session information such as name, node count, start time, and a thumbnail are displayed. This dialog allows connecting to different sessions, shutting them down, or starting a new session. | +| Node types... | Invokes the CORE Node Types dialog, performing the same function as the Edit button on the Network-Layer Nodes toolbar. | +| Comments... | Invokes the CORE Session Comments window where optional text comments may be specified. These comments are saved at the top of the configuration file, and can be useful for describing the topology or how to use the network. | +| Hooks... | Invokes the CORE Session Hooks window where scripts may be configured for a particular session state. The session states are defined in the [table](#session-states) below. The top of the window has a list of configured hooks, and buttons on the bottom left allow adding, editing, and removing hook scripts. The new or edit button will open a hook script editing window. A hook script is a shell script invoked on the host (not within a virtual node). | +| Reset node positions | If you have moved nodes around using the mouse or by using a mobility module, choosing this item will reset all nodes to their original position on the canvas. The node locations are remembered when you first press the Start button. | +| Emulation servers... | Invokes the CORE emulation servers dialog for configuring. | +| Change Sessions... | Invokes the Sessions dialog for switching between different running sessions. This dialog is presented during startup when one or more sessions are already running. | +| Options... | Presents per-session options, such as the IPv4 prefix to be used, if any, for a control network the ability to preserve the session directory; and an on/off switch for SDT3D support. | #### Session States -| State | Description | -|---|---| -| definition | Used by the GUI to tell the backend to clear any state. | -| configuration | When the user presses the *Start* button, node, link, and other configuration data is sent to the backend. This state is also reached when the user customizes a service. | -| instantiation | After configuration data has been sent, just before the nodes are created. | -| runtime | All nodes and networks have been built and are running. (This is the same state at which the previously-named *global experiment script* was run.) -| datacollect | The user has pressed the *Stop* button, but before services have been stopped and nodes have been shut down. This is a good time to collect log files and other data from the nodes. | -| shutdown | All nodes and networks have been shut down and destroyed. | +| State | Description | +|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| definition | Used by the GUI to tell the backend to clear any state. | +| configuration | When the user presses the *Start* button, node, link, and other configuration data is sent to the backend. This state is also reached when the user customizes a service. | +| instantiation | After configuration data has been sent, just before the nodes are created. | +| runtime | All nodes and networks have been built and are running. (This is the same state at which the previously-named *global experiment script* was run.) | +| datacollect | The user has pressed the *Stop* button, but before services have been stopped and nodes have been shut down. This is a good time to collect log files and other data from the nodes. | +| shutdown | All nodes and networks have been shut down and destroyed. | ### Help Menu -| Option | Description | -|---|---| -| CORE Github (www) | Link to the CORE GitHub page. | -| CORE Documentation (www) | Lnk to the CORE Documentation page. | -| About | Invokes the About dialog box for viewing version information. | +| Option | Description | +|--------------------------|---------------------------------------------------------------| +| CORE Github (www) | Link to the CORE GitHub page. | +| CORE Documentation (www) | Lnk to the CORE Documentation page. | +| About | Invokes the About dialog box for viewing version information. | ## Connecting with Physical Networks @@ -542,10 +542,10 @@ complexity and CPU usage. The availability of certain plug-ins varies depending on platform. See the table below for a brief overview of wireless model types. -|Model|Type|Supported Platform(s)|Fidelity|Description| -|-----|----|---------------------|--------|-----------| -|Basic|on/off|Linux|Low|Ethernet bridging with nftables| -|EMANE|Plug-in|Linux|High|TAP device connected to EMANE emulator with pluggable MAC and PHY radio types| +| Model | Type | Supported Platform(s) | Fidelity | Description | +|-------|---------|-----------------------|----------|-------------------------------------------------------------------------------| +| Basic | on/off | Linux | Low | Ethernet bridging with nftables | +| EMANE | Plug-in | Linux | High | TAP device connected to EMANE emulator with pluggable MAC and PHY radio types | To quickly build a wireless network, you can first place several router nodes onto the canvas. If you have the @@ -581,11 +581,11 @@ See the [EMANE](emane.md) chapter for details on using EMANE. CORE has a few ways to script mobility. -| Option | Description | -|---|---| -| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. | -| CORE API | An external entity can move nodes by sending CORE API Node messages with updated X,Y coordinates; the **coresendmsg** utility allows a shell script to generate these messages. | -| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. | +| Option | Description | +|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. | +| CORE API | An external entity can move nodes by sending CORE API Node messages with updated X,Y coordinates; the **coresendmsg** utility allows a shell script to generate these messages. | +| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. | For the first method, you can create a mobility script using a text editor, or using a tool such as [BonnMotion](http://net.cs.uni-bonn.de/wg/cs/applications/bonnmotion/), and associate the script with one of the wireless diff --git a/docs/index.md b/docs/index.md index 0bfe5a26b..2321fa54f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,22 +18,22 @@ networking scenarios, security studies, and increasing the size of physical test ## Topics -| Topic | Description| -|-------|------------| -|[Installation](install.md)|How to install CORE and its requirements| -|[Architecture](architecture.md)|Overview of the architecture| -|[Node Types](nodetypes.md)|Overview of node types supported within CORE| -|[GUI](gui.md)|How to use the GUI| -|[(BETA) Python GUI](pygui.md)|How to use the BETA python based GUI| -|[Python API](python.md)|Covers how to control core directly using python| -|[gRPC API](grpc.md)|Covers how control core using gRPC| -|[Distributed](distributed.md)|Details for running CORE across multiple servers| -|[Control Network](ctrlnet.md)|How to use control networks to communicate with nodes from host| -|[Config Services](configservices.md)|Overview of provided config services and creating custom ones| -|[Services](services.md)|Overview of provided services and creating custom ones| -|[EMANE](emane.md)|Overview of EMANE integration and integrating custom EMANE models| -|[Performance](performance.md)|Notes on performance when using CORE| -|[Developers Guide](devguide.md)|Overview on how to contribute to CORE| +| Topic | Description | +|--------------------------------------|-------------------------------------------------------------------| +| [Installation](install.md) | How to install CORE and its requirements | +| [Architecture](architecture.md) | Overview of the architecture | +| [Node Types](nodetypes.md) | Overview of node types supported within CORE | +| [Python GUI](pygui.md) | How to use the default python based GUI | +| [Legacy GUI (deprecated)](gui.md) | How to use the deprecated Tcl based GUI | +| [Python API](python.md) | Covers how to control core directly using python | +| [gRPC API](grpc.md) | Covers how control core using gRPC | +| [Distributed](distributed.md) | Details for running CORE across multiple servers | +| [Control Network](ctrlnet.md) | How to use control networks to communicate with nodes from host | +| [Config Services](configservices.md) | Overview of provided config services and creating custom ones | +| [Services](services.md) | Overview of provided services and creating custom ones | +| [EMANE](emane.md) | Overview of EMANE integration and integrating custom EMANE models | +| [Performance](performance.md) | Notes on performance when using CORE | +| [Developers Guide](devguide.md) | Overview on how to contribute to CORE | ## Credits diff --git a/docs/install.md b/docs/install.md index 2ba72fc5b..2f6dbce3d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -37,12 +37,12 @@ sudo modprobe sch_netem ### Tools Used The following tools will be leveraged during installation: -|Tool|Description| -|---|---| -|[pip](https://pip.pypa.io/en/stable/)|used to install pipx| -|[pipx](https://pipxproject.github.io/pipx/)|used to install standalone python tools (invoke, poetry)| -|[invoke](http://www.pyinvoke.org/)|used to run provided tasks (install, uninstall, reinstall, etc)| -|[poetry](https://python-poetry.org/)|used to install python virtual environment or building a python wheel| +| Tool | Description | +|---------------------------------------------|-----------------------------------------------------------------------| +| [pip](https://pip.pypa.io/en/stable/) | used to install pipx | +| [pipx](https://pipxproject.github.io/pipx/) | used to install standalone python tools (invoke, poetry) | +| [invoke](http://www.pyinvoke.org/) | used to run provided tasks (install, uninstall, reinstall, etc) | +| [poetry](https://python-poetry.org/) | used to install python virtual environment or building a python wheel | ### Files The following is a list of files that would be installed after running the automated installation. @@ -73,19 +73,19 @@ The following is a list of files that would be installed after running the autom ### Installed Executables After the installation complete it will have installed the following scripts. -| Name | Description | -|---|---| -| core-cleanup | tool to help removed lingering core created containers, bridges, directories | -| core-cli | tool to query, open xml files, and send commands using gRPC | -| core-daemon | runs the backed core server providing TLV and gRPC APIs | -| core-gui | runs the legacy tcl/tk based GUI | -| core-imn-to-xml | tool to help automate converting a .imn file to .xml format | -| core-manage | tool to add, remove, or check for services, models, and node types | -| core-pygui | runs the new python/tk based GUI | -| core-python | provides a convenience for running the core python virtual environment | -| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT | -| core-service-update | tool to update automate modifying a legacy service to match current naming | -| coresendmsg | tool to send TLV API commands from command line | +| Name | Description | +|---------------------|------------------------------------------------------------------------------| +| core-cleanup | tool to help removed lingering core created containers, bridges, directories | +| core-cli | tool to query, open xml files, and send commands using gRPC | +| core-daemon | runs the backed core server providing TLV and gRPC APIs | +| core-gui | runs the legacy tcl/tk based GUI | +| core-imn-to-xml | tool to help automate converting a .imn file to .xml format | +| core-manage | tool to add, remove, or check for services, models, and node types | +| core-pygui | runs the new python/tk based GUI | +| core-python | provides a convenience for running the core python virtual environment | +| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT | +| core-service-update | tool to update automate modifying a legacy service to match current naming | +| coresendmsg | tool to send TLV API commands from command line | ## Upgrading from Older Release Please make sure to uninstall any previous installations of CORE cleanly @@ -127,7 +127,7 @@ source ~/.bashrc # Ubuntu inv install # CentOS -./install.sh -p /usr +inv install -p /usr ``` First you can use `setup.sh` as a convenience to install tooling for running invoke tasks: diff --git a/docs/performance.md b/docs/performance.md index b088c65b5..5c3ae3a00 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -8,13 +8,13 @@ The top question about the performance of CORE is often *how many nodes can it handle?* The answer depends on several factors: -| Factor | Performance Impact | -|---|---| -| Hardware | the number and speed of processors in the computer, the available processor cache, RAM memory, and front-side bus speed may greatly affect overall performance. | -| Operating system version | distribution of Linux and the specific kernel versions used will affect overall performance. | -| Active processes | all nodes share the same CPU resources, so if one or more nodes is performing a CPU-intensive task, overall performance will suffer. | -| Network traffic | the more packets that are sent around the virtual network increases the amount of CPU usage. | -| GUI usage | widgets that run periodically, mobility scenarios, and other GUI interactions generally consume CPU cycles that may be needed for emulation. | +| Factor | Performance Impact | +|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Hardware | the number and speed of processors in the computer, the available processor cache, RAM memory, and front-side bus speed may greatly affect overall performance. | +| Operating system version | distribution of Linux and the specific kernel versions used will affect overall performance. | +| Active processes | all nodes share the same CPU resources, so if one or more nodes is performing a CPU-intensive task, overall performance will suffer. | +| Network traffic | the more packets that are sent around the virtual network increases the amount of CPU usage. | +| GUI usage | widgets that run periodically, mobility scenarios, and other GUI interactions generally consume CPU cycles that may be needed for emulation. | On a typical single-CPU Xeon 3.0GHz server machine with 2GB RAM running Linux, diff --git a/docs/pygui.md b/docs/pygui.md index 2e9f726ab..1d4958343 100644 --- a/docs/pygui.md +++ b/docs/pygui.md @@ -114,45 +114,45 @@ the left side of the CORE window. Below are brief descriptions for each toolbar item, starting from the top. Most of the tools are grouped into related sub-menus, which appear when you click on their group icon. -| Icon | Name | Description | -|---|---|---| -| ![](static/pygui/select.png) | Selection Tool | Tool for selecting, moving, configuring nodes. | -| ![](static/pygui/start.png) | Start Button | Starts Execute mode, instantiates the emulation. | -| ![](static/pygui/link.png) | Link | Allows network links to be drawn between two nodes by clicking and dragging the mouse. | +| Icon | Name | Description | +|------------------------------|----------------|----------------------------------------------------------------------------------------| +| ![](static/pygui/select.png) | Selection Tool | Tool for selecting, moving, configuring nodes. | +| ![](static/pygui/start.png) | Start Button | Starts Execute mode, instantiates the emulation. | +| ![](static/pygui/link.png) | Link | Allows network links to be drawn between two nodes by clicking and dragging the mouse. | ### CORE Nodes These nodes will create a new node container and run associated services. -| Icon | Name | Description | -|---|---|---| -| ![](static/pygui/router.png) | Router | Runs Quagga OSPFv2 and OSPFv3 routing to forward packets. | -| ![](static/pygui/host.png) | Host | Emulated server machine having a default route, runs SSH server. | -| ![](static/pygui/pc.png) | PC | Basic emulated machine having a default route, runs no processes by default. | -| ![](static/pygui/mdr.png) | MDR | Runs Quagga OSPFv3 MDR routing for MANET-optimized routing. | -| ![](static/pygui/router.png) | PRouter | Physical router represents a real testbed machine. | +| Icon | Name | Description | +|------------------------------|---------|------------------------------------------------------------------------------| +| ![](static/pygui/router.png) | Router | Runs Quagga OSPFv2 and OSPFv3 routing to forward packets. | +| ![](static/pygui/host.png) | Host | Emulated server machine having a default route, runs SSH server. | +| ![](static/pygui/pc.png) | PC | Basic emulated machine having a default route, runs no processes by default. | +| ![](static/pygui/mdr.png) | MDR | Runs Quagga OSPFv3 MDR routing for MANET-optimized routing. | +| ![](static/pygui/router.png) | PRouter | Physical router represents a real testbed machine. | ### Network Nodes These nodes are mostly used to create a Linux bridge that serves the purpose described below. -| Icon | Name | Description | -|---|---|---| -| ![](static/pygui/hub.png) | Hub | Ethernet hub forwards incoming packets to every connected node. | -| ![](static/pygui/lanswitch.png) | Switch | Ethernet switch intelligently forwards incoming packets to attached hosts using an Ethernet address hash table. | -| ![](static/pygui/wlan.png) | Wireless LAN | When routers are connected to this WLAN node, they join a wireless network and an antenna is drawn instead of a connecting line; the WLAN node typically controls connectivity between attached wireless nodes based on the distance between them. | -| ![](static/pygui/rj45.png) | RJ45 | RJ45 Physical Interface Tool, emulated nodes can be linked to real physical interfaces; using this tool, real networks and devices can be physically connected to the live-running emulation. | -| ![](static/pygui/tunnel.png) | Tunnel | Tool allows connecting together more than one CORE emulation using GRE tunnels. | +| Icon | Name | Description | +|---------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](static/pygui/hub.png) | Hub | Ethernet hub forwards incoming packets to every connected node. | +| ![](static/pygui/lanswitch.png) | Switch | Ethernet switch intelligently forwards incoming packets to attached hosts using an Ethernet address hash table. | +| ![](static/pygui/wlan.png) | Wireless LAN | When routers are connected to this WLAN node, they join a wireless network and an antenna is drawn instead of a connecting line; the WLAN node typically controls connectivity between attached wireless nodes based on the distance between them. | +| ![](static/pygui/rj45.png) | RJ45 | RJ45 Physical Interface Tool, emulated nodes can be linked to real physical interfaces; using this tool, real networks and devices can be physically connected to the live-running emulation. | +| ![](static/pygui/tunnel.png) | Tunnel | Tool allows connecting together more than one CORE emulation using GRE tunnels. | ### Annotation Tools -| Icon | Name | Description | -|---|---|---| -| ![](static/pygui/marker.png) | Marker | For drawing marks on the canvas. | -| ![](static/pygui/oval.png) | Oval | For drawing circles on the canvas that appear in the background. | +| Icon | Name | Description | +|---------------------------------|-----------|---------------------------------------------------------------------| +| ![](static/pygui/marker.png) | Marker | For drawing marks on the canvas. | +| ![](static/pygui/oval.png) | Oval | For drawing circles on the canvas that appear in the background. | | ![](static/pygui/rectangle.png) | Rectangle | For drawing rectangles on the canvas that appear in the background. | -| ![](static/pygui/text.png) | Text | For placing text captions on the canvas. | +| ![](static/pygui/text.png) | Text | For placing text captions on the canvas. | ### Execution Toolbar @@ -160,12 +160,12 @@ When the Start button is pressed, CORE switches to Execute mode, and the Edit toolbar on the left of the CORE window is replaced with the Execution toolbar Below are the items on this toolbar, starting from the top. -| Icon | Name | Description | -|---|---|---| -| ![](static/pygui/stop.png) | Stop Button | Stops Execute mode, terminates the emulation, returns CORE to edit mode. | -| ![](static/pygui/select.png) | Selection Tool | In Execute mode, the Selection Tool can be used for moving nodes around the canvas, and double-clicking on a node will open a shell window for that node; right-clicking on a node invokes a pop-up menu of run-time options for that node. | -| ![](static/pygui/marker.png) | Marker | For drawing freehand lines on the canvas, useful during demonstrations; markings are not saved. | -| ![](static/pygui/run.png) | Run Tool | This tool allows easily running a command on all or a subset of all nodes. A list box allows selecting any of the nodes. A text entry box allows entering any command. The command should return immediately, otherwise the display will block awaiting response. The *ping* command, for example, with no parameters, is not a good idea. The result of each command is displayed in a results box. The first occurrence of the special text "NODE" will be replaced with the node name. The command will not be attempted to run on nodes that are not routers, PCs, or hosts, even if they are selected. | +| Icon | Name | Description | +|------------------------------|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![](static/pygui/stop.png) | Stop Button | Stops Execute mode, terminates the emulation, returns CORE to edit mode. | +| ![](static/pygui/select.png) | Selection Tool | In Execute mode, the Selection Tool can be used for moving nodes around the canvas, and double-clicking on a node will open a shell window for that node; right-clicking on a node invokes a pop-up menu of run-time options for that node. | +| ![](static/pygui/marker.png) | Marker | For drawing freehand lines on the canvas, useful during demonstrations; markings are not saved. | +| ![](static/pygui/run.png) | Run Tool | This tool allows easily running a command on all or a subset of all nodes. A list box allows selecting any of the nodes. A text entry box allows entering any command. The command should return immediately, otherwise the display will block awaiting response. The *ping* command, for example, with no parameters, is not a good idea. The result of each command is displayed in a results box. The first occurrence of the special text "NODE" will be replaced with the node name. The command will not be attempted to run on nodes that are not routers, PCs, or hosts, even if they are selected. | ## Menu @@ -178,58 +178,58 @@ menu, by clicking the dashed line at the top. The File menu contains options for manipulating the **.imn** Configuration Files. Generally, these menu items should not be used in Execute mode. -| Option | Description | -|---|---| -| New Session | This starts a new session with an empty canvas. | -| Save | Saves the current topology. If you have not yet specified a file name, the Save As dialog box is invoked. | -| Save As | Invokes the Save As dialog box for selecting a new **.xml** file for saving the current configuration in the XML file. | -| Open | Invokes the File Open dialog box for selecting a new XML file to open. | -| Recently used files | Above the Quit menu command is a list of recently use files, if any have been opened. You can clear this list in the Preferences dialog box. You can specify the number of files to keep in this list from the Preferences dialog. Click on one of the file names listed to open that configuration file. | +| Option | Description | +|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| New Session | This starts a new session with an empty canvas. | +| Save | Saves the current topology. If you have not yet specified a file name, the Save As dialog box is invoked. | +| Save As | Invokes the Save As dialog box for selecting a new **.xml** file for saving the current configuration in the XML file. | +| Open | Invokes the File Open dialog box for selecting a new XML file to open. | +| Recently used files | Above the Quit menu command is a list of recently use files, if any have been opened. You can clear this list in the Preferences dialog box. You can specify the number of files to keep in this list from the Preferences dialog. Click on one of the file names listed to open that configuration file. | | Execute Python Script | Invokes a File Open dialog box for selecting a Python script to run and automatically connect to. After a selection is made, a Python Script Options dialog box is invoked to allow for command-line options to be added. The Python script must create a new CORE Session and add this session to the daemon's list of sessions in order for this to work. | -| Quit | The Quit command should be used to exit the CORE GUI. CORE may prompt for termination if you are currently in Execute mode. Preferences and the recently-used files list are saved. | +| Quit | The Quit command should be used to exit the CORE GUI. CORE may prompt for termination if you are currently in Execute mode. Preferences and the recently-used files list are saved. | ### Edit Menu -| Option | Description | -|---|---| -| Preferences | Invokes the Preferences dialog box. | -| Custom Nodes | Custom node creation dialog box. | -| Undo | (Disabled) Attempts to undo the last edit in edit mode. | -| Redo | (Disabled) Attempts to redo an edit that has been undone. | -| Cut, Copy, Paste, Delete | Used to cut, copy, paste, and delete a selection. When nodes are pasted, their node numbers are automatically incremented, and existing links are preserved with new IP addresses assigned. Services and their customizations are copied to the new node, but care should be taken as node IP addresses have changed with possibly old addresses remaining in any custom service configurations. Annotations may also be copied and pasted. +| Option | Description | +|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Preferences | Invokes the Preferences dialog box. | +| Custom Nodes | Custom node creation dialog box. | +| Undo | (Disabled) Attempts to undo the last edit in edit mode. | +| Redo | (Disabled) Attempts to redo an edit that has been undone. | +| Cut, Copy, Paste, Delete | Used to cut, copy, paste, and delete a selection. When nodes are pasted, their node numbers are automatically incremented, and existing links are preserved with new IP addresses assigned. Services and their customizations are copied to the new node, but care should be taken as node IP addresses have changed with possibly old addresses remaining in any custom service configurations. Annotations may also be copied and pasted. | ### Canvas Menu The canvas menu provides commands related to the editing canvas. -| Option | Description | -|---|---| -| Size/scale | Invokes a Canvas Size and Scale dialog that allows configuring the canvas size, scale, and geographic reference point. The size controls allow changing the width and height of the current canvas, in pixels or meters. The scale allows specifying how many meters are equivalent to 100 pixels. The reference point controls specify the latitude, longitude, and altitude reference point used to convert between geographic and Cartesian coordinate systems. By clicking the *Save as default* option, all new canvases will be created with these properties. The default canvas size can also be changed in the Preferences dialog box. -| Wallpaper | Used for setting the canvas background image. | +| Option | Description | +|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Size/scale | Invokes a Canvas Size and Scale dialog that allows configuring the canvas size, scale, and geographic reference point. The size controls allow changing the width and height of the current canvas, in pixels or meters. The scale allows specifying how many meters are equivalent to 100 pixels. The reference point controls specify the latitude, longitude, and altitude reference point used to convert between geographic and Cartesian coordinate systems. By clicking the *Save as default* option, all new canvases will be created with these properties. The default canvas size can also be changed in the Preferences dialog box. | +| Wallpaper | Used for setting the canvas background image. | ### View Menu The View menu features items for toggling on and off their display on the canvas. -| Option | Description | -|---|---| +| Option | Description | +|-----------------|-----------------------------------| | Interface Names | Display interface names on links. | -| IPv4 Addresses | Display IPv4 addresses on links. | -| IPv6 Addresses | Display IPv6 addresses on links. | -| Node Labels | Display node names. | -| Link Labels | Display link labels. | -| Annotations | Display annotations. | -| Canvas Grid | Display the canvas grid. | +| IPv4 Addresses | Display IPv4 addresses on links. | +| IPv6 Addresses | Display IPv6 addresses on links. | +| Node Labels | Display node names. | +| Link Labels | Display link labels. | +| Annotations | Display annotations. | +| Canvas Grid | Display the canvas grid. | ### Tools Menu The tools menu lists different utility functions. -| Option | Description | -|---|---| -| Find | Display find dialog used for highlighting a node on the canvas. | -| Auto Grid | Automatically layout nodes in a grid. | -| IP addresses | Invokes the IP Addresses dialog box for configuring which IPv4/IPv6 prefixes are used when automatically addressing new interfaces. | +| Option | Description | +|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Find | Display find dialog used for highlighting a node on the canvas. | +| Auto Grid | Automatically layout nodes in a grid. | +| IP addresses | Invokes the IP Addresses dialog box for configuring which IPv4/IPv6 prefixes are used when automatically addressing new interfaces. | | MAC addresses | Invokes the MAC Addresses dialog box for configuring the starting number used as the lowest byte when generating each interface MAC address. This value should be changed when tunneling between CORE emulations to prevent MAC address conflicts. | ### Widgets Menu @@ -288,31 +288,31 @@ The Session Menu has entries for starting, stopping, and managing sessions, in addition to global options such as node types, comments, hooks, servers, and options. -| Option | Description | -|---|---| -| Sessions | Invokes the CORE Sessions dialog box containing a list of active CORE sessions in the daemon. Basic session information such as name, node count, start time, and a thumbnail are displayed. This dialog allows connecting to different sessions, shutting them down, or starting a new session. | -| Servers | Invokes the CORE emulation servers dialog for configuring. | -| Options | Presents per-session options, such as the IPv4 prefix to be used, if any, for a control network the ability to preserve the session directory; and an on/off switch for SDT3D support. | -| Hooks | Invokes the CORE Session Hooks window where scripts may be configured for a particular session state. The session states are defined in the [table](#session-states) below. The top of the window has a list of configured hooks, and buttons on the bottom left allow adding, editing, and removing hook scripts. The new or edit button will open a hook script editing window. A hook script is a shell script invoked on the host (not within a virtual node). | +| Option | Description | +|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Sessions | Invokes the CORE Sessions dialog box containing a list of active CORE sessions in the daemon. Basic session information such as name, node count, start time, and a thumbnail are displayed. This dialog allows connecting to different sessions, shutting them down, or starting a new session. | +| Servers | Invokes the CORE emulation servers dialog for configuring. | +| Options | Presents per-session options, such as the IPv4 prefix to be used, if any, for a control network the ability to preserve the session directory; and an on/off switch for SDT3D support. | +| Hooks | Invokes the CORE Session Hooks window where scripts may be configured for a particular session state. The session states are defined in the [table](#session-states) below. The top of the window has a list of configured hooks, and buttons on the bottom left allow adding, editing, and removing hook scripts. The new or edit button will open a hook script editing window. A hook script is a shell script invoked on the host (not within a virtual node). | #### Session States -| State | Description | -|---|---| -| Definition | Used by the GUI to tell the backend to clear any state. | -| Configuration | When the user presses the *Start* button, node, link, and other configuration data is sent to the backend. This state is also reached when the user customizes a service. | -| Instantiation | After configuration data has been sent, just before the nodes are created. | -| Runtime | All nodes and networks have been built and are running. (This is the same state at which the previously-named *global experiment script* was run.) -| Datacollect | The user has pressed the *Stop* button, but before services have been stopped and nodes have been shut down. This is a good time to collect log files and other data from the nodes. | -| Shutdown | All nodes and networks have been shut down and destroyed. | +| State | Description | +|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Definition | Used by the GUI to tell the backend to clear any state. | +| Configuration | When the user presses the *Start* button, node, link, and other configuration data is sent to the backend. This state is also reached when the user customizes a service. | +| Instantiation | After configuration data has been sent, just before the nodes are created. | +| Runtime | All nodes and networks have been built and are running. (This is the same state at which the previously-named *global experiment script* was run.) | +| Datacollect | The user has pressed the *Stop* button, but before services have been stopped and nodes have been shut down. This is a good time to collect log files and other data from the nodes. | +| Shutdown | All nodes and networks have been shut down and destroyed. | ### Help Menu -| Option | Description | -|---|---| -| CORE Github (www) | Link to the CORE GitHub page. | -| CORE Documentation (www) | Lnk to the CORE Documentation page. | -| About | Invokes the About dialog box for viewing version information. | +| Option | Description | +|--------------------------|---------------------------------------------------------------| +| CORE Github (www) | Link to the CORE GitHub page. | +| CORE Documentation (www) | Lnk to the CORE Documentation page. | +| About | Invokes the About dialog box for viewing version information. | ## Connecting with Physical Networks @@ -519,10 +519,10 @@ complexity and CPU usage. The availability of certain plug-ins varies depending on platform. See the table below for a brief overview of wireless model types. -|Model|Type|Supported Platform(s)|Fidelity|Description| -|-----|----|---------------------|--------|-----------| -|Basic|on/off|Linux|Low|Ethernet bridging with nftables| -|EMANE|Plug-in|Linux|High|TAP device connected to EMANE emulator with pluggable MAC and PHY radio types| +| Model | Type | Supported Platform(s) | Fidelity | Description | +|-------|---------|-----------------------|----------|-------------------------------------------------------------------------------| +| Basic | on/off | Linux | Low | Ethernet bridging with nftables | +| EMANE | Plug-in | Linux | High | TAP device connected to EMANE emulator with pluggable MAC and PHY radio types | To quickly build a wireless network, you can first place several router nodes onto the canvas. If you have the @@ -556,11 +556,11 @@ See the [EMANE](emane.md) chapter for details on using EMANE. CORE has a few ways to script mobility. -| Option | Description | -|---|---| -| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. | -| CORE API | An external entity can move nodes by sending CORE API Node messages with updated X,Y coordinates; the **coresendmsg** utility allows a shell script to generate these messages. | -| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. | +| Option | Description | +|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. | +| CORE API | An external entity can move nodes by sending CORE API Node messages with updated X,Y coordinates; the **coresendmsg** utility allows a shell script to generate these messages. | +| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. | For the first method, you can create a mobility script using a text editor, or using a tool such as [BonnMotion](http://net.cs.uni-bonn.de/wg/cs/applications/bonnmotion/), and associate the script with one of the wireless diff --git a/docs/python.md b/docs/python.md index fe776662f..ba4b4f335 100644 --- a/docs/python.md +++ b/docs/python.md @@ -341,19 +341,11 @@ EMANE Model Configuration: ```python from core import utils -# emane network specific config -session.emane.set_model_config(emane.id, EmaneIeee80211abgModel.name, { - "unicastrate": "3", -}) - -# node specific config -session.emane.set_model_config(node.id, EmaneIeee80211abgModel.name, { - "unicastrate": "3", -}) - -# node interface specific config +# standardized way to retrieve an appropriate config id +# iface id can be omitted, to allow a general configuration for a model, per node config_id = utils.iface_config_id(node.id, iface_id) -session.emane.set_model_config(config_id, EmaneIeee80211abgModel.name, { +# set emane configuration for the config id +session.emane.set_config(config_id, EmaneIeee80211abgModel.name, { "unicastrate": "3", }) ``` diff --git a/docs/services.md b/docs/services.md index 477a828ca..f92e5df17 100644 --- a/docs/services.md +++ b/docs/services.md @@ -21,28 +21,28 @@ shutdown commands, and meta-data associated with a node. ## Available Services -| Service Group | Services | -|---|---| -|[BIRD](services/bird.md)|BGP, OSPF, RADV, RIP, Static| -|[EMANE](services/emane.md)|Transport Service| -|[FRR](services/frr.md)|BABEL, BGP, OSPFv2, OSPFv3, PIMD, RIP, RIPNG, Zebra| -|[NRL](services/nrl.md)|arouted, MGEN Sink, MGEN Actor, NHDP, OLSR, OLSRORG, OLSRv2, SMF| -|[Quagga](services/quagga.md)|BABEL, BGP, OSPFv2, OSPFv3, OSPFv3 MDR, RIP, RIPNG, XPIMD, Zebra| -|[SDN](services/sdn.md)|OVS, RYU| -|[Security](services/security.md)|Firewall, IPsec, NAT, VPN Client, VPN Server| -|[Utility](services/utility.md)|ATD, Routing Utils, DHCP, FTP, IP Forward, PCAP, RADVD, SSF, UCARP| -|[XORP](services/xorp.md)|BGP, OLSR, OSPFv2, OSPFv3, PIMSM4, PIMSM6, RIP, RIPNG, Router Manager| +| Service Group | Services | +|----------------------------------|-----------------------------------------------------------------------| +| [BIRD](services/bird.md) | BGP, OSPF, RADV, RIP, Static | +| [EMANE](services/emane.md) | Transport Service | +| [FRR](services/frr.md) | BABEL, BGP, OSPFv2, OSPFv3, PIMD, RIP, RIPNG, Zebra | +| [NRL](services/nrl.md) | arouted, MGEN Sink, MGEN Actor, NHDP, OLSR, OLSRORG, OLSRv2, SMF | +| [Quagga](services/quagga.md) | BABEL, BGP, OSPFv2, OSPFv3, OSPFv3 MDR, RIP, RIPNG, XPIMD, Zebra | +| [SDN](services/sdn.md) | OVS, RYU | +| [Security](services/security.md) | Firewall, IPsec, NAT, VPN Client, VPN Server | +| [Utility](services/utility.md) | ATD, Routing Utils, DHCP, FTP, IP Forward, PCAP, RADVD, SSF, UCARP | +| [XORP](services/xorp.md) | BGP, OLSR, OSPFv2, OSPFv3, PIMSM4, PIMSM6, RIP, RIPNG, Router Manager | ## Node Types and Default Services Here are the default node types and their services: -| Node Type | Services | -|---|---| -| *router* | zebra, OSFPv2, OSPFv3, and IPForward services for IGP link-state routing. | -| *host* | DefaultRoute and SSH services, representing an SSH server having a default route when connected directly to a router. | -| *PC* | DefaultRoute service for having a default route when connected directly to a router. | -| *mdr* | zebra, OSPFv3MDR, and IPForward services for wireless-optimized MANET Designated Router routing. | +| Node Type | Services | +|-----------|--------------------------------------------------------------------------------------------------------------------------------------------| +| *router* | zebra, OSFPv2, OSPFv3, and IPForward services for IGP link-state routing. | +| *host* | DefaultRoute and SSH services, representing an SSH server having a default route when connected directly to a router. | +| *PC* | DefaultRoute service for having a default route when connected directly to a router. | +| *mdr* | zebra, OSPFv3MDR, and IPForward services for wireless-optimized MANET Designated Router routing. | | *prouter* | a physical router, having the same default services as the *router* node type; for incorporating Linux testbed machines into an emulation. | Configuration files can be automatically generated by each service. For diff --git a/docs/static/distributed-emane-configuration.png b/docs/static/distributed-emane-configuration.png index 219e5d43a..ad66a6f3e 100644 Binary files a/docs/static/distributed-emane-configuration.png and b/docs/static/distributed-emane-configuration.png differ diff --git a/docs/static/single-pc-emane.png b/docs/static/single-pc-emane.png index 579255b81..8c58d825e 100644 Binary files a/docs/static/single-pc-emane.png and b/docs/static/single-pc-emane.png differ diff --git a/tasks.py b/tasks.py index 1ebb860fe..58f8282b2 100644 --- a/tasks.py +++ b/tasks.py @@ -210,7 +210,7 @@ def install_poetry(c: Context, dev: bool, local: bool, hide: bool) -> None: def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None: - if c.run("which zebra", warn=True, hide=hide): + if c.run("sudo which zebra", warn=True, hide=hide): print("\nquagga already installed, skipping ospf mdr") return if os_info.like == OsLike.DEBIAN: