core-extra/daemon/core/services/nrl.py

582 lines
19 KiB
Python

"""
nrl.py: defines services provided by NRL protolib tools hosted here:
http://www.nrl.navy.mil/itd/ncs/products
"""
from typing import Optional
from core import utils
from core.nodes.base import CoreNode
from core.services.coreservices import CoreService
class NrlService(CoreService):
"""
Parent class for NRL services. Defines properties and methods
common to NRL's routing daemons.
"""
name: Optional[str] = None
group: str = "ProtoSvc"
@classmethod
def generate_config(cls, node: CoreNode, filename: str) -> str:
return ""
@staticmethod
def firstipv4prefix(node: CoreNode, prefixlen: int = 24) -> str:
"""
Similar to QuaggaService.routerid(). Helper to return the first IPv4
prefix of a node, using the supplied prefix length. This ignores the
interface's prefix length, so e.g. '/32' can turn into '/24'.
"""
for iface in node.get_ifaces(control=False):
ip4 = iface.get_ip4()
if ip4:
return f"{ip4.ip}/{prefixlen}"
return f"0.0.0.0/{prefixlen}"
class MgenSinkService(NrlService):
name: str = "MGEN_Sink"
executables: tuple[str, ...] = ("mgen",)
configs: tuple[str, ...] = ("sink.mgen",)
startup: tuple[str, ...] = ("mgen input sink.mgen",)
validate: tuple[str, ...] = ("pidof mgen",)
shutdown: tuple[str, ...] = ("killall mgen",)
@classmethod
def generate_config(cls, node: CoreNode, filename: str) -> str:
cfg = "0.0 LISTEN UDP 5000\n"
for iface in node.get_ifaces():
name = utils.sysctl_devname(iface.name)
cfg += f"0.0 Join 224.225.1.2 INTERFACE {name}\n"
return cfg
@classmethod
def get_startup(cls, node: CoreNode) -> tuple[str, ...]:
cmd = cls.startup[0]
cmd += f" output /tmp/mgen_{node.name}.log"
return (cmd,)
class NrlNhdp(NrlService):
"""
NeighborHood Discovery Protocol for MANET networks.
"""
name: str = "NHDP"
executables: tuple[str, ...] = ("nrlnhdp",)
startup: tuple[str, ...] = ("nrlnhdp",)
shutdown: tuple[str, ...] = ("killall nrlnhdp",)
validate: tuple[str, ...] = ("pidof nrlnhdp",)
@classmethod
def get_startup(cls, node: CoreNode) -> tuple[str, ...]:
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls.startup[0]
cmd += " -l /var/log/nrlnhdp.log"
cmd += f" -rpipe {node.name}_nhdp"
servicenames = map(lambda x: x.name, node.services)
if "SMF" in servicenames:
cmd += " -flooding ecds"
cmd += f" -smfClient {node.name}_smf"
ifaces = node.get_ifaces(control=False)
if len(ifaces) > 0:
iface_names = map(lambda x: x.name, ifaces)
cmd += " -i "
cmd += " -i ".join(iface_names)
return (cmd,)
class NrlSmf(NrlService):
"""
Simplified Multicast Forwarding for MANET networks.
"""
name: str = "SMF"
executables: tuple[str, ...] = ("nrlsmf",)
startup: tuple[str, ...] = ("bash startsmf.sh",)
shutdown: tuple[str, ...] = ("killall nrlsmf",)
validate: tuple[str, ...] = ("pidof nrlsmf",)
configs: tuple[str, ...] = ("startsmf.sh",)
@classmethod
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a startup script for SMF. Because nrlsmf does not
daemonize, it can cause problems in some situations when launched
directly using vcmd.
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by nrl.py:NrlSmf.generateconfig()\n"
comments = ""
cmd = f"nrlsmf instance {node.name}_smf"
servicenames = map(lambda x: x.name, node.services)
ifaces = node.get_ifaces(control=False)
if len(ifaces) == 0:
return ""
if len(ifaces) > 0:
if "NHDP" in servicenames:
comments += "# NHDP service is enabled\n"
cmd += " ecds "
elif "OLSR" in servicenames:
comments += "# OLSR service is enabled\n"
cmd += " smpr "
else:
cmd += " cf "
iface_names = map(lambda x: x.name, ifaces)
cmd += ",".join(iface_names)
cmd += " hash MD5"
cmd += " log /var/log/nrlsmf.log"
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
return cfg
class NrlOlsr(NrlService):
"""
Optimized Link State Routing protocol for MANET networks.
"""
name: str = "OLSR"
executables: tuple[str, ...] = ("nrlolsrd",)
startup: tuple[str, ...] = ("nrlolsrd",)
shutdown: tuple[str, ...] = ("killall nrlolsrd",)
validate: tuple[str, ...] = ("pidof nrlolsrd",)
@classmethod
def get_startup(cls, node: CoreNode) -> tuple[str, ...]:
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls.startup[0]
# are multiple interfaces supported? No.
ifaces = node.get_ifaces()
if len(ifaces) > 0:
iface = ifaces[0]
cmd += f" -i {iface.name}"
cmd += " -l /var/log/nrlolsrd.log"
cmd += f" -rpipe {node.name}_olsr"
servicenames = map(lambda x: x.name, node.services)
if "SMF" in servicenames and "NHDP" not in servicenames:
cmd += " -flooding s-mpr"
cmd += f" -smfClient {node.name}_smf"
if "zebra" in servicenames:
cmd += " -z"
return (cmd,)
class NrlOlsrv2(NrlService):
"""
Optimized Link State Routing protocol version 2 for MANET networks.
"""
name: str = "OLSRv2"
executables: tuple[str, ...] = ("nrlolsrv2",)
startup: tuple[str, ...] = ("nrlolsrv2",)
shutdown: tuple[str, ...] = ("killall nrlolsrv2",)
validate: tuple[str, ...] = ("pidof nrlolsrv2",)
@classmethod
def get_startup(cls, node: CoreNode) -> tuple[str, ...]:
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls.startup[0]
cmd += " -l /var/log/nrlolsrv2.log"
cmd += f" -rpipe {node.name}_olsrv2"
servicenames = map(lambda x: x.name, node.services)
if "SMF" in servicenames:
cmd += " -flooding ecds"
cmd += f" -smfClient {node.name}_smf"
cmd += " -p olsr"
ifaces = node.get_ifaces(control=False)
if len(ifaces) > 0:
iface_names = map(lambda x: x.name, ifaces)
cmd += " -i "
cmd += " -i ".join(iface_names)
return (cmd,)
class OlsrOrg(NrlService):
"""
Optimized Link State Routing protocol from olsr.org for MANET networks.
"""
name: str = "OLSRORG"
executables: tuple[str, ...] = ("olsrd",)
configs: tuple[str, ...] = ("/etc/olsrd/olsrd.conf",)
dirs: tuple[str, ...] = ("/etc/olsrd",)
startup: tuple[str, ...] = ("olsrd",)
shutdown: tuple[str, ...] = ("killall olsrd",)
validate: tuple[str, ...] = ("pidof olsrd",)
@classmethod
def get_startup(cls, node: CoreNode) -> tuple[str, ...]:
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls.startup[0]
ifaces = node.get_ifaces(control=False)
if len(ifaces) > 0:
iface_names = map(lambda x: x.name, ifaces)
cmd += " -i "
cmd += " -i ".join(iface_names)
return (cmd,)
@classmethod
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a default olsrd config file to use the broadcast address of
255.255.255.255.
"""
cfg = """\
#
# OLSR.org routing daemon config file
# This file contains the usual options for an ETX based
# stationary network without fisheye
# (for other options see olsrd.conf.default.full)
#
# Lines starting with a # are discarded
#
#### ATTENTION for IPv6 users ####
# Because of limitations in the parser IPv6 addresses must NOT
# begin with a ":", so please add a "0" as a prefix.
###########################
### Basic configuration ###
###########################
# keep this settings at the beginning of your first configuration file
# Debug level (0-9)
# If set to 0 the daemon runs in the background, unless "NoFork" is set to true
# (Default is 1)
# DebugLevel 1
# IP version to use (4 or 6)
# (Default is 4)
# IpVersion 4
#################################
### OLSRd agent configuration ###
#################################
# this parameters control the settings of the routing agent which are not
# related to the OLSR protocol and it's extensions
# FIBMetric controls the metric value of the host-routes OLSRd sets.
# - "flat" means that the metric value is always 2. This is the preferred value
# because it helps the linux kernel routing to clean up older routes
# - "correct" use the hopcount as the metric value.
# - "approx" use the hopcount as the metric value too, but does only update the
# hopcount if the nexthop changes too
# (Default is "flat")
# FIBMetric "flat"
#######################################
### Linux specific OLSRd extensions ###
#######################################
# these parameters are only working on linux at the moment
# SrcIpRoutes tells OLSRd to set the Src flag of host routes to the originator-ip
# of the node. In addition to this an additional localhost device is created
# to make sure the returning traffic can be received.
# (Default is "no")
# SrcIpRoutes no
# Specify the proto tag to be used for routes olsr inserts into kernel
# currently only implemented for linux
# valid values under linux are 1 .. 254
# 1 gets remapped by olsrd to 0 UNSPECIFIED (1 is reserved for ICMP redirects)
# 2 KERNEL routes (not very wise to use)
# 3 BOOT (should in fact not be used by routing daemons)
# 4 STATIC
# 8 .. 15 various routing daemons (gated, zebra, bird, & co)
# (defaults to 0 which gets replaced by an OS-specific default value
# under linux 3 (BOOT) (for backward compatibility)
# RtProto 0
# Activates (in IPv6 mode) the automatic use of NIIT
# (see README-Olsr-Extensions)
# (default is "yes")
# UseNiit yes
# Activates the smartgateway ipip tunnel feature.
# See README-Olsr-Extensions for a description of smartgateways.
# (default is "no")
# SmartGateway no
# Signals that the server tunnel must always be removed on shutdown,
# irrespective of the interface up/down state during startup.
# (default is "no")
# SmartGatewayAlwaysRemoveServerTunnel no
# Determines the maximum number of gateways that can be in use at any given
# time. This setting is used to mitigate the effects of breaking connections
# (due to the selection of a new gateway) on a dynamic network.
# (default is 1)
# SmartGatewayUseCount 1
# Determines the take-down percentage for a non-current smart gateway tunnel.
# If the cost of the current smart gateway tunnel is less than this percentage
# of the cost of the non-current smart gateway tunnel, then the non-current smart
# gateway tunnel is taken down because it is then presumed to be 'too expensive'.
# This setting is only relevant when SmartGatewayUseCount is larger than 1;
# a value of 0 will result in the tunnels not being taken down proactively.
# (default is 0)
# SmartGatewayTakeDownPercentage 0
# Determines the policy routing script that is executed during startup and
# shutdown of olsrd. The script is only executed when SmartGatewayUseCount
# is set to a value larger than 1. The script must setup policy routing
# rules such that multi-gateway mode works. A sample script is included.
# (default is not set)
# SmartGatewayPolicyRoutingScript ""
# Determines the egress interfaces that are part of the multi-gateway setup and
# therefore only relevant when SmartGatewayUseCount is larger than 1 (in which
# case it must be explicitly set).
# (default is not set)
# SmartGatewayEgressInterfaces ""
# Determines the routing tables offset for multi-gateway policy routing tables
# See the policy routing script for an explanation.
# (default is 90)
# SmartGatewayTablesOffset 90
# Determines the policy routing rules offset for multi-gateway policy routing
# rules. See the policy routing script for an explanation.
# (default is 0, which indicates that the rules and tables should be aligned and
# puts this value at SmartGatewayTablesOffset - # egress interfaces -
# # olsr interfaces)
# SmartGatewayRulesOffset 87
# Allows the selection of a smartgateway with NAT (only for IPv4)
# (default is "yes")
# SmartGatewayAllowNAT yes
# Determines the period (in milliseconds) on which a new smart gateway
# selection is performed.
# (default is 10000 milliseconds)
# SmartGatewayPeriod 10000
# Determines the number of times the link state database must be stable
# before a new smart gateway is selected.
# (default is 6)
# SmartGatewayStableCount 6
# When another gateway than the current one has a cost of less than the cost
# of the current gateway multiplied by SmartGatewayThreshold then the smart
# gateway is switched to the other gateway. The unit is percentage.
# (defaults to 0)
# SmartGatewayThreshold 0
# The weighing factor for the gateway uplink bandwidth (exit link, uplink).
# See README-Olsr-Extensions for a description of smart gateways.
# (default is 1)
# SmartGatewayWeightExitLinkUp 1
# The weighing factor for the gateway downlink bandwidth (exit link, downlink).
# See README-Olsr-Extensions for a description of smart gateways.
# (default is 1)
# SmartGatewayWeightExitLinkDown 1
# The weighing factor for the ETX costs.
# See README-Olsr-Extensions for a description of smart gateways.
# (default is 1)
# SmartGatewayWeightEtx 1
# The divider for the ETX costs.
# See README-Olsr-Extensions for a description of smart gateways.
# (default is 0)
# SmartGatewayDividerEtx 0
# Defines what kind of Uplink this node will publish as a
# smartgateway. The existence of the uplink is detected by
# a route to 0.0.0.0/0, ::ffff:0:0/96 and/or 2000::/3.
# possible values are "none", "ipv4", "ipv6", "both"
# (default is "both")
# SmartGatewayUplink "both"
# Specifies if the local ipv4 uplink use NAT
# (default is "yes")
# SmartGatewayUplinkNAT yes
# Specifies the speed of the uplink in kilobit/s.
# First parameter is upstream, second parameter is downstream
# (default is 128/1024)
# SmartGatewaySpeed 128 1024
# Specifies the EXTERNAL ipv6 prefix of the uplink. A prefix
# length of more than 64 is not allowed.
# (default is 0::/0
# SmartGatewayPrefix 0::/0
##############################
### OLSR protocol settings ###
##############################
# HNA (Host network association) allows the OLSR to announce
# additional IPs or IP subnets to the net that are reachable
# through this node.
# Syntax for HNA4 is "network-address network-mask"
# Syntax for HNA6 is "network-address prefix-length"
# (default is no HNA)
Hna4
{
# Internet gateway
# 0.0.0.0 0.0.0.0
# specific small networks reachable through this node
# 15.15.0.0 255.255.255.0
}
Hna6
{
# Internet gateway
# 0:: 0
# specific small networks reachable through this node
# fec0:2200:106:0:0:0:0:0 48
}
################################
### OLSR protocol extensions ###
################################
# Link quality algorithm (only for lq level 2)
# (see README-Olsr-Extensions)
# - "etx_float", a floating point ETX with exponential aging
# - "etx_fpm", same as ext_float, but with integer arithmetic
# - "etx_ff" (ETX freifunk), an etx variant which use all OLSR
# traffic (instead of only hellos) for ETX calculation
# - "etx_ffeth", an incompatible variant of etx_ff that allows
# ethernet links with ETX 0.1.
# (defaults to "etx_ff")
# LinkQualityAlgorithm "etx_ff"
# Fisheye mechanism for TCs (0 meansoff, 1 means on)
# (default is 1)
LinkQualityFishEye 0
#####################################
### Example plugin configurations ###
#####################################
# Olsrd plugins to load
# This must be the absolute path to the file
# or the loader will use the following scheme:
# - Try the paths in the LD_LIBRARY_PATH
# environment variable.
# - The list of libraries cached in /etc/ld.so.cache
# - /lib, followed by /usr/lib
#
# the examples in this list are for linux, so check if the plugin is
# available if you use windows.
# each plugin should have a README file in it's lib subfolder
# LoadPlugin "olsrd_txtinfo.dll"
#LoadPlugin "olsrd_txtinfo.so.0.1"
#{
# the default port is 2006 but you can change it like this:
#PlParam "port" "8080"
# You can set a "accept" single address to allow to connect to
# txtinfo. If no address is specified, then localhost (127.0.0.1)
# is allowed by default. txtinfo will only use the first "accept"
# parameter specified and will ignore the rest.
# to allow a specific host:
#PlParam "accept" "172.29.44.23"
# if you set it to 0.0.0.0, it will accept all connections
#PlParam "accept" "0.0.0.0"
#}
#############################################
### OLSRD default interface configuration ###
#############################################
# the default interface section can have the same values as the following
# interface configuration. It will allow you so set common options for all
# interfaces.
InterfaceDefaults {
Ip4Broadcast 255.255.255.255
}
######################################
### OLSRd Interfaces configuration ###
######################################
# multiple interfaces can be specified for a single configuration block
# multiple configuration blocks can be specified
# WARNING, don't forget to insert your interface names here !
#Interface "<OLSRd-Interface1>" "<OLSRd-Interface2>"
#{
# Interface Mode is used to prevent unnecessary
# packet forwarding on switched ethernet interfaces
# valid Modes are "mesh" and "ether"
# (default is "mesh")
# Mode "mesh"
#}
"""
return cfg
class MgenActor(NrlService):
"""
ZpcMgenActor.
"""
# a unique name is required, without spaces
name: str = "MgenActor"
group: str = "ProtoSvc"
executables: tuple[str, ...] = ("mgen",)
configs: tuple[str, ...] = ("start_mgen_actor.sh",)
startup: tuple[str, ...] = ("bash start_mgen_actor.sh",)
validate: tuple[str, ...] = ("pidof mgen",)
shutdown: tuple[str, ...] = ("killall mgen",)
@classmethod
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a startup script for MgenActor. Because mgenActor does not
daemonize, it can cause problems in some situations when launched
directly using vcmd.
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by nrl.py:MgenActor.generateconfig()\n"
comments = ""
cmd = f"mgenBasicActor.py -n {node.name} -a 0.0.0.0"
ifaces = node.get_ifaces(control=False)
if len(ifaces) == 0:
return ""
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
return cfg