Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e9b83b0
daemon: refactored how interfaces are configured, updated link edits …
bharnden Jan 25, 2022
6791269
daemon: refactored interfaces to store configuration options as link …
bharnden Jan 26, 2022
d5b05a3
gui: adjustment to update drawing asymmetric edge data when joining a…
bharnden Jan 26, 2022
8f76720
daemon: small adjustment to fix xml related issues parsing links for …
bharnden Jan 26, 2022
df5ff02
docs: fix for bad config service example
bharnden Feb 2, 2022
44b7b6a
daemon: update config service files to use paths for retrieving templ…
bharnden Feb 3, 2022
43737a4
daemon: update nftables bridge tables to use priority -1 to beat defa…
bharnden Feb 3, 2022
efb97d1
daemon: updates to remove the delay for processing wlan changes along…
bharnden Feb 5, 2022
490a4ac
daemon: fixed issues related to rj45
bharnden Feb 5, 2022
0e2219f
daemon: fixed issue creating directory for files when needed, within …
bharnden Feb 5, 2022
47b02c3
docs: removed notes on needing to install ebtables legacy
bharnden Feb 9, 2022
a1e9fc0
install: bumped pinned poetry version to 1.1.12 to avoid installation…
bharnden Feb 11, 2022
e80d220
install: bumping version to 8.1.0 for next release
bharnden Feb 11, 2022
0fcc532
docs: updated note on poetry version installed
bharnden Feb 12, 2022
3c64654
services: fix missing configurations for ospfv2 in config services
bharnden Feb 17, 2022
9d32c43
install: updates to README and install docs for installing to run ens…
bharnden Feb 17, 2022
113be65
install: adjustments to have a better workflow for installation
bharnden Feb 17, 2022
96f2408
daemon: fixed deadlock issue when starting/stopping nftables queue
bharnden Feb 18, 2022
458b7f1
pygui: fixed antenna image to properly show alpha png
bharnden Feb 18, 2022
a341691
install: poetry updates to fix vulnerability issues with protobuf, py…
bharnden Feb 18, 2022
cdde1c8
added 8.1.0 notes to changelog
bharnden Feb 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 2022-02-18 CORE 8.1.0

* Installation
* updated dependency versions to account for known vulnerabilities
* GUI
* fixed issue drawing asymmetric link configurations when joining a session
* daemon
* fixed issue getting templates and creating files for config services
* added by directional support for network to network links
* \#647 - fixed issue when creating RJ45 nodes
* \#646 - fixed issue when creating files for Docker nodes
* \#645 - improved wlan change updates to account for all updates with no delay
* services
* fixed file generation for OSPFv2 config service

## 2022-01-12 CORE 8.0.0

*Breaking Changes
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ For more detailed installation see [here](https://coreemu.github.io/core/install
```shell
git clone https://github.com/coreemu/core.git
cd core
# install dependencies to run installation task
./setup.sh
# run the following or open a new terminal
source ~/.bashrc
# Ubuntu
inv install
# CentOS
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, 8.0.0)
AC_INIT(core, 8.1.0)

# autoconf and automake initialization
AC_CONFIG_SRCDIR([netns/version.h.in])
Expand Down
16 changes: 12 additions & 4 deletions daemon/core/api/grpc/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,17 +288,25 @@ def StartSession(

# create links
links = []
asym_links = []
edit_links = []
known_links = set()
for link in request.session.links:
if link.options.unidirectional:
asym_links.append(link)
iface1 = link.iface1.id if link.iface1 else None
iface2 = link.iface2.id if link.iface2 else None
if link.node1_id < link.node2_id:
link_id = (link.node1_id, iface1, link.node2_id, iface2)
else:
link_id = (link.node2_id, iface2, link.node1_id, iface1)
if link_id in known_links:
edit_links.append(link)
else:
known_links.add(link_id)
links.append(link)
_, exceptions = grpcutils.create_links(session, links)
if exceptions:
exceptions = [str(x) for x in exceptions]
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
_, exceptions = grpcutils.edit_links(session, asym_links)
_, exceptions = grpcutils.edit_links(session, edit_links)
if exceptions:
exceptions = [str(x) for x in exceptions]
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
Expand Down
24 changes: 18 additions & 6 deletions daemon/core/configservice/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@
TEMPLATES_DIR: str = "templates"


def get_template_path(file_path: Path) -> str:
"""
Utility to convert a given file path to a valid template path format.

:param file_path: file path to convert
:return: template path
"""
if file_path.is_absolute():
template_path = str(file_path.relative_to("/"))
else:
template_path = str(file_path)
return template_path


class ConfigServiceMode(enum.Enum):
BLOCKING = 0
NON_BLOCKING = 1
Expand Down Expand Up @@ -295,10 +309,7 @@ def get_templates(self) -> Dict[str, str]:
templates = {}
for file in self.files:
file_path = Path(file)
if file_path.is_absolute():
template_path = str(file_path.relative_to("/"))
else:
template_path = str(file_path)
template_path = get_template_path(file_path)
if file in self.custom_templates:
template = self.custom_templates[file]
template = self.clean_text(template)
Expand All @@ -322,11 +333,12 @@ def create_files(self) -> None:
"node(%s) service(%s) template(%s)", self.node.name, self.name, file
)
file_path = Path(file)
template_path = get_template_path(file_path)
if file in self.custom_templates:
text = self.custom_templates[file]
rendered = self.render_text(text, data)
elif self.templates.has_template(file_path.name):
rendered = self.render_template(file_path.name, data)
elif self.templates.has_template(template_path):
rendered = self.render_template(template_path, data)
else:
text = self.get_text_template(file)
rendered = self.render_text(text, data)
Expand Down
50 changes: 43 additions & 7 deletions daemon/core/configservices/quaggaservices/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from core.emane.nodes import EmaneNet
from core.nodes.base import CoreNodeBase
from core.nodes.interface import DEFAULT_MTU, CoreInterface
from core.nodes.network import WlanNode
from core.nodes.network import PtpNet, WlanNode
from core.nodes.physical import Rj45Node

logger = logging.getLogger(__name__)
GROUP: str = "Quagga"
Expand Down Expand Up @@ -55,6 +56,20 @@ def get_router_id(node: CoreNodeBase) -> str:
return "0.0.0.0"


def rj45_check(iface: CoreInterface) -> bool:
"""
Helper to detect whether interface is connected an external RJ45
link.
"""
if iface.net:
for peer_iface in iface.net.get_ifaces():
if peer_iface == iface:
continue
if isinstance(peer_iface.node, Rj45Node):
return True
return False


class Zebra(ConfigService):
name: str = "zebra"
group: str = GROUP
Expand Down Expand Up @@ -105,7 +120,13 @@ def data(self) -> Dict[str, Any]:
ip4s.append(str(ip4))
for ip6 in iface.ip6s:
ip6s.append(str(ip6))
ifaces.append((iface, ip4s, ip6s, iface.control))
configs = []
if not iface.control:
for service in services:
config = service.quagga_iface_config(iface)
if config:
configs.append(config.split("\n"))
ifaces.append((iface, ip4s, ip6s, configs))

return dict(
quagga_bin_search=quagga_bin_search,
Expand Down Expand Up @@ -156,17 +177,32 @@ class Ospfv2(QuaggaService, ConfigService):
ipv4_routing: bool = True

def quagga_iface_config(self, iface: CoreInterface) -> str:
if has_mtu_mismatch(iface):
return "ip ospf mtu-ignore"
else:
return ""
has_mtu = has_mtu_mismatch(iface)
has_rj45 = rj45_check(iface)
is_ptp = isinstance(iface.net, PtpNet)
data = dict(has_mtu=has_mtu, is_ptp=is_ptp, has_rj45=has_rj45)
text = """
% if has_mtu:
ip ospf mtu-ignore
% endif
% if has_rj45:
<% return STOP_RENDERING %>
% endif
% if is_ptp:
ip ospf network point-to-point
% endif
ip ospf hello-interval 2
ip ospf dead-interval 6
ip ospf retransmit-interval 5
"""
return self.render_text(text, data)

def quagga_config(self) -> str:
router_id = get_router_id(self.node)
addresses = []
for iface in self.node.get_ifaces(control=False):
for ip4 in iface.ip4s:
addresses.append(str(ip4.ip))
addresses.append(str(ip4))
data = dict(router_id=router_id, addresses=addresses)
text = """
router ospf
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% for iface, ip4s, ip6s, is_control in ifaces:
% for iface, ip4s, ip6s, configs in ifaces:
interface ${iface.name}
% if want_ip4:
% for addr in ip4s:
Expand All @@ -10,13 +10,11 @@ interface ${iface.name}
ipv6 address ${addr}
% endfor
% endif
% if not is_control:
% for service in services:
% for line in service.quagga_iface_config(iface).split("\n"):
% for config in configs:
% for line in config:
${line}
% endfor
% endfor
% endif
% endfor
!
% endfor

Expand Down
63 changes: 62 additions & 1 deletion daemon/core/emulator/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
CORE data objects.
"""
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, List, Optional, Tuple
from typing import TYPE_CHECKING, Any, List, Optional, Tuple

import netaddr

Expand Down Expand Up @@ -176,6 +176,67 @@ class LinkOptions:
key: int = None
buffer: int = None

def update(self, options: "LinkOptions") -> bool:
"""
Updates current options with values from other options.

:param options: options to update with
:return: True if any value has changed, False otherwise
"""
changed = False
if options.delay is not None and 0 <= options.delay != self.delay:
self.delay = options.delay
changed = True
if options.bandwidth is not None and 0 <= options.bandwidth != self.bandwidth:
self.bandwidth = options.bandwidth
changed = True
if options.loss is not None and 0 <= options.loss != self.loss:
self.loss = options.loss
changed = True
if options.dup is not None and 0 <= options.dup != self.dup:
self.dup = options.dup
changed = True
if options.jitter is not None and 0 <= options.jitter != self.jitter:
self.jitter = options.jitter
changed = True
if options.buffer is not None and 0 <= options.buffer != self.buffer:
self.buffer = options.buffer
changed = True
return changed

def is_clear(self) -> bool:
"""
Checks if the current option values represent a clear state.

:return: True if the current values should clear, False otherwise
"""
clear = self.delay is None or self.delay <= 0
clear &= self.jitter is None or self.jitter <= 0
clear &= self.loss is None or self.loss <= 0
clear &= self.dup is None or self.dup <= 0
clear &= self.bandwidth is None or self.bandwidth <= 0
clear &= self.buffer is None or self.buffer <= 0
return clear

def __eq__(self, other: Any) -> bool:
"""
Custom logic to check if this link options is equivalent to another.

:param other: other object to check
:return: True if they are both link options with the same values,
False otherwise
"""
if not isinstance(other, LinkOptions):
return False
return (
self.delay == other.delay
and self.jitter == other.jitter
and self.loss == other.loss
and self.dup == other.dup
and self.bandwidth == other.bandwidth
and self.buffer == other.buffer
)


@dataclass
class LinkData:
Expand Down
Loading