Skip to content

Commit

Permalink
Merge pull request #534 from coreemu/develop
Browse files Browse the repository at this point in the history
merge for 7.3.0
  • Loading branch information
bharnden authored Dec 2, 2020
2 parents 56e98f4 + 8297b74 commit a57b838
Show file tree
Hide file tree
Showing 48 changed files with 2,567 additions and 521 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
## 2020-12-02 CORE 7.3.0

* core-daemon
* fixed issue where emane global configuration was not being sent to core-gui
* updated controlnet names on host to be prefixed with ctrl
* fixed RJ45 link shutdown from core-gui causing an error
* fixed emane external transport xml generation
* \#517 - update to account for radvd required directory
* \#514 - support added for session specific environment files
* \#529 - updated to configure netem limit based on delay or user specified, requires kernel 3.3+
* core-pygui
* fixed issue drawing wlan/emane link options when it should not have
* edge labels are now placed a set distance from nodes like original gui
* link color/width are now saved to xml files
* added support to configure buffer size for links
* \#525 - added support for multiple wired links between the same nodes
* \#526 - added option to hide/show links with 100% loss
* Documentation
* \#527 - typo in service documentation
* \#515 - added examples to docs for using EMANE features within a CORE context

## 2020-09-29 CORE 7.2.1

* core-daemon
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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, 7.2.1)
AC_INIT(core, 7.3.0)

# autoconf and automake initialization
AC_CONFIG_SRCDIR([netns/version.h.in])
Expand Down
2 changes: 2 additions & 0 deletions daemon/core/api/grpc/grpcutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def add_link_data(
options.mer = options_proto.mer
options.burst = options_proto.burst
options.mburst = options_proto.mburst
options.buffer = options_proto.buffer
options.unidirectional = options_proto.unidirectional
options.key = options_proto.key
return iface1_data, iface2_data, options, link_type
Expand Down Expand Up @@ -329,6 +330,7 @@ def convert_link_options(options_data: LinkOptions) -> core_pb2.LinkOptions:
burst=options_data.burst,
delay=options_data.delay,
dup=options_data.dup,
buffer=options_data.buffer,
unidirectional=options_data.unidirectional,
)

Expand Down
1 change: 1 addition & 0 deletions daemon/core/api/grpc/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ def EditLink(
mburst=options_proto.mburst,
unidirectional=options_proto.unidirectional,
key=options_proto.key,
buffer=options_proto.buffer,
)
session.update_link(node1_id, node2_id, iface1_id, iface2_id, options)
iface1 = InterfaceData(id=iface1_id)
Expand Down
3 changes: 3 additions & 0 deletions daemon/core/api/grpc/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ class LinkOptions:
delay: int = 0
dup: int = 0
unidirectional: bool = False
buffer: int = 0

@classmethod
def from_proto(cls, proto: core_pb2.LinkOptions) -> "LinkOptions":
Expand All @@ -471,6 +472,7 @@ def from_proto(cls, proto: core_pb2.LinkOptions) -> "LinkOptions":
delay=proto.delay,
dup=proto.dup,
unidirectional=proto.unidirectional,
buffer=proto.buffer,
)

def to_proto(self) -> core_pb2.LinkOptions:
Expand All @@ -485,6 +487,7 @@ def to_proto(self) -> core_pb2.LinkOptions:
delay=self.delay,
dup=self.dup,
unidirectional=self.unidirectional,
buffer=self.buffer,
)


Expand Down
25 changes: 22 additions & 3 deletions daemon/core/api/tlv/corehandlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from core.location.mobility import BasicRangeModel
from core.nodes.base import CoreNode, CoreNodeBase, NodeBase
from core.nodes.network import WlanNode
from core.nodes.physical import Rj45Node
from core.services.coreservices import ServiceManager, ServiceShim


Expand Down Expand Up @@ -787,20 +788,30 @@ def handle_link_message(self, message):
options = LinkOptions()
options.delay = message.get_tlv(LinkTlvs.DELAY.value)
options.bandwidth = message.get_tlv(LinkTlvs.BANDWIDTH.value)
options.loss = message.get_tlv(LinkTlvs.LOSS.value)
options.dup = message.get_tlv(LinkTlvs.DUP.value)
options.jitter = message.get_tlv(LinkTlvs.JITTER.value)
options.mer = message.get_tlv(LinkTlvs.MER.value)
options.burst = message.get_tlv(LinkTlvs.BURST.value)
options.mburst = message.get_tlv(LinkTlvs.MBURST.value)
options.unidirectional = message.get_tlv(LinkTlvs.UNIDIRECTIONAL.value)
options.key = message.get_tlv(LinkTlvs.KEY.value)
loss = message.get_tlv(LinkTlvs.LOSS.value)
dup = message.get_tlv(LinkTlvs.DUP.value)
if loss is not None:
options.loss = float(loss)
if dup is not None:
options.dup = int(dup)

if message.flags & MessageFlags.ADD.value:
self.session.add_link(
node1_id, node2_id, iface1_data, iface2_data, options, link_type
)
elif message.flags & MessageFlags.DELETE.value:
node1 = self.session.get_node(node1_id, NodeBase)
node2 = self.session.get_node(node2_id, NodeBase)
if isinstance(node1, Rj45Node):
iface1_data.id = node1.iface_id
if isinstance(node2, Rj45Node):
iface2_data.id = node2.iface_id
self.session.delete_link(
node1_id, node2_id, iface1_data.id, iface2_data.id, link_type
)
Expand Down Expand Up @@ -1851,7 +1862,15 @@ def send_objects(self):
)
self.session.broadcast_config(config_data)

# send emane model info
# send global emane config
config = self.session.emane.get_configs()
logging.debug("global emane config: values(%s)", config)
config_data = ConfigShim.config_data(
0, None, ConfigFlags.UPDATE.value, self.session.emane.emane_config, config
)
self.session.broadcast_config(config_data)

# send emane model configs
for node_id in self.session.emane.nodes():
emane_configs = self.session.emane.get_all_configs(node_id)
for model_name in emane_configs:
Expand Down
4 changes: 2 additions & 2 deletions daemon/core/configservices/frrservices/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from core.configservice.base import ConfigService, ConfigServiceMode
from core.emane.nodes import EmaneNet
from core.nodes.base import CoreNodeBase
from core.nodes.interface import CoreInterface
from core.nodes.interface import DEFAULT_MTU, CoreInterface
from core.nodes.network import WlanNode

GROUP: str = "FRR"
Expand All @@ -18,7 +18,7 @@ def has_mtu_mismatch(iface: CoreInterface) -> bool:
mtu-ignore command. This is needed when e.g. a node is linked via a
GreTap device.
"""
if iface.mtu != 1500:
if iface.mtu != DEFAULT_MTU:
return True
if not iface.net:
return False
Expand Down
4 changes: 2 additions & 2 deletions daemon/core/configservices/quaggaservices/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from core.configservice.base import ConfigService, ConfigServiceMode
from core.emane.nodes import EmaneNet
from core.nodes.base import CoreNodeBase
from core.nodes.interface import CoreInterface
from core.nodes.interface import DEFAULT_MTU, CoreInterface
from core.nodes.network import WlanNode

GROUP: str = "Quagga"
Expand All @@ -19,7 +19,7 @@ def has_mtu_mismatch(iface: CoreInterface) -> bool:
mtu-ignore command. This is needed when e.g. a node is linked via a
GreTap device.
"""
if iface.mtu != 1500:
if iface.mtu != DEFAULT_MTU:
return True
if not iface.net:
return False
Expand Down
2 changes: 1 addition & 1 deletion daemon/core/configservices/utilservices/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def data(self) -> Dict[str, Any]:
class RadvdService(ConfigService):
name: str = "radvd"
group: str = GROUP_NAME
directories: List[str] = ["/etc/radvd"]
directories: List[str] = ["/etc/radvd", "/var/run/radvd"]
files: List[str] = ["/etc/radvd/radvd.conf"]
executables: List[str] = ["radvd"]
dependencies: List[str] = []
Expand Down
1 change: 1 addition & 0 deletions daemon/core/emulator/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class LinkOptions:
mburst: int = None
unidirectional: int = None
key: int = None
buffer: int = None


@dataclass
Expand Down
46 changes: 23 additions & 23 deletions daemon/core/emulator/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import tempfile
import threading
import time
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar

from core import constants, utils
Expand Down Expand Up @@ -997,28 +998,25 @@ def get_environment(self, state: bool = True) -> Dict[str, str]:
env["SESSION_USER"] = str(self.user)
if state:
env["SESSION_STATE"] = str(self.state)
# attempt to read and add environment config file
environment_config_file = os.path.join(constants.CORE_CONF_DIR, "environment")
try:
if os.path.isfile(environment_config_file):
utils.load_config(environment_config_file, env)
except IOError:
logging.warning(
"environment configuration file does not exist: %s",
environment_config_file,
)
# attempt to read and add user environment file
# try reading and merging optional environments from:
# /etc/core/environment
# /home/user/.core/environment
# /tmp/pycore.<session id>/environment
core_env_path = Path(constants.CORE_CONF_DIR) / "environment"
session_env_path = Path(self.session_dir) / "environment"
if self.user:
environment_user_file = os.path.join(
"/home", self.user, ".core", "environment"
)
try:
utils.load_config(environment_user_file, env)
except IOError:
logging.debug(
"user core environment settings file not present: %s",
environment_user_file,
)
user_home_path = Path(f"~{self.user}").expanduser()
user_env1 = user_home_path / ".core" / "environment"
user_env2 = user_home_path / ".coregui" / "environment"
paths = [core_env_path, user_env1, user_env2, session_env_path]
else:
paths = [core_env_path, session_env_path]
for path in paths:
if path.is_file():
try:
utils.load_config(path, env)
except IOError:
logging.exception("error reading environment file: %s", path)
return env

def set_thumbnail(self, thumb_file: str) -> None:
Expand Down Expand Up @@ -1447,12 +1445,14 @@ def add_remove_control_net(
)
control_net = self.create_node(
CtrlNet,
True,
prefix,
start=False,
prefix=prefix,
_id=_id,
updown_script=updown_script,
serverintf=server_iface,
)
control_net.brname = f"ctrl{net_index}.{self.short_session_id()}"
control_net.startup()
return control_net

def add_remove_control_iface(
Expand Down
55 changes: 39 additions & 16 deletions daemon/core/gui/coreclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ def __init__(self, app: "Application", proxy: bool) -> None:
self.read_config()

# helpers
self.iface_to_edge: Dict[Tuple[int, ...], Tuple[int, ...]] = {}
self.iface_to_edge: Dict[Tuple[int, ...], CanvasEdge] = {}
self.ifaces_manager: InterfaceManager = InterfaceManager(self.app)
self.observer: Optional[str] = None

# session data
self.mobility_players: Dict[int, MobilityPlayer] = {}
self.canvas_nodes: Dict[int, CanvasNode] = {}
self.links: Dict[Tuple[int, int], CanvasEdge] = {}
self.links: Dict[str, CanvasEdge] = {}
self.handling_throughputs: Optional[grpc.Future] = None
self.handling_cpu_usage: Optional[grpc.Future] = None
self.handling_events: Optional[grpc.Future] = None
Expand Down Expand Up @@ -225,11 +225,9 @@ def handle_link_event(self, event: LinkEvent) -> None:
self.app.canvas.add_wired_edge(canvas_node1, canvas_node2, event.link)
self.app.canvas.organize()
elif event.message_type == MessageType.DELETE:
self.app.canvas.delete_wired_edge(canvas_node1, canvas_node2)
self.app.canvas.delete_wired_edge(event.link)
elif event.message_type == MessageType.NONE:
self.app.canvas.update_wired_edge(
canvas_node1, canvas_node2, event.link
)
self.app.canvas.update_wired_edge(event.link)
else:
logging.warning("unknown link event: %s", event)

Expand Down Expand Up @@ -383,6 +381,17 @@ def parse_metadata(self) -> None:
except ValueError:
logging.exception("unknown shape: %s", shape_type)

# load edges config
edges_config = config.get("edges")
if edges_config:
edges_config = json.loads(edges_config)
logging.info("edges config: %s", edges_config)
for edge_config in edges_config:
edge = self.links[edge_config["token"]]
edge.width = edge_config["width"]
edge.color = edge_config["color"]
edge.redraw()

def create_new_session(self) -> None:
"""
Create a new session
Expand Down Expand Up @@ -570,7 +579,15 @@ def set_metadata(self) -> None:
shapes.append(shape.metadata())
shapes = json.dumps(shapes)

metadata = {"canvas": canvas_config, "shapes": shapes}
# create edges config
edges_config = []
for edge in self.links.values():
edge_config = dict(token=edge.token, width=edge.width, color=edge.color)
edges_config.append(edge_config)
edges_config = json.dumps(edges_config)

# save metadata
metadata = dict(canvas=canvas_config, shapes=shapes, edges=edges_config)
response = self.client.set_session_metadata(self.session.id, metadata)
logging.debug("set session metadata %s, result: %s", metadata, response)

Expand Down Expand Up @@ -877,7 +894,7 @@ def create_iface(self, canvas_node: CanvasNode) -> Interface:

def create_link(
self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode
) -> None:
) -> Link:
"""
Create core link for a pair of canvas nodes, with token referencing
the canvas edge.
Expand All @@ -888,25 +905,31 @@ def create_link(
src_iface = None
if NodeUtils.is_container_node(src_node.type):
src_iface = self.create_iface(canvas_src_node)
self.iface_to_edge[(src_node.id, src_iface.id)] = edge.token
edge.src_iface = src_iface
canvas_src_node.ifaces[src_iface.id] = src_iface
dst_iface = None
if NodeUtils.is_container_node(dst_node.type):
dst_iface = self.create_iface(canvas_dst_node)
self.iface_to_edge[(dst_node.id, dst_iface.id)] = edge.token
edge.dst_iface = dst_iface
canvas_dst_node.ifaces[dst_iface.id] = dst_iface
link = Link(
type=LinkType.WIRED,
node1_id=src_node.id,
node2_id=dst_node.id,
iface1=src_iface,
iface2=dst_iface,
)
edge.set_link(link)
self.links[edge.token] = edge
logging.info("added link between %s and %s", src_node.name, dst_node.name)
return link

def save_edge(
self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode
) -> None:
self.links[edge.token] = edge
src_node = canvas_src_node.core_node
dst_node = canvas_dst_node.core_node
if NodeUtils.is_container_node(src_node.type):
src_iface_id = edge.link.iface1.id
self.iface_to_edge[(src_node.id, src_iface_id)] = edge
if NodeUtils.is_container_node(dst_node.type):
dst_iface_id = edge.link.iface2.id
self.iface_to_edge[(dst_node.id, dst_iface_id)] = edge

def get_wlan_configs_proto(self) -> List[wlan_pb2.WlanConfig]:
configs = []
Expand Down
Loading

0 comments on commit a57b838

Please sign in to comment.