daemon: added type hinting throughout all services and made small tweaks/fixes that were ran across
This commit is contained in:
parent
250bc6e1f5
commit
cd74a44558
11 changed files with 560 additions and 636 deletions
|
@ -7,7 +7,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type
|
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, Union
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ if TYPE_CHECKING:
|
||||||
from core.configservice.base import ConfigService
|
from core.configservice.base import ConfigService
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
CoreServices = List[CoreService]
|
CoreServices = List[Union[CoreService, Type[CoreService]]]
|
||||||
ConfigServiceType = Type[ConfigService]
|
ConfigServiceType = Type[ConfigService]
|
||||||
|
|
||||||
_DEFAULT_MTU = 1500
|
_DEFAULT_MTU = 1500
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
"""
|
"""
|
||||||
bird.py: defines routing services provided by the BIRD Internet Routing Daemon.
|
bird.py: defines routing services provided by the BIRD Internet Routing Daemon.
|
||||||
"""
|
"""
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,27 +14,27 @@ class Bird(CoreService):
|
||||||
Bird router support
|
Bird router support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "bird"
|
name: str = "bird"
|
||||||
executables = ("bird",)
|
group: str = "BIRD"
|
||||||
group = "BIRD"
|
executables: Tuple[str, ...] = ("bird",)
|
||||||
dirs = ("/etc/bird",)
|
dirs: Tuple[str, ...] = ("/etc/bird",)
|
||||||
configs = ("/etc/bird/bird.conf",)
|
configs: Tuple[str, ...] = ("/etc/bird/bird.conf",)
|
||||||
startup = ("bird -c %s" % (configs[0]),)
|
startup: Tuple[str, ...] = ("bird -c %s" % (configs[0]),)
|
||||||
shutdown = ("killall bird",)
|
shutdown: Tuple[str, ...] = ("killall bird",)
|
||||||
validate = ("pidof bird",)
|
validate: Tuple[str, ...] = ("pidof bird",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the bird.conf file contents.
|
Return the bird.conf file contents.
|
||||||
"""
|
"""
|
||||||
if filename == cls.configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateBirdConf(node)
|
return cls.generate_bird_config(node)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routerid(node):
|
def router_id(node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
|
@ -40,15 +43,13 @@ class Bird(CoreService):
|
||||||
a = a.split("/")[0]
|
a = a.split("/")[0]
|
||||||
if netaddr.valid_ipv4(a):
|
if netaddr.valid_ipv4(a):
|
||||||
return a
|
return a
|
||||||
# raise ValueError, "no IPv4 address found for router ID"
|
|
||||||
return "0.0.0.0"
|
return "0.0.0.0"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateBirdConf(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text. Other services that depend on bird
|
Returns configuration file text. Other services that depend on bird
|
||||||
will have generatebirdifcconfig() and generatebirdconfig()
|
will have hooks that are invoked here.
|
||||||
hooks that are invoked here.
|
|
||||||
"""
|
"""
|
||||||
cfg = """\
|
cfg = """\
|
||||||
/* Main configuration file for BIRD. This is ony a template,
|
/* Main configuration file for BIRD. This is ony a template,
|
||||||
|
@ -75,15 +76,16 @@ protocol device {
|
||||||
|
|
||||||
""" % (
|
""" % (
|
||||||
cls.name,
|
cls.name,
|
||||||
cls.routerid(node),
|
cls.router_id(node),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate protocol specific configurations
|
# generate protocol specific configurations
|
||||||
for s in node.services:
|
for s in node.services:
|
||||||
if cls.name not in s.dependencies:
|
if cls.name not in s.dependencies:
|
||||||
continue
|
continue
|
||||||
|
if not (isinstance(s, BirdService) or issubclass(s, BirdService)):
|
||||||
|
continue
|
||||||
cfg += s.generate_bird_config(node)
|
cfg += s.generate_bird_config(node)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,32 +95,26 @@ class BirdService(CoreService):
|
||||||
common to Bird's routing daemons.
|
common to Bird's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
executables = ("bird",)
|
group: str = "BIRD"
|
||||||
group = "BIRD"
|
executables: Tuple[str, ...] = ("bird",)
|
||||||
dependencies = ("bird",)
|
dependencies: Tuple[str, ...] = ("bird",)
|
||||||
dirs = ()
|
meta: str = "The config file for this service can be found in the bird service."
|
||||||
configs = ()
|
|
||||||
startup = ()
|
|
||||||
shutdown = ()
|
|
||||||
meta = "The config file for this service can be found in the bird service."
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_iface_config(cls, node):
|
def generate_bird_iface_config(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Use only bare interfaces descriptions in generated protocol
|
Use only bare interfaces descriptions in generated protocol
|
||||||
configurations. This has the slight advantage of being the same
|
configurations. This has the slight advantage of being the same
|
||||||
everywhere.
|
everywhere.
|
||||||
"""
|
"""
|
||||||
cfg = ""
|
cfg = ""
|
||||||
|
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
cfg += ' interface "%s";\n' % iface.name
|
cfg += ' interface "%s";\n' % iface.name
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,11 +123,11 @@ class BirdBgp(BirdService):
|
||||||
BGP BIRD Service (configuration generation)
|
BGP BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BIRD_BGP"
|
name: str = "BIRD_BGP"
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
return """
|
return """
|
||||||
/* This is a sample config that should be customized with appropriate AS numbers
|
/* This is a sample config that should be customized with appropriate AS numbers
|
||||||
* and peers; add one section like this for each neighbor */
|
* and peers; add one section like this for each neighbor */
|
||||||
|
@ -158,10 +154,10 @@ class BirdOspf(BirdService):
|
||||||
OSPF BIRD Service (configuration generation)
|
OSPF BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BIRD_OSPFv2"
|
name: str = "BIRD_OSPFv2"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "protocol ospf {\n"
|
cfg = "protocol ospf {\n"
|
||||||
cfg += " export filter {\n"
|
cfg += " export filter {\n"
|
||||||
cfg += " if source = RTS_BGP then {\n"
|
cfg += " if source = RTS_BGP then {\n"
|
||||||
|
@ -174,7 +170,6 @@ class BirdOspf(BirdService):
|
||||||
cfg += cls.generate_bird_iface_config(node)
|
cfg += cls.generate_bird_iface_config(node)
|
||||||
cfg += " };\n"
|
cfg += " };\n"
|
||||||
cfg += "}\n\n"
|
cfg += "}\n\n"
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,12 +178,11 @@ class BirdRadv(BirdService):
|
||||||
RADV BIRD Service (configuration generation)
|
RADV BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BIRD_RADV"
|
name: str = "BIRD_RADV"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "/* This is a sample config that must be customized */\n"
|
cfg = "/* This is a sample config that must be customized */\n"
|
||||||
|
|
||||||
cfg += "protocol radv {\n"
|
cfg += "protocol radv {\n"
|
||||||
cfg += " # auto configuration on all interfaces\n"
|
cfg += " # auto configuration on all interfaces\n"
|
||||||
cfg += cls.generate_bird_iface_config(node)
|
cfg += cls.generate_bird_iface_config(node)
|
||||||
|
@ -202,7 +196,6 @@ class BirdRadv(BirdService):
|
||||||
cfg += "# ns 2001:0DB8:1234::12;\n"
|
cfg += "# ns 2001:0DB8:1234::12;\n"
|
||||||
cfg += " };\n"
|
cfg += " };\n"
|
||||||
cfg += "}\n\n"
|
cfg += "}\n\n"
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,10 +204,10 @@ class BirdRip(BirdService):
|
||||||
RIP BIRD Service (configuration generation)
|
RIP BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BIRD_RIP"
|
name: str = "BIRD_RIP"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "protocol rip {\n"
|
cfg = "protocol rip {\n"
|
||||||
cfg += " period 10;\n"
|
cfg += " period 10;\n"
|
||||||
cfg += " garbage time 60;\n"
|
cfg += " garbage time 60;\n"
|
||||||
|
@ -224,7 +217,6 @@ class BirdRip(BirdService):
|
||||||
cfg += " import all;\n"
|
cfg += " import all;\n"
|
||||||
cfg += " export all;\n"
|
cfg += " export all;\n"
|
||||||
cfg += "}\n\n"
|
cfg += "}\n\n"
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,11 +225,11 @@ class BirdStatic(BirdService):
|
||||||
Static Bird Service (configuration generation)
|
Static Bird Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BIRD_static"
|
name: str = "BIRD_static"
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_bird_config(cls, node):
|
def generate_bird_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "/* This is a sample config that must be customized */\n"
|
cfg = "/* This is a sample config that must be customized */\n"
|
||||||
cfg += "protocol static {\n"
|
cfg += "protocol static {\n"
|
||||||
cfg += "# route 0.0.0.0/0 via 198.51.100.130; # Default route. Do NOT advertise on BGP !\n"
|
cfg += "# route 0.0.0.0/0 via 198.51.100.130; # Default route. Do NOT advertise on BGP !\n"
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.errors import CoreError
|
from core.errors import CoreError
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
from core.xml import emanexml
|
from core.xml import emanexml
|
||||||
|
|
||||||
|
|
||||||
class EmaneTransportService(CoreService):
|
class EmaneTransportService(CoreService):
|
||||||
name = "transportd"
|
name: str = "transportd"
|
||||||
executables = ("emanetransportd", "emanegentransportxml")
|
group: str = "EMANE"
|
||||||
group = "EMANE"
|
executables: Tuple[str, ...] = ("emanetransportd", "emanegentransportxml")
|
||||||
dependencies = ()
|
dependencies: Tuple[str, ...] = ()
|
||||||
dirs = ()
|
dirs: Tuple[str, ...] = ()
|
||||||
configs = ("emanetransport.sh",)
|
configs: Tuple[str, ...] = ("emanetransport.sh",)
|
||||||
startup = ("sh %s" % configs[0],)
|
startup: Tuple[str, ...] = ("sh %s" % configs[0],)
|
||||||
validate = ("pidof %s" % executables[0],)
|
validate: Tuple[str, ...] = ("pidof %s" % executables[0],)
|
||||||
validation_timer = 0.5
|
validation_timer: float = 0.5
|
||||||
shutdown = ("killall %s" % executables[0],)
|
shutdown: Tuple[str, ...] = ("killall %s" % executables[0],)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
if filename == cls.configs[0]:
|
if filename == cls.configs[0]:
|
||||||
transport_commands = []
|
transport_commands = []
|
||||||
for iface in node.get_ifaces():
|
for iface in node.get_ifaces():
|
||||||
|
|
|
@ -2,60 +2,63 @@
|
||||||
frr.py: defines routing services provided by FRRouting.
|
frr.py: defines routing services provided by FRRouting.
|
||||||
Assumes installation of FRR via https://deb.frrouting.org/
|
Assumes installation of FRR via https://deb.frrouting.org/
|
||||||
"""
|
"""
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
|
from core.nodes.interface import CoreInterface
|
||||||
from core.nodes.network import PtpNet, WlanNode
|
from core.nodes.network import PtpNet, WlanNode
|
||||||
from core.nodes.physical import Rj45Node
|
from core.nodes.physical import Rj45Node
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
class FRRZebra(CoreService):
|
class FRRZebra(CoreService):
|
||||||
name = "FRRzebra"
|
name: str = "FRRzebra"
|
||||||
group = "FRR"
|
group: str = "FRR"
|
||||||
dirs = ("/usr/local/etc/frr", "/var/run/frr", "/var/log/frr")
|
dirs: Tuple[str, ...] = ("/usr/local/etc/frr", "/var/run/frr", "/var/log/frr")
|
||||||
configs = (
|
configs: Tuple[str, ...] = (
|
||||||
"/usr/local/etc/frr/frr.conf",
|
"/usr/local/etc/frr/frr.conf",
|
||||||
"frrboot.sh",
|
"frrboot.sh",
|
||||||
"/usr/local/etc/frr/vtysh.conf",
|
"/usr/local/etc/frr/vtysh.conf",
|
||||||
"/usr/local/etc/frr/daemons",
|
"/usr/local/etc/frr/daemons",
|
||||||
)
|
)
|
||||||
startup = ("sh frrboot.sh zebra",)
|
startup: Tuple[str, ...] = ("sh frrboot.sh zebra",)
|
||||||
shutdown = ("killall zebra",)
|
shutdown: Tuple[str, ...] = ("killall zebra",)
|
||||||
validate = ("pidof zebra",)
|
validate: Tuple[str, ...] = ("pidof zebra",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the frr.conf or frrboot.sh file contents.
|
Return the frr.conf or frrboot.sh file contents.
|
||||||
"""
|
"""
|
||||||
if filename == cls.configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateFrrConf(node)
|
return cls.generate_frr_conf(node)
|
||||||
elif filename == cls.configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateFrrBoot(node)
|
return cls.generate_frr_boot(node)
|
||||||
elif filename == cls.configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generateVtyshConf(node)
|
return cls.generate_vtysh_conf(node)
|
||||||
elif filename == cls.configs[3]:
|
elif filename == cls.configs[3]:
|
||||||
return cls.generateFrrDaemons(node)
|
return cls.generate_frr_daemons(node)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"file name (%s) is not a known configuration: %s", filename, cls.configs
|
"file name (%s) is not a known configuration: %s", filename, cls.configs
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateVtyshConf(cls, node):
|
def generate_vtysh_conf(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text.
|
Returns configuration file text.
|
||||||
"""
|
"""
|
||||||
return "service integrated-vtysh-config\n"
|
return "service integrated-vtysh-config\n"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateFrrConf(cls, node):
|
def generate_frr_conf(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text. Other services that depend on zebra
|
Returns configuration file text. Other services that depend on zebra
|
||||||
will have generatefrrifcconfig() and generatefrrconfig()
|
will have hooks that are invoked here.
|
||||||
hooks that are invoked here.
|
|
||||||
"""
|
"""
|
||||||
# we could verify here that filename == frr.conf
|
# we could verify here that filename == frr.conf
|
||||||
cfg = ""
|
cfg = ""
|
||||||
|
@ -108,7 +111,7 @@ class FRRZebra(CoreService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def addrstr(x):
|
def addrstr(x: str) -> str:
|
||||||
"""
|
"""
|
||||||
helper for mapping IP addresses to zebra config statements
|
helper for mapping IP addresses to zebra config statements
|
||||||
"""
|
"""
|
||||||
|
@ -121,7 +124,7 @@ class FRRZebra(CoreService):
|
||||||
raise ValueError("invalid address: %s", x)
|
raise ValueError("invalid address: %s", x)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateFrrBoot(cls, node):
|
def generate_frr_boot(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a shell script used to boot the FRR daemons.
|
Generate a shell script used to boot the FRR daemons.
|
||||||
"""
|
"""
|
||||||
|
@ -244,7 +247,7 @@ bootfrr
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateFrrDaemons(cls, node):
|
def generate_frr_daemons(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text.
|
Returns configuration file text.
|
||||||
"""
|
"""
|
||||||
|
@ -317,20 +320,15 @@ class FrrService(CoreService):
|
||||||
common to FRR's routing daemons.
|
common to FRR's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
group = "FRR"
|
group: str = "FRR"
|
||||||
dependencies = ("FRRzebra",)
|
dependencies: Tuple[str, ...] = ("FRRzebra",)
|
||||||
dirs = ()
|
meta: str = "The config file for this service can be found in the Zebra service."
|
||||||
configs = ()
|
ipv4_routing: bool = False
|
||||||
startup = ()
|
ipv6_routing: bool = False
|
||||||
shutdown = ()
|
|
||||||
meta = "The config file for this service can be found in the Zebra service."
|
|
||||||
|
|
||||||
ipv4_routing = False
|
|
||||||
ipv6_routing = False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routerid(node):
|
def router_id(node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
|
@ -339,11 +337,10 @@ class FrrService(CoreService):
|
||||||
a = a.split("/")[0]
|
a = a.split("/")[0]
|
||||||
if netaddr.valid_ipv4(a):
|
if netaddr.valid_ipv4(a):
|
||||||
return a
|
return a
|
||||||
# raise ValueError, "no IPv4 address found for router ID"
|
|
||||||
return "0.0.0.0"
|
return "0.0.0.0"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def rj45check(iface):
|
def rj45check(iface: CoreInterface) -> bool:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected an external RJ45
|
Helper to detect whether interface is connected an external RJ45
|
||||||
link.
|
link.
|
||||||
|
@ -357,15 +354,15 @@ class FrrService(CoreService):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@ -376,14 +373,13 @@ class FRROspfv2(FrrService):
|
||||||
unified frr.conf file.
|
unified frr.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRROSPFv2"
|
name: str = "FRROSPFv2"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ospfd",)
|
||||||
shutdown = ("killall ospfd",)
|
validate: Tuple[str, ...] = ("pidof ospfd",)
|
||||||
validate = ("pidof ospfd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mtucheck(iface):
|
def mtu_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect MTU mismatch and add the appropriate OSPF
|
Helper to detect MTU mismatch and add the appropriate OSPF
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
|
@ -401,7 +397,7 @@ class FRROspfv2(FrrService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ptpcheck(iface):
|
def ptp_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected to a notional
|
Helper to detect whether interface is connected to a notional
|
||||||
point-to-point link.
|
point-to-point link.
|
||||||
|
@ -411,9 +407,9 @@ class FRROspfv2(FrrService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router ospf\n"
|
cfg = "router ospf\n"
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " router-id %s\n" % rtrid
|
cfg += " router-id %s\n" % rtrid
|
||||||
# network 10.0.0.0/24 area 0
|
# network 10.0.0.0/24 area 0
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
|
@ -426,8 +422,8 @@ class FRROspfv2(FrrService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return cls.mtucheck(iface)
|
return cls.mtu_check(iface)
|
||||||
|
|
||||||
|
|
||||||
class FRROspfv3(FrrService):
|
class FRROspfv3(FrrService):
|
||||||
|
@ -437,15 +433,14 @@ class FRROspfv3(FrrService):
|
||||||
unified frr.conf file.
|
unified frr.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRROSPFv3"
|
name: str = "FRROSPFv3"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ospf6d",)
|
||||||
shutdown = ("killall ospf6d",)
|
validate: Tuple[str, ...] = ("pidof ospf6d",)
|
||||||
validate = ("pidof ospf6d",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def minmtu(iface):
|
def min_mtu(iface: CoreInterface) -> int:
|
||||||
"""
|
"""
|
||||||
Helper to discover the minimum MTU of interfaces linked with the
|
Helper to discover the minimum MTU of interfaces linked with the
|
||||||
given interface.
|
given interface.
|
||||||
|
@ -459,20 +454,20 @@ class FRROspfv3(FrrService):
|
||||||
return mtu
|
return mtu
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def mtucheck(cls, iface):
|
def mtu_check(cls, iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect MTU mismatch and add the appropriate OSPFv3
|
Helper to detect MTU mismatch and add the appropriate OSPFv3
|
||||||
ifmtu command. This is needed when e.g. a node is linked via a
|
ifmtu command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
minmtu = cls.minmtu(iface)
|
minmtu = cls.min_mtu(iface)
|
||||||
if minmtu < iface.mtu:
|
if minmtu < iface.mtu:
|
||||||
return " ipv6 ospf6 ifmtu %d\n" % minmtu
|
return " ipv6 ospf6 ifmtu %d\n" % minmtu
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ptpcheck(iface):
|
def ptp_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected to a notional
|
Helper to detect whether interface is connected to a notional
|
||||||
point-to-point link.
|
point-to-point link.
|
||||||
|
@ -482,9 +477,9 @@ class FRROspfv3(FrrService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router ospf6\n"
|
cfg = "router ospf6\n"
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " router-id %s\n" % rtrid
|
cfg += " router-id %s\n" % rtrid
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
cfg += " interface %s area 0.0.0.0\n" % iface.name
|
cfg += " interface %s area 0.0.0.0\n" % iface.name
|
||||||
|
@ -492,14 +487,13 @@ class FRROspfv3(FrrService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return cls.mtucheck(iface)
|
return cls.mtu_check(iface)
|
||||||
# cfg = cls.mtucheck(ifc)
|
# cfg = cls.mtucheck(ifc)
|
||||||
# external RJ45 connections will use default OSPF timers
|
# external RJ45 connections will use default OSPF timers
|
||||||
# if cls.rj45check(ifc):
|
# if cls.rj45check(ifc):
|
||||||
# return cfg
|
# return cfg
|
||||||
# cfg += cls.ptpcheck(ifc)
|
# cfg += cls.ptpcheck(ifc)
|
||||||
|
|
||||||
# return cfg + """\
|
# return cfg + """\
|
||||||
|
|
||||||
|
|
||||||
|
@ -516,21 +510,20 @@ class FRRBgp(FrrService):
|
||||||
having the same AS number.
|
having the same AS number.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRBGP"
|
name: str = "FRRBGP"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall bgpd",)
|
||||||
shutdown = ("killall bgpd",)
|
validate: Tuple[str, ...] = ("pidof bgpd",)
|
||||||
validate = ("pidof bgpd",)
|
custom_needed: bool = True
|
||||||
custom_needed = True
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "!\n! BGP configuration\n!\n"
|
cfg = "!\n! BGP configuration\n!\n"
|
||||||
cfg += "! You should configure the AS number below,\n"
|
cfg += "! You should configure the AS number below,\n"
|
||||||
cfg += "! along with this router's peers.\n!\n"
|
cfg += "! along with this router's peers.\n!\n"
|
||||||
cfg += "router bgp %s\n" % node.id
|
cfg += "router bgp %s\n" % node.id
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " bgp router-id %s\n" % rtrid
|
cfg += " bgp router-id %s\n" % rtrid
|
||||||
cfg += " redistribute connected\n"
|
cfg += " redistribute connected\n"
|
||||||
cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n"
|
cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n"
|
||||||
|
@ -542,14 +535,13 @@ class FRRRip(FrrService):
|
||||||
The RIP service provides IPv4 routing for wired networks.
|
The RIP service provides IPv4 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRRIP"
|
name: str = "FRRRIP"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ripd",)
|
||||||
shutdown = ("killall ripd",)
|
validate: Tuple[str, ...] = ("pidof ripd",)
|
||||||
validate = ("pidof ripd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = """\
|
cfg = """\
|
||||||
router rip
|
router rip
|
||||||
redistribute static
|
redistribute static
|
||||||
|
@ -566,14 +558,13 @@ class FRRRipng(FrrService):
|
||||||
The RIP NG service provides IPv6 routing for wired networks.
|
The RIP NG service provides IPv6 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRRIPNG"
|
name: str = "FRRRIPNG"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ripngd",)
|
||||||
shutdown = ("killall ripngd",)
|
validate: Tuple[str, ...] = ("pidof ripngd",)
|
||||||
validate = ("pidof ripngd",)
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = """\
|
cfg = """\
|
||||||
router ripng
|
router ripng
|
||||||
redistribute static
|
redistribute static
|
||||||
|
@ -591,14 +582,13 @@ class FRRBabel(FrrService):
|
||||||
protocol for IPv6 and IPv4 with fast convergence properties.
|
protocol for IPv6 and IPv4 with fast convergence properties.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRBabel"
|
name: str = "FRRBabel"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall babeld",)
|
||||||
shutdown = ("killall babeld",)
|
validate: Tuple[str, ...] = ("pidof babeld",)
|
||||||
validate = ("pidof babeld",)
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router babel\n"
|
cfg = "router babel\n"
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
cfg += " network %s\n" % iface.name
|
cfg += " network %s\n" % iface.name
|
||||||
|
@ -606,7 +596,7 @@ class FRRBabel(FrrService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
if iface.net and isinstance(iface.net, (EmaneNet, WlanNode)):
|
if iface.net and isinstance(iface.net, (EmaneNet, WlanNode)):
|
||||||
return " babel wireless\n no babel split-horizon\n"
|
return " babel wireless\n no babel split-horizon\n"
|
||||||
else:
|
else:
|
||||||
|
@ -618,14 +608,13 @@ class FRRpimd(FrrService):
|
||||||
PIM multicast routing based on XORP.
|
PIM multicast routing based on XORP.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRpimd"
|
name: str = "FRRpimd"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall pimd",)
|
||||||
shutdown = ("killall pimd",)
|
validate: Tuple[str, ...] = ("pidof pimd",)
|
||||||
validate = ("pidof pimd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
ifname = "eth0"
|
ifname = "eth0"
|
||||||
for iface in node.get_ifaces():
|
for iface in node.get_ifaces():
|
||||||
if iface.name != "lo":
|
if iface.name != "lo":
|
||||||
|
@ -641,7 +630,7 @@ class FRRpimd(FrrService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return " ip mfea\n ip igmp\n ip pim\n"
|
return " ip mfea\n ip igmp\n ip pim\n"
|
||||||
|
|
||||||
|
|
||||||
|
@ -652,15 +641,14 @@ class FRRIsis(FrrService):
|
||||||
unified frr.conf file.
|
unified frr.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FRRISIS"
|
name: str = "FRRISIS"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall isisd",)
|
||||||
shutdown = ("killall isisd",)
|
validate: Tuple[str, ...] = ("pidof isisd",)
|
||||||
validate = ("pidof isisd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ptpcheck(iface):
|
def ptp_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected to a notional
|
Helper to detect whether interface is connected to a notional
|
||||||
point-to-point link.
|
point-to-point link.
|
||||||
|
@ -670,7 +658,7 @@ class FRRIsis(FrrService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_config(cls, node):
|
def generate_frr_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router isis DEFAULT\n"
|
cfg = "router isis DEFAULT\n"
|
||||||
cfg += " net 47.0001.0000.1900.%04x.00\n" % node.id
|
cfg += " net 47.0001.0000.1900.%04x.00\n" % node.id
|
||||||
cfg += " metric-style wide\n"
|
cfg += " metric-style wide\n"
|
||||||
|
@ -679,9 +667,9 @@ class FRRIsis(FrrService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_frr_iface_config(cls, node, iface):
|
def generate_frr_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
cfg = " ip router isis DEFAULT\n"
|
cfg = " ip router isis DEFAULT\n"
|
||||||
cfg += " ipv6 router isis DEFAULT\n"
|
cfg += " ipv6 router isis DEFAULT\n"
|
||||||
cfg += " isis circuit-type level-2-only\n"
|
cfg += " isis circuit-type level-2-only\n"
|
||||||
cfg += cls.ptpcheck(iface)
|
cfg += cls.ptp_check(iface)
|
||||||
return cfg
|
return cfg
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
nrl.py: defines services provided by NRL protolib tools hosted here:
|
nrl.py: defines services provided by NRL protolib tools hosted here:
|
||||||
http://www.nrl.navy.mil/itd/ncs/products
|
http://www.nrl.navy.mil/itd/ncs/products
|
||||||
"""
|
"""
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core import utils
|
from core import utils
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,19 +17,15 @@ class NrlService(CoreService):
|
||||||
common to NRL's routing daemons.
|
common to NRL's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
group = "ProtoSvc"
|
group: str = "ProtoSvc"
|
||||||
dirs = ()
|
|
||||||
configs = ()
|
|
||||||
startup = ()
|
|
||||||
shutdown = ()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def firstipv4prefix(node, prefixlen=24):
|
def firstipv4prefix(node: CoreNode, prefixlen: int = 24) -> str:
|
||||||
"""
|
"""
|
||||||
Similar to QuaggaService.routerid(). Helper to return the first IPv4
|
Similar to QuaggaService.routerid(). Helper to return the first IPv4
|
||||||
prefix of a node, using the supplied prefix length. This ignores the
|
prefix of a node, using the supplied prefix length. This ignores the
|
||||||
|
@ -37,20 +36,19 @@ class NrlService(CoreService):
|
||||||
a = a.split("/")[0]
|
a = a.split("/")[0]
|
||||||
if netaddr.valid_ipv4(a):
|
if netaddr.valid_ipv4(a):
|
||||||
return f"{a}/{prefixlen}"
|
return f"{a}/{prefixlen}"
|
||||||
# raise ValueError, "no IPv4 address found"
|
|
||||||
return "0.0.0.0/%s" % prefixlen
|
return "0.0.0.0/%s" % prefixlen
|
||||||
|
|
||||||
|
|
||||||
class MgenSinkService(NrlService):
|
class MgenSinkService(NrlService):
|
||||||
name = "MGEN_Sink"
|
name: str = "MGEN_Sink"
|
||||||
executables = ("mgen",)
|
executables: Tuple[str, ...] = ("mgen",)
|
||||||
configs = ("sink.mgen",)
|
configs: Tuple[str, ...] = ("sink.mgen",)
|
||||||
startup = ("mgen input sink.mgen",)
|
startup: Tuple[str, ...] = ("mgen input sink.mgen",)
|
||||||
validate = ("pidof mgen",)
|
validate: Tuple[str, ...] = ("pidof mgen",)
|
||||||
shutdown = ("killall mgen",)
|
shutdown: Tuple[str, ...] = ("killall mgen",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
cfg = "0.0 LISTEN UDP 5000\n"
|
cfg = "0.0 LISTEN UDP 5000\n"
|
||||||
for iface in node.get_ifaces():
|
for iface in node.get_ifaces():
|
||||||
name = utils.sysctl_devname(iface.name)
|
name = utils.sysctl_devname(iface.name)
|
||||||
|
@ -58,7 +56,7 @@ class MgenSinkService(NrlService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_startup(cls, node):
|
def get_startup(cls, node: CoreNode) -> Tuple[str, ...]:
|
||||||
cmd = cls.startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " output /tmp/mgen_%s.log" % node.name
|
cmd += " output /tmp/mgen_%s.log" % node.name
|
||||||
return (cmd,)
|
return (cmd,)
|
||||||
|
@ -69,32 +67,29 @@ class NrlNhdp(NrlService):
|
||||||
NeighborHood Discovery Protocol for MANET networks.
|
NeighborHood Discovery Protocol for MANET networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "NHDP"
|
name: str = "NHDP"
|
||||||
executables = ("nrlnhdp",)
|
executables: Tuple[str, ...] = ("nrlnhdp",)
|
||||||
startup = ("nrlnhdp",)
|
startup: Tuple[str, ...] = ("nrlnhdp",)
|
||||||
shutdown = ("killall nrlnhdp",)
|
shutdown: Tuple[str, ...] = ("killall nrlnhdp",)
|
||||||
validate = ("pidof nrlnhdp",)
|
validate: Tuple[str, ...] = ("pidof nrlnhdp",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_startup(cls, node):
|
def get_startup(cls, node: CoreNode) -> Tuple[str, ...]:
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls.startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " -l /var/log/nrlnhdp.log"
|
cmd += " -l /var/log/nrlnhdp.log"
|
||||||
cmd += " -rpipe %s_nhdp" % node.name
|
cmd += " -rpipe %s_nhdp" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x.name, node.services)
|
servicenames = map(lambda x: x.name, node.services)
|
||||||
if "SMF" in servicenames:
|
if "SMF" in servicenames:
|
||||||
cmd += " -flooding ecds"
|
cmd += " -flooding ecds"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
|
|
||||||
ifaces = node.get_ifaces(control=False)
|
ifaces = node.get_ifaces(control=False)
|
||||||
if len(ifaces) > 0:
|
if len(ifaces) > 0:
|
||||||
iface_names = map(lambda x: x.name, ifaces)
|
iface_names = map(lambda x: x.name, ifaces)
|
||||||
cmd += " -i "
|
cmd += " -i "
|
||||||
cmd += " -i ".join(iface_names)
|
cmd += " -i ".join(iface_names)
|
||||||
|
|
||||||
return (cmd,)
|
return (cmd,)
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,15 +98,15 @@ class NrlSmf(NrlService):
|
||||||
Simplified Multicast Forwarding for MANET networks.
|
Simplified Multicast Forwarding for MANET networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "SMF"
|
name: str = "SMF"
|
||||||
executables = ("nrlsmf",)
|
executables: Tuple[str, ...] = ("nrlsmf",)
|
||||||
startup = ("sh startsmf.sh",)
|
startup: Tuple[str, ...] = ("sh startsmf.sh",)
|
||||||
shutdown = ("killall nrlsmf",)
|
shutdown: Tuple[str, ...] = ("killall nrlsmf",)
|
||||||
validate = ("pidof nrlsmf",)
|
validate: Tuple[str, ...] = ("pidof nrlsmf",)
|
||||||
configs = ("startsmf.sh",)
|
configs: Tuple[str, ...] = ("startsmf.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a startup script for SMF. Because nrlsmf does not
|
Generate a startup script for SMF. Because nrlsmf does not
|
||||||
daemonize, it can cause problems in some situations when launched
|
daemonize, it can cause problems in some situations when launched
|
||||||
|
@ -146,7 +141,6 @@ class NrlSmf(NrlService):
|
||||||
|
|
||||||
cmd += " hash MD5"
|
cmd += " hash MD5"
|
||||||
cmd += " log /var/log/nrlsmf.log"
|
cmd += " log /var/log/nrlsmf.log"
|
||||||
|
|
||||||
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
|
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
@ -156,14 +150,14 @@ class NrlOlsr(NrlService):
|
||||||
Optimized Link State Routing protocol for MANET networks.
|
Optimized Link State Routing protocol for MANET networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OLSR"
|
name: str = "OLSR"
|
||||||
executables = ("nrlolsrd",)
|
executables: Tuple[str, ...] = ("nrlolsrd",)
|
||||||
startup = ("nrlolsrd",)
|
startup: Tuple[str, ...] = ("nrlolsrd",)
|
||||||
shutdown = ("killall nrlolsrd",)
|
shutdown: Tuple[str, ...] = ("killall nrlolsrd",)
|
||||||
validate = ("pidof nrlolsrd",)
|
validate: Tuple[str, ...] = ("pidof nrlolsrd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_startup(cls, node):
|
def get_startup(cls, node: CoreNode) -> Tuple[str, ...]:
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
|
@ -175,14 +169,12 @@ class NrlOlsr(NrlService):
|
||||||
cmd += " -i %s" % iface.name
|
cmd += " -i %s" % iface.name
|
||||||
cmd += " -l /var/log/nrlolsrd.log"
|
cmd += " -l /var/log/nrlolsrd.log"
|
||||||
cmd += " -rpipe %s_olsr" % node.name
|
cmd += " -rpipe %s_olsr" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x.name, node.services)
|
servicenames = map(lambda x: x.name, node.services)
|
||||||
if "SMF" in servicenames and "NHDP" not in servicenames:
|
if "SMF" in servicenames and "NHDP" not in servicenames:
|
||||||
cmd += " -flooding s-mpr"
|
cmd += " -flooding s-mpr"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
if "zebra" in servicenames:
|
if "zebra" in servicenames:
|
||||||
cmd += " -z"
|
cmd += " -z"
|
||||||
|
|
||||||
return (cmd,)
|
return (cmd,)
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,34 +183,30 @@ class NrlOlsrv2(NrlService):
|
||||||
Optimized Link State Routing protocol version 2 for MANET networks.
|
Optimized Link State Routing protocol version 2 for MANET networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OLSRv2"
|
name: str = "OLSRv2"
|
||||||
executables = ("nrlolsrv2",)
|
executables: Tuple[str, ...] = ("nrlolsrv2",)
|
||||||
startup = ("nrlolsrv2",)
|
startup: Tuple[str, ...] = ("nrlolsrv2",)
|
||||||
shutdown = ("killall nrlolsrv2",)
|
shutdown: Tuple[str, ...] = ("killall nrlolsrv2",)
|
||||||
validate = ("pidof nrlolsrv2",)
|
validate: Tuple[str, ...] = ("pidof nrlolsrv2",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_startup(cls, node):
|
def get_startup(cls, node: CoreNode) -> Tuple[str, ...]:
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls.startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " -l /var/log/nrlolsrv2.log"
|
cmd += " -l /var/log/nrlolsrv2.log"
|
||||||
cmd += " -rpipe %s_olsrv2" % node.name
|
cmd += " -rpipe %s_olsrv2" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x.name, node.services)
|
servicenames = map(lambda x: x.name, node.services)
|
||||||
if "SMF" in servicenames:
|
if "SMF" in servicenames:
|
||||||
cmd += " -flooding ecds"
|
cmd += " -flooding ecds"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
|
|
||||||
cmd += " -p olsr"
|
cmd += " -p olsr"
|
||||||
|
|
||||||
ifaces = node.get_ifaces(control=False)
|
ifaces = node.get_ifaces(control=False)
|
||||||
if len(ifaces) > 0:
|
if len(ifaces) > 0:
|
||||||
iface_names = map(lambda x: x.name, ifaces)
|
iface_names = map(lambda x: x.name, ifaces)
|
||||||
cmd += " -i "
|
cmd += " -i "
|
||||||
cmd += " -i ".join(iface_names)
|
cmd += " -i ".join(iface_names)
|
||||||
|
|
||||||
return (cmd,)
|
return (cmd,)
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,16 +215,16 @@ class OlsrOrg(NrlService):
|
||||||
Optimized Link State Routing protocol from olsr.org for MANET networks.
|
Optimized Link State Routing protocol from olsr.org for MANET networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OLSRORG"
|
name: str = "OLSRORG"
|
||||||
executables = ("olsrd",)
|
executables: Tuple[str, ...] = ("olsrd",)
|
||||||
configs = ("/etc/olsrd/olsrd.conf",)
|
configs: Tuple[str, ...] = ("/etc/olsrd/olsrd.conf",)
|
||||||
dirs = ("/etc/olsrd",)
|
dirs: Tuple[str, ...] = ("/etc/olsrd",)
|
||||||
startup = ("olsrd",)
|
startup: Tuple[str, ...] = ("olsrd",)
|
||||||
shutdown = ("killall olsrd",)
|
shutdown: Tuple[str, ...] = ("killall olsrd",)
|
||||||
validate = ("pidof olsrd",)
|
validate: Tuple[str, ...] = ("pidof olsrd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_startup(cls, node):
|
def get_startup(cls, node: CoreNode) -> Tuple[str, ...]:
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
|
@ -246,13 +234,13 @@ class OlsrOrg(NrlService):
|
||||||
iface_names = map(lambda x: x.name, ifaces)
|
iface_names = map(lambda x: x.name, ifaces)
|
||||||
cmd += " -i "
|
cmd += " -i "
|
||||||
cmd += " -i ".join(iface_names)
|
cmd += " -i ".join(iface_names)
|
||||||
|
|
||||||
return (cmd,)
|
return (cmd,)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
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.
|
Generate a default olsrd config file to use the broadcast address of
|
||||||
|
255.255.255.255.
|
||||||
"""
|
"""
|
||||||
cfg = """\
|
cfg = """\
|
||||||
#
|
#
|
||||||
|
@ -577,24 +565,16 @@ class MgenActor(NrlService):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# a unique name is required, without spaces
|
# a unique name is required, without spaces
|
||||||
name = "MgenActor"
|
name: str = "MgenActor"
|
||||||
executables = ("mgen",)
|
group: str = "ProtoSvc"
|
||||||
# you can create your own group here
|
executables: Tuple[str, ...] = ("mgen",)
|
||||||
group = "ProtoSvc"
|
configs: Tuple[str, ...] = ("start_mgen_actor.sh",)
|
||||||
# per-node directories
|
startup: Tuple[str, ...] = ("sh start_mgen_actor.sh",)
|
||||||
dirs = ()
|
validate: Tuple[str, ...] = ("pidof mgen",)
|
||||||
# generated files (without a full path this file goes in the node's dir,
|
shutdown: Tuple[str, ...] = ("killall mgen",)
|
||||||
# e.g. /tmp/pycore.12345/n1.conf/)
|
|
||||||
configs = ("start_mgen_actor.sh",)
|
|
||||||
# list of startup commands, also may be generated during startup
|
|
||||||
startup = ("sh start_mgen_actor.sh",)
|
|
||||||
# list of validation commands
|
|
||||||
validate = ("pidof mgen",)
|
|
||||||
# list of shutdown commands
|
|
||||||
shutdown = ("killall mgen",)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a startup script for MgenActor. Because mgenActor does not
|
Generate a startup script for MgenActor. Because mgenActor does not
|
||||||
daemonize, it can cause problems in some situations when launched
|
daemonize, it can cause problems in some situations when launched
|
||||||
|
@ -604,11 +584,9 @@ class MgenActor(NrlService):
|
||||||
cfg += "# auto-generated by nrl.py:MgenActor.generateconfig()\n"
|
cfg += "# auto-generated by nrl.py:MgenActor.generateconfig()\n"
|
||||||
comments = ""
|
comments = ""
|
||||||
cmd = "mgenBasicActor.py -n %s -a 0.0.0.0" % node.name
|
cmd = "mgenBasicActor.py -n %s -a 0.0.0.0" % node.name
|
||||||
|
|
||||||
ifaces = node.get_ifaces(control=False)
|
ifaces = node.get_ifaces(control=False)
|
||||||
if len(ifaces) == 0:
|
if len(ifaces) == 0:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
|
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
@ -618,15 +596,15 @@ class Arouted(NrlService):
|
||||||
Adaptive Routing
|
Adaptive Routing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "arouted"
|
name: str = "arouted"
|
||||||
executables = ("arouted",)
|
executables: Tuple[str, ...] = ("arouted",)
|
||||||
configs = ("startarouted.sh",)
|
configs: Tuple[str, ...] = ("startarouted.sh",)
|
||||||
startup = ("sh startarouted.sh",)
|
startup: Tuple[str, ...] = ("sh startarouted.sh",)
|
||||||
shutdown = ("pkill arouted",)
|
shutdown: Tuple[str, ...] = ("pkill arouted",)
|
||||||
validate = ("pidof arouted",)
|
validate: Tuple[str, ...] = ("pidof arouted",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the Quagga.conf or quaggaboot.sh file contents.
|
Return the Quagga.conf or quaggaboot.sh file contents.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,65 +1,68 @@
|
||||||
"""
|
"""
|
||||||
quagga.py: defines routing services provided by Quagga.
|
quagga.py: defines routing services provided by Quagga.
|
||||||
"""
|
"""
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.emulator.enumerations import LinkTypes
|
from core.emulator.enumerations import LinkTypes
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
|
from core.nodes.interface import CoreInterface
|
||||||
from core.nodes.network import PtpNet, WlanNode
|
from core.nodes.network import PtpNet, WlanNode
|
||||||
from core.nodes.physical import Rj45Node
|
from core.nodes.physical import Rj45Node
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
class Zebra(CoreService):
|
class Zebra(CoreService):
|
||||||
name = "zebra"
|
name: str = "zebra"
|
||||||
group = "Quagga"
|
group: str = "Quagga"
|
||||||
dirs = ("/usr/local/etc/quagga", "/var/run/quagga")
|
dirs: Tuple[str, ...] = ("/usr/local/etc/quagga", "/var/run/quagga")
|
||||||
configs = (
|
configs: Tuple[str, ...] = (
|
||||||
"/usr/local/etc/quagga/Quagga.conf",
|
"/usr/local/etc/quagga/Quagga.conf",
|
||||||
"quaggaboot.sh",
|
"quaggaboot.sh",
|
||||||
"/usr/local/etc/quagga/vtysh.conf",
|
"/usr/local/etc/quagga/vtysh.conf",
|
||||||
)
|
)
|
||||||
startup = ("sh quaggaboot.sh zebra",)
|
startup: Tuple[str, ...] = ("sh quaggaboot.sh zebra",)
|
||||||
shutdown = ("killall zebra",)
|
shutdown: Tuple[str, ...] = ("killall zebra",)
|
||||||
validate = ("pidof zebra",)
|
validate: Tuple[str, ...] = ("pidof zebra",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the Quagga.conf or quaggaboot.sh file contents.
|
Return the Quagga.conf or quaggaboot.sh file contents.
|
||||||
"""
|
"""
|
||||||
if filename == cls.configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateQuaggaConf(node)
|
return cls.generate_quagga_conf(node)
|
||||||
elif filename == cls.configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateQuaggaBoot(node)
|
return cls.generate_quagga_boot(node)
|
||||||
elif filename == cls.configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generateVtyshConf(node)
|
return cls.generate_vtysh_conf(node)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"file name (%s) is not a known configuration: %s", filename, cls.configs
|
"file name (%s) is not a known configuration: %s", filename, cls.configs
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateVtyshConf(cls, node):
|
def generate_vtysh_conf(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text.
|
Returns configuration file text.
|
||||||
"""
|
"""
|
||||||
return "service integrated-vtysh-config\n"
|
return "service integrated-vtysh-config\n"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateQuaggaConf(cls, node):
|
def generate_quagga_conf(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text. Other services that depend on zebra
|
Returns configuration file text. Other services that depend on zebra
|
||||||
will have generatequaggaifcconfig() and generatequaggaconfig()
|
will have hooks that are invoked here.
|
||||||
hooks that are invoked here.
|
|
||||||
"""
|
"""
|
||||||
# we could verify here that filename == Quagga.conf
|
# we could verify here that filename == Quagga.conf
|
||||||
cfg = ""
|
cfg = ""
|
||||||
for iface in node.get_ifaces():
|
for iface in node.get_ifaces():
|
||||||
cfg += "interface %s\n" % iface.name
|
cfg += "interface %s\n" % iface.name
|
||||||
# include control interfaces in addressing but not routing daemons
|
# include control interfaces in addressing but not routing daemons
|
||||||
if hasattr(iface, "control") and iface.control is True:
|
if getattr(iface, "control", False):
|
||||||
cfg += " "
|
cfg += " "
|
||||||
cfg += "\n ".join(map(cls.addrstr, iface.addrlist))
|
cfg += "\n ".join(map(cls.addrstr, iface.addrlist))
|
||||||
cfg += "\n"
|
cfg += "\n"
|
||||||
|
@ -71,6 +74,8 @@ class Zebra(CoreService):
|
||||||
for s in node.services:
|
for s in node.services:
|
||||||
if cls.name not in s.dependencies:
|
if cls.name not in s.dependencies:
|
||||||
continue
|
continue
|
||||||
|
if not (isinstance(s, QuaggaService) or issubclass(s, QuaggaService)):
|
||||||
|
continue
|
||||||
iface_config = s.generate_quagga_iface_config(node, iface)
|
iface_config = s.generate_quagga_iface_config(node, iface)
|
||||||
if s.ipv4_routing:
|
if s.ipv4_routing:
|
||||||
want_ipv4 = True
|
want_ipv4 = True
|
||||||
|
@ -101,11 +106,13 @@ class Zebra(CoreService):
|
||||||
for s in node.services:
|
for s in node.services:
|
||||||
if cls.name not in s.dependencies:
|
if cls.name not in s.dependencies:
|
||||||
continue
|
continue
|
||||||
|
if not (isinstance(s, QuaggaService) or issubclass(s, QuaggaService)):
|
||||||
|
continue
|
||||||
cfg += s.generate_quagga_config(node)
|
cfg += s.generate_quagga_config(node)
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def addrstr(x):
|
def addrstr(x: str) -> str:
|
||||||
"""
|
"""
|
||||||
helper for mapping IP addresses to zebra config statements
|
helper for mapping IP addresses to zebra config statements
|
||||||
"""
|
"""
|
||||||
|
@ -118,7 +125,7 @@ class Zebra(CoreService):
|
||||||
raise ValueError("invalid address: %s", x)
|
raise ValueError("invalid address: %s", x)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateQuaggaBoot(cls, node):
|
def generate_quagga_boot(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a shell script used to boot the Quagga daemons.
|
Generate a shell script used to boot the Quagga daemons.
|
||||||
"""
|
"""
|
||||||
|
@ -235,20 +242,15 @@ class QuaggaService(CoreService):
|
||||||
common to Quagga's routing daemons.
|
common to Quagga's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
group = "Quagga"
|
group: str = "Quagga"
|
||||||
dependencies = ("zebra",)
|
dependencies: Tuple[str, ...] = (Zebra.name,)
|
||||||
dirs = ()
|
meta: str = "The config file for this service can be found in the Zebra service."
|
||||||
configs = ()
|
ipv4_routing: bool = False
|
||||||
startup = ()
|
ipv6_routing: bool = False
|
||||||
shutdown = ()
|
|
||||||
meta = "The config file for this service can be found in the Zebra service."
|
|
||||||
|
|
||||||
ipv4_routing = False
|
|
||||||
ipv6_routing = False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routerid(node):
|
def router_id(node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
|
@ -257,11 +259,10 @@ class QuaggaService(CoreService):
|
||||||
a = a.split("/")[0]
|
a = a.split("/")[0]
|
||||||
if netaddr.valid_ipv4(a):
|
if netaddr.valid_ipv4(a):
|
||||||
return a
|
return a
|
||||||
# raise ValueError, "no IPv4 address found for router ID"
|
return f"0.0.0.{node.id:d}"
|
||||||
return "0.0.0.%d" % node.id
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def rj45check(iface):
|
def rj45check(iface: CoreInterface) -> bool:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected an external RJ45
|
Helper to detect whether interface is connected an external RJ45
|
||||||
link.
|
link.
|
||||||
|
@ -275,15 +276,15 @@ class QuaggaService(CoreService):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,14 +295,13 @@ class Ospfv2(QuaggaService):
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OSPFv2"
|
name: str = "OSPFv2"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ospfd",)
|
||||||
shutdown = ("killall ospfd",)
|
validate: Tuple[str, ...] = ("pidof ospfd",)
|
||||||
validate = ("pidof ospfd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mtucheck(iface):
|
def mtu_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect MTU mismatch and add the appropriate OSPF
|
Helper to detect MTU mismatch and add the appropriate OSPF
|
||||||
mtu-ignore command. This is needed when e.g. a node is linked via a
|
mtu-ignore command. This is needed when e.g. a node is linked via a
|
||||||
|
@ -319,7 +319,7 @@ class Ospfv2(QuaggaService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ptpcheck(iface):
|
def ptp_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected to a notional
|
Helper to detect whether interface is connected to a notional
|
||||||
point-to-point link.
|
point-to-point link.
|
||||||
|
@ -329,9 +329,9 @@ class Ospfv2(QuaggaService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router ospf\n"
|
cfg = "router ospf\n"
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " router-id %s\n" % rtrid
|
cfg += " router-id %s\n" % rtrid
|
||||||
# network 10.0.0.0/24 area 0
|
# network 10.0.0.0/24 area 0
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
|
@ -343,12 +343,12 @@ class Ospfv2(QuaggaService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
cfg = cls.mtucheck(iface)
|
cfg = cls.mtu_check(iface)
|
||||||
# external RJ45 connections will use default OSPF timers
|
# external RJ45 connections will use default OSPF timers
|
||||||
if cls.rj45check(iface):
|
if cls.rj45check(iface):
|
||||||
return cfg
|
return cfg
|
||||||
cfg += cls.ptpcheck(iface)
|
cfg += cls.ptp_check(iface)
|
||||||
return (
|
return (
|
||||||
cfg
|
cfg
|
||||||
+ """\
|
+ """\
|
||||||
|
@ -366,15 +366,14 @@ class Ospfv3(QuaggaService):
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OSPFv3"
|
name: str = "OSPFv3"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ospf6d",)
|
||||||
shutdown = ("killall ospf6d",)
|
validate: Tuple[str, ...] = ("pidof ospf6d",)
|
||||||
validate = ("pidof ospf6d",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def minmtu(iface):
|
def min_mtu(iface: CoreInterface) -> int:
|
||||||
"""
|
"""
|
||||||
Helper to discover the minimum MTU of interfaces linked with the
|
Helper to discover the minimum MTU of interfaces linked with the
|
||||||
given interface.
|
given interface.
|
||||||
|
@ -388,20 +387,20 @@ class Ospfv3(QuaggaService):
|
||||||
return mtu
|
return mtu
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def mtucheck(cls, iface):
|
def mtu_check(cls, iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect MTU mismatch and add the appropriate OSPFv3
|
Helper to detect MTU mismatch and add the appropriate OSPFv3
|
||||||
ifmtu command. This is needed when e.g. a node is linked via a
|
ifmtu command. This is needed when e.g. a node is linked via a
|
||||||
GreTap device.
|
GreTap device.
|
||||||
"""
|
"""
|
||||||
minmtu = cls.minmtu(iface)
|
minmtu = cls.min_mtu(iface)
|
||||||
if minmtu < iface.mtu:
|
if minmtu < iface.mtu:
|
||||||
return " ipv6 ospf6 ifmtu %d\n" % minmtu
|
return " ipv6 ospf6 ifmtu %d\n" % minmtu
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ptpcheck(iface):
|
def ptp_check(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to detect whether interface is connected to a notional
|
Helper to detect whether interface is connected to a notional
|
||||||
point-to-point link.
|
point-to-point link.
|
||||||
|
@ -411,9 +410,9 @@ class Ospfv3(QuaggaService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router ospf6\n"
|
cfg = "router ospf6\n"
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " instance-id 65\n"
|
cfg += " instance-id 65\n"
|
||||||
cfg += " router-id %s\n" % rtrid
|
cfg += " router-id %s\n" % rtrid
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
|
@ -422,8 +421,8 @@ class Ospfv3(QuaggaService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return cls.mtucheck(iface)
|
return cls.mtu_check(iface)
|
||||||
|
|
||||||
|
|
||||||
class Ospfv3mdr(Ospfv3):
|
class Ospfv3mdr(Ospfv3):
|
||||||
|
@ -434,12 +433,12 @@ class Ospfv3mdr(Ospfv3):
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "OSPFv3MDR"
|
name: str = "OSPFv3MDR"
|
||||||
ipv4_routing = True
|
ipv4_routing: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
cfg = cls.mtucheck(iface)
|
cfg = cls.mtu_check(iface)
|
||||||
if iface.net is not None and isinstance(iface.net, (WlanNode, EmaneNet)):
|
if iface.net is not None and isinstance(iface.net, (WlanNode, EmaneNet)):
|
||||||
return (
|
return (
|
||||||
cfg
|
cfg
|
||||||
|
@ -464,21 +463,20 @@ class Bgp(QuaggaService):
|
||||||
having the same AS number.
|
having the same AS number.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "BGP"
|
name: str = "BGP"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall bgpd",)
|
||||||
shutdown = ("killall bgpd",)
|
validate: Tuple[str, ...] = ("pidof bgpd",)
|
||||||
validate = ("pidof bgpd",)
|
custom_needed: bool = True
|
||||||
custom_needed = True
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "!\n! BGP configuration\n!\n"
|
cfg = "!\n! BGP configuration\n!\n"
|
||||||
cfg += "! You should configure the AS number below,\n"
|
cfg += "! You should configure the AS number below,\n"
|
||||||
cfg += "! along with this router's peers.\n!\n"
|
cfg += "! along with this router's peers.\n!\n"
|
||||||
cfg += "router bgp %s\n" % node.id
|
cfg += "router bgp %s\n" % node.id
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += " bgp router-id %s\n" % rtrid
|
cfg += " bgp router-id %s\n" % rtrid
|
||||||
cfg += " redistribute connected\n"
|
cfg += " redistribute connected\n"
|
||||||
cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n"
|
cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n"
|
||||||
|
@ -490,14 +488,13 @@ class Rip(QuaggaService):
|
||||||
The RIP service provides IPv4 routing for wired networks.
|
The RIP service provides IPv4 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "RIP"
|
name: str = "RIP"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ripd",)
|
||||||
shutdown = ("killall ripd",)
|
validate: Tuple[str, ...] = ("pidof ripd",)
|
||||||
validate = ("pidof ripd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = """\
|
cfg = """\
|
||||||
router rip
|
router rip
|
||||||
redistribute static
|
redistribute static
|
||||||
|
@ -514,14 +511,13 @@ class Ripng(QuaggaService):
|
||||||
The RIP NG service provides IPv6 routing for wired networks.
|
The RIP NG service provides IPv6 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "RIPNG"
|
name: str = "RIPNG"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall ripngd",)
|
||||||
shutdown = ("killall ripngd",)
|
validate: Tuple[str, ...] = ("pidof ripngd",)
|
||||||
validate = ("pidof ripngd",)
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = """\
|
cfg = """\
|
||||||
router ripng
|
router ripng
|
||||||
redistribute static
|
redistribute static
|
||||||
|
@ -539,14 +535,13 @@ class Babel(QuaggaService):
|
||||||
protocol for IPv6 and IPv4 with fast convergence properties.
|
protocol for IPv6 and IPv4 with fast convergence properties.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "Babel"
|
name: str = "Babel"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall babeld",)
|
||||||
shutdown = ("killall babeld",)
|
validate: Tuple[str, ...] = ("pidof babeld",)
|
||||||
validate = ("pidof babeld",)
|
ipv6_routing: bool = True
|
||||||
ipv6_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "router babel\n"
|
cfg = "router babel\n"
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
cfg += " network %s\n" % iface.name
|
cfg += " network %s\n" % iface.name
|
||||||
|
@ -554,7 +549,7 @@ class Babel(QuaggaService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
if iface.net and iface.net.linktype == LinkTypes.WIRELESS:
|
if iface.net and iface.net.linktype == LinkTypes.WIRELESS:
|
||||||
return " babel wireless\n no babel split-horizon\n"
|
return " babel wireless\n no babel split-horizon\n"
|
||||||
else:
|
else:
|
||||||
|
@ -566,14 +561,13 @@ class Xpimd(QuaggaService):
|
||||||
PIM multicast routing based on XORP.
|
PIM multicast routing based on XORP.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "Xpimd"
|
name: str = "Xpimd"
|
||||||
startup = ()
|
shutdown: Tuple[str, ...] = ("killall xpimd",)
|
||||||
shutdown = ("killall xpimd",)
|
validate: Tuple[str, ...] = ("pidof xpimd",)
|
||||||
validate = ("pidof xpimd",)
|
ipv4_routing: bool = True
|
||||||
ipv4_routing = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_config(cls, node):
|
def generate_quagga_config(cls, node: CoreNode) -> str:
|
||||||
ifname = "eth0"
|
ifname = "eth0"
|
||||||
for iface in node.get_ifaces():
|
for iface in node.get_ifaces():
|
||||||
if iface.name != "lo":
|
if iface.name != "lo":
|
||||||
|
@ -589,5 +583,5 @@ class Xpimd(QuaggaService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_quagga_iface_config(cls, node, iface):
|
def generate_quagga_iface_config(cls, node: CoreNode, iface: CoreInterface) -> str:
|
||||||
return " ip mfea\n ip igmp\n ip pim\n"
|
return " ip mfea\n ip igmp\n ip pim\n"
|
||||||
|
|
|
@ -3,9 +3,11 @@ sdn.py defines services to start Open vSwitch and the Ryu SDN Controller.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,24 +16,28 @@ class SdnService(CoreService):
|
||||||
Parent class for SDN services.
|
Parent class for SDN services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
group = "SDN"
|
group: str = "SDN"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class OvsService(SdnService):
|
class OvsService(SdnService):
|
||||||
name = "OvsService"
|
name: str = "OvsService"
|
||||||
executables = ("ovs-ofctl", "ovs-vsctl")
|
group: str = "SDN"
|
||||||
group = "SDN"
|
executables: Tuple[str, ...] = ("ovs-ofctl", "ovs-vsctl")
|
||||||
dirs = ("/etc/openvswitch", "/var/run/openvswitch", "/var/log/openvswitch")
|
dirs: Tuple[str, ...] = (
|
||||||
configs = ("OvsService.sh",)
|
"/etc/openvswitch",
|
||||||
startup = ("sh OvsService.sh",)
|
"/var/run/openvswitch",
|
||||||
shutdown = ("killall ovs-vswitchd", "killall ovsdb-server")
|
"/var/log/openvswitch",
|
||||||
|
)
|
||||||
|
configs: Tuple[str, ...] = ("OvsService.sh",)
|
||||||
|
startup: Tuple[str, ...] = ("sh OvsService.sh",)
|
||||||
|
shutdown: Tuple[str, ...] = ("killall ovs-vswitchd", "killall ovsdb-server")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
# Check whether the node is running zebra
|
# Check whether the node is running zebra
|
||||||
has_zebra = 0
|
has_zebra = 0
|
||||||
for s in node.services:
|
for s in node.services:
|
||||||
|
@ -46,8 +52,8 @@ class OvsService(SdnService):
|
||||||
cfg += "## this stops it from routing traffic without defined flows.\n"
|
cfg += "## this stops it from routing traffic without defined flows.\n"
|
||||||
cfg += "## remove the -- and everything after if you want it to act as a regular switch\n"
|
cfg += "## remove the -- and everything after if you want it to act as a regular switch\n"
|
||||||
cfg += "ovs-vsctl add-br ovsbr0 -- set Bridge ovsbr0 fail-mode=secure\n"
|
cfg += "ovs-vsctl add-br ovsbr0 -- set Bridge ovsbr0 fail-mode=secure\n"
|
||||||
|
|
||||||
cfg += "\n## Now add all our interfaces as ports to the switch\n"
|
cfg += "\n## Now add all our interfaces as ports to the switch\n"
|
||||||
|
|
||||||
portnum = 1
|
portnum = 1
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
ifnumstr = re.findall(r"\d+", iface.name)
|
ifnumstr = re.findall(r"\d+", iface.name)
|
||||||
|
@ -111,21 +117,19 @@ class OvsService(SdnService):
|
||||||
% (portnum + 1, portnum)
|
% (portnum + 1, portnum)
|
||||||
)
|
)
|
||||||
portnum += 2
|
portnum += 2
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
class RyuService(SdnService):
|
class RyuService(SdnService):
|
||||||
name = "ryuService"
|
name: str = "ryuService"
|
||||||
executables = ("ryu-manager",)
|
group: str = "SDN"
|
||||||
group = "SDN"
|
executables: Tuple[str, ...] = ("ryu-manager",)
|
||||||
dirs = ()
|
configs: Tuple[str, ...] = ("ryuService.sh",)
|
||||||
configs = ("ryuService.sh",)
|
startup: Tuple[str, ...] = ("sh ryuService.sh",)
|
||||||
startup = ("sh ryuService.sh",)
|
shutdown: Tuple[str, ...] = ("killall ryu-manager",)
|
||||||
shutdown = ("killall ryu-manager",)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return a string that will be written to filename, or sent to the
|
Return a string that will be written to filename, or sent to the
|
||||||
GUI for user customization.
|
GUI for user customization.
|
||||||
|
|
|
@ -4,78 +4,79 @@ firewall)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
|
from core.nodes.interface import CoreInterface
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
class VPNClient(CoreService):
|
class VPNClient(CoreService):
|
||||||
name = "VPNClient"
|
name: str = "VPNClient"
|
||||||
group = "Security"
|
group: str = "Security"
|
||||||
configs = ("vpnclient.sh",)
|
configs: Tuple[str, ...] = ("vpnclient.sh",)
|
||||||
startup = ("sh vpnclient.sh",)
|
startup: Tuple[str, ...] = ("sh vpnclient.sh",)
|
||||||
shutdown = ("killall openvpn",)
|
shutdown: Tuple[str, ...] = ("killall openvpn",)
|
||||||
validate = ("pidof openvpn",)
|
validate: Tuple[str, ...] = ("pidof openvpn",)
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the client.conf and vpnclient.sh file contents to
|
Return the client.conf and vpnclient.sh file contents to
|
||||||
"""
|
"""
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# custom VPN Client configuration for service (security.py)\n"
|
cfg += "# custom VPN Client configuration for service (security.py)\n"
|
||||||
fname = "%s/examples/services/sampleVPNClient" % constants.CORE_DATA_DIR
|
fname = f"{constants.CORE_DATA_DIR}/examples/services/sampleVPNClient"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg += open(fname, "rb").read()
|
with open(fname, "r") as f:
|
||||||
|
cfg += f.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"Error opening VPN client configuration template (%s)", fname
|
"error opening VPN client configuration template (%s)", fname
|
||||||
)
|
)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
class VPNServer(CoreService):
|
class VPNServer(CoreService):
|
||||||
name = "VPNServer"
|
name: str = "VPNServer"
|
||||||
group = "Security"
|
group: str = "Security"
|
||||||
configs = ("vpnserver.sh",)
|
configs: Tuple[str, ...] = ("vpnserver.sh",)
|
||||||
startup = ("sh vpnserver.sh",)
|
startup: Tuple[str, ...] = ("sh vpnserver.sh",)
|
||||||
shutdown = ("killall openvpn",)
|
shutdown: Tuple[str, ...] = ("killall openvpn",)
|
||||||
validate = ("pidof openvpn",)
|
validate: Tuple[str, ...] = ("pidof openvpn",)
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the sample server.conf and vpnserver.sh file contents to
|
Return the sample server.conf and vpnserver.sh file contents to
|
||||||
GUI for user customization.
|
GUI for user customization.
|
||||||
"""
|
"""
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# custom VPN Server Configuration for service (security.py)\n"
|
cfg += "# custom VPN Server Configuration for service (security.py)\n"
|
||||||
fname = "%s/examples/services/sampleVPNServer" % constants.CORE_DATA_DIR
|
fname = f"{constants.CORE_DATA_DIR}/examples/services/sampleVPNServer"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg += open(fname, "rb").read()
|
with open(fname, "r") as f:
|
||||||
|
cfg += f.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"Error opening VPN server configuration template (%s)", fname
|
"Error opening VPN server configuration template (%s)", fname
|
||||||
)
|
)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
class IPsec(CoreService):
|
class IPsec(CoreService):
|
||||||
name = "IPsec"
|
name: str = "IPsec"
|
||||||
group = "Security"
|
group: str = "Security"
|
||||||
configs = ("ipsec.sh",)
|
configs: Tuple[str, ...] = ("ipsec.sh",)
|
||||||
startup = ("sh ipsec.sh",)
|
startup: Tuple[str, ...] = ("sh ipsec.sh",)
|
||||||
shutdown = ("killall racoon",)
|
shutdown: Tuple[str, ...] = ("killall racoon",)
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the ipsec.conf and racoon.conf file contents to
|
Return the ipsec.conf and racoon.conf file contents to
|
||||||
GUI for user customization.
|
GUI for user customization.
|
||||||
|
@ -83,7 +84,7 @@ class IPsec(CoreService):
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# set up static tunnel mode security assocation for service "
|
cfg += "# set up static tunnel mode security assocation for service "
|
||||||
cfg += "(security.py)\n"
|
cfg += "(security.py)\n"
|
||||||
fname = "%s/examples/services/sampleIPsec" % constants.CORE_DATA_DIR
|
fname = f"{constants.CORE_DATA_DIR}/examples/services/sampleIPsec"
|
||||||
try:
|
try:
|
||||||
with open(fname, "r") as f:
|
with open(fname, "r") as f:
|
||||||
cfg += f.read()
|
cfg += f.read()
|
||||||
|
@ -93,28 +94,27 @@ class IPsec(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class Firewall(CoreService):
|
class Firewall(CoreService):
|
||||||
name = "Firewall"
|
name: str = "Firewall"
|
||||||
group = "Security"
|
group: str = "Security"
|
||||||
configs = ("firewall.sh",)
|
configs: Tuple[str, ...] = ("firewall.sh",)
|
||||||
startup = ("sh firewall.sh",)
|
startup: Tuple[str, ...] = ("sh firewall.sh",)
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the firewall rule examples to GUI for user customization.
|
Return the firewall rule examples to GUI for user customization.
|
||||||
"""
|
"""
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# custom node firewall rules for service (security.py)\n"
|
cfg += "# custom node firewall rules for service (security.py)\n"
|
||||||
fname = "%s/examples/services/sampleFirewall" % constants.CORE_DATA_DIR
|
fname = f"{constants.CORE_DATA_DIR}/examples/services/sampleFirewall"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg += open(fname, "rb").read()
|
with open(fname, "r") as f:
|
||||||
|
cfg += f.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"Error opening Firewall configuration template (%s)", fname
|
"Error opening Firewall configuration template (%s)", fname
|
||||||
)
|
)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,30 +123,28 @@ class Nat(CoreService):
|
||||||
IPv4 source NAT service.
|
IPv4 source NAT service.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "NAT"
|
name: str = "NAT"
|
||||||
executables = ("iptables",)
|
group: str = "Security"
|
||||||
group = "Security"
|
executables: Tuple[str, ...] = ("iptables",)
|
||||||
configs = ("nat.sh",)
|
configs: Tuple[str, ...] = ("nat.sh",)
|
||||||
startup = ("sh nat.sh",)
|
startup: Tuple[str, ...] = ("sh nat.sh",)
|
||||||
custom_needed = False
|
custom_needed: bool = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_iface_nat_rule(cls, iface, line_prefix=""):
|
def generate_iface_nat_rule(cls, iface: CoreInterface, prefix: str = "") -> str:
|
||||||
"""
|
"""
|
||||||
Generate a NAT line for one interface.
|
Generate a NAT line for one interface.
|
||||||
"""
|
"""
|
||||||
cfg = line_prefix + "iptables -t nat -A POSTROUTING -o "
|
cfg = prefix + "iptables -t nat -A POSTROUTING -o "
|
||||||
cfg += iface.name + " -j MASQUERADE\n"
|
cfg += iface.name + " -j MASQUERADE\n"
|
||||||
|
cfg += prefix + "iptables -A FORWARD -i " + iface.name
|
||||||
cfg += line_prefix + "iptables -A FORWARD -i " + iface.name
|
|
||||||
cfg += " -m state --state RELATED,ESTABLISHED -j ACCEPT\n"
|
cfg += " -m state --state RELATED,ESTABLISHED -j ACCEPT\n"
|
||||||
|
cfg += prefix + "iptables -A FORWARD -i "
|
||||||
cfg += line_prefix + "iptables -A FORWARD -i "
|
|
||||||
cfg += iface.name + " -j DROP\n"
|
cfg += iface.name + " -j DROP\n"
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
NAT out the first interface
|
NAT out the first interface
|
||||||
"""
|
"""
|
||||||
|
@ -156,7 +154,7 @@ class Nat(CoreService):
|
||||||
have_nat = False
|
have_nat = False
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
if have_nat:
|
if have_nat:
|
||||||
cfg += cls.generate_iface_nat_rule(iface, line_prefix="#")
|
cfg += cls.generate_iface_nat_rule(iface, prefix="#")
|
||||||
else:
|
else:
|
||||||
have_nat = True
|
have_nat = True
|
||||||
cfg += "# NAT out the " + iface.name + " interface\n"
|
cfg += "# NAT out the " + iface.name + " interface\n"
|
||||||
|
|
|
@ -1,52 +1,52 @@
|
||||||
"""
|
"""
|
||||||
ucarp.py: defines high-availability IP address controlled by ucarp
|
ucarp.py: defines high-availability IP address controlled by ucarp
|
||||||
"""
|
"""
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
UCARP_ETC = "/usr/local/etc/ucarp"
|
UCARP_ETC = "/usr/local/etc/ucarp"
|
||||||
|
|
||||||
|
|
||||||
class Ucarp(CoreService):
|
class Ucarp(CoreService):
|
||||||
name = "ucarp"
|
name: str = "ucarp"
|
||||||
group = "Utility"
|
group: str = "Utility"
|
||||||
dirs = (UCARP_ETC,)
|
dirs: Tuple[str, ...] = (UCARP_ETC,)
|
||||||
configs = (
|
configs: Tuple[str, ...] = (
|
||||||
UCARP_ETC + "/default.sh",
|
UCARP_ETC + "/default.sh",
|
||||||
UCARP_ETC + "/default-up.sh",
|
UCARP_ETC + "/default-up.sh",
|
||||||
UCARP_ETC + "/default-down.sh",
|
UCARP_ETC + "/default-down.sh",
|
||||||
"ucarpboot.sh",
|
"ucarpboot.sh",
|
||||||
)
|
)
|
||||||
startup = ("sh ucarpboot.sh",)
|
startup: Tuple[str, ...] = ("sh ucarpboot.sh",)
|
||||||
shutdown = ("killall ucarp",)
|
shutdown: Tuple[str, ...] = ("killall ucarp",)
|
||||||
validate = ("pidof ucarp",)
|
validate: Tuple[str, ...] = ("pidof ucarp",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Return the default file contents
|
Return the default file contents
|
||||||
"""
|
"""
|
||||||
if filename == cls.configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateUcarpConf(node)
|
return cls.generate_ucarp_conf(node)
|
||||||
elif filename == cls.configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateVipUp(node)
|
return cls.generate_vip_up(node)
|
||||||
elif filename == cls.configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generateVipDown(node)
|
return cls.generate_vip_down(node)
|
||||||
elif filename == cls.configs[3]:
|
elif filename == cls.configs[3]:
|
||||||
return cls.generateUcarpBoot(node)
|
return cls.generate_ucarp_boot(node)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateUcarpConf(cls, node):
|
def generate_ucarp_conf(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Returns configuration file text.
|
Returns configuration file text.
|
||||||
"""
|
"""
|
||||||
try:
|
ucarp_bin = node.session.options.get_config(
|
||||||
ucarp_bin = node.session.cfg["ucarp_bin"]
|
"ucarp_bin", default="/usr/sbin/ucarp"
|
||||||
except KeyError:
|
)
|
||||||
ucarp_bin = "/usr/sbin/ucarp"
|
|
||||||
|
|
||||||
return """\
|
return """\
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Location of UCARP executable
|
# Location of UCARP executable
|
||||||
|
@ -110,7 +110,7 @@ ${UCARP_EXEC} -B ${UCARP_OPTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateUcarpBoot(cls, node):
|
def generate_ucarp_boot(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a shell script used to boot the Ucarp daemons.
|
Generate a shell script used to boot the Ucarp daemons.
|
||||||
"""
|
"""
|
||||||
|
@ -130,7 +130,7 @@ ${UCARP_CFGDIR}/default.sh
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateVipUp(cls, node):
|
def generate_vip_up(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a shell script used to start the virtual ip
|
Generate a shell script used to start the virtual ip
|
||||||
"""
|
"""
|
||||||
|
@ -152,7 +152,7 @@ fi
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateVipDown(cls, node):
|
def generate_vip_down(cls, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a shell script used to stop the virtual ip
|
Generate a shell script used to stop the virtual ip
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
"""
|
"""
|
||||||
utility.py: defines miscellaneous utility services.
|
utility.py: defines miscellaneous utility services.
|
||||||
"""
|
"""
|
||||||
import os
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core import constants, utils
|
from core import constants, utils
|
||||||
from core.errors import CoreCommandError
|
from core.errors import CoreCommandError
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
from core.services.coreservices import CoreService, ServiceMode
|
from core.services.coreservices import CoreService, ServiceMode
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,32 +16,25 @@ class UtilService(CoreService):
|
||||||
Parent class for utility services.
|
Parent class for utility services.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
group = "Utility"
|
group: str = "Utility"
|
||||||
dirs = ()
|
|
||||||
configs = ()
|
|
||||||
startup = ()
|
|
||||||
shutdown = ()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class IPForwardService(UtilService):
|
class IPForwardService(UtilService):
|
||||||
name = "IPForward"
|
name: str = "IPForward"
|
||||||
configs = ("ipforward.sh",)
|
configs: Tuple[str, ...] = ("ipforward.sh",)
|
||||||
startup = ("sh ipforward.sh",)
|
startup: Tuple[str, ...] = ("sh ipforward.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
if os.uname()[0] == "Linux":
|
|
||||||
return cls.generateconfiglinux(node, filename)
|
return cls.generateconfiglinux(node, filename)
|
||||||
else:
|
|
||||||
raise Exception("unknown platform")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfiglinux(cls, node, filename):
|
def generateconfiglinux(cls, node: CoreNode, filename: str) -> str:
|
||||||
cfg = """\
|
cfg = """\
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# auto-generated by IPForward service (utility.py)
|
# auto-generated by IPForward service (utility.py)
|
||||||
|
@ -70,12 +64,12 @@ class IPForwardService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class DefaultRouteService(UtilService):
|
class DefaultRouteService(UtilService):
|
||||||
name = "DefaultRoute"
|
name: str = "DefaultRoute"
|
||||||
configs = ("defaultroute.sh",)
|
configs: Tuple[str, ...] = ("defaultroute.sh",)
|
||||||
startup = ("sh defaultroute.sh",)
|
startup: Tuple[str, ...] = ("sh defaultroute.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
routes = []
|
routes = []
|
||||||
ifaces = node.get_ifaces()
|
ifaces = node.get_ifaces()
|
||||||
if ifaces:
|
if ifaces:
|
||||||
|
@ -93,22 +87,18 @@ class DefaultRouteService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class DefaultMulticastRouteService(UtilService):
|
class DefaultMulticastRouteService(UtilService):
|
||||||
name = "DefaultMulticastRoute"
|
name: str = "DefaultMulticastRoute"
|
||||||
configs = ("defaultmroute.sh",)
|
configs: Tuple[str, ...] = ("defaultmroute.sh",)
|
||||||
startup = ("sh defaultmroute.sh",)
|
startup: Tuple[str, ...] = ("sh defaultmroute.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# auto-generated by DefaultMulticastRoute service (utility.py)\n"
|
cfg += "# auto-generated by DefaultMulticastRoute service (utility.py)\n"
|
||||||
cfg += "# the first interface is chosen below; please change it "
|
cfg += "# the first interface is chosen below; please change it "
|
||||||
cfg += "as needed\n"
|
cfg += "as needed\n"
|
||||||
|
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
if os.uname()[0] == "Linux":
|
|
||||||
rtcmd = "ip route add 224.0.0.0/4 dev"
|
rtcmd = "ip route add 224.0.0.0/4 dev"
|
||||||
else:
|
|
||||||
raise Exception("unknown platform")
|
|
||||||
cfg += "%s %s\n" % (rtcmd, iface.name)
|
cfg += "%s %s\n" % (rtcmd, iface.name)
|
||||||
cfg += "\n"
|
cfg += "\n"
|
||||||
break
|
break
|
||||||
|
@ -116,13 +106,13 @@ class DefaultMulticastRouteService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class StaticRouteService(UtilService):
|
class StaticRouteService(UtilService):
|
||||||
name = "StaticRoute"
|
name: str = "StaticRoute"
|
||||||
configs = ("staticroute.sh",)
|
configs: Tuple[str, ...] = ("staticroute.sh",)
|
||||||
startup = ("sh staticroute.sh",)
|
startup: Tuple[str, ...] = ("sh staticroute.sh",)
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
cfg += "# auto-generated by StaticRoute service (utility.py)\n#\n"
|
cfg += "# auto-generated by StaticRoute service (utility.py)\n#\n"
|
||||||
cfg += "# NOTE: this service must be customized to be of any use\n"
|
cfg += "# NOTE: this service must be customized to be of any use\n"
|
||||||
|
@ -133,7 +123,7 @@ class StaticRouteService(UtilService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routestr(x):
|
def routestr(x: str) -> str:
|
||||||
addr = x.split("/")[0]
|
addr = x.split("/")[0]
|
||||||
if netaddr.valid_ipv6(addr):
|
if netaddr.valid_ipv6(addr):
|
||||||
dst = "3ffe:4::/64"
|
dst = "3ffe:4::/64"
|
||||||
|
@ -143,24 +133,20 @@ class StaticRouteService(UtilService):
|
||||||
if net[-2] == net[1]:
|
if net[-2] == net[1]:
|
||||||
return ""
|
return ""
|
||||||
else:
|
else:
|
||||||
if os.uname()[0] == "Linux":
|
|
||||||
rtcmd = "#/sbin/ip route add %s via" % dst
|
rtcmd = "#/sbin/ip route add %s via" % dst
|
||||||
else:
|
|
||||||
raise Exception("unknown platform")
|
|
||||||
return "%s %s" % (rtcmd, net[1])
|
return "%s %s" % (rtcmd, net[1])
|
||||||
|
|
||||||
|
|
||||||
class SshService(UtilService):
|
class SshService(UtilService):
|
||||||
name = "SSH"
|
name: str = "SSH"
|
||||||
configs = ("startsshd.sh", "/etc/ssh/sshd_config")
|
configs: Tuple[str, ...] = ("startsshd.sh", "/etc/ssh/sshd_config")
|
||||||
dirs = ("/etc/ssh", "/var/run/sshd")
|
dirs: Tuple[str, ...] = ("/etc/ssh", "/var/run/sshd")
|
||||||
startup = ("sh startsshd.sh",)
|
startup: Tuple[str, ...] = ("sh startsshd.sh",)
|
||||||
shutdown = ("killall sshd",)
|
shutdown: Tuple[str, ...] = ("killall sshd",)
|
||||||
validate = ()
|
validation_mode: ServiceMode = ServiceMode.BLOCKING
|
||||||
validation_mode = ServiceMode.BLOCKING
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Use a startup script for launching sshd in order to wait for host
|
Use a startup script for launching sshd in order to wait for host
|
||||||
key generation.
|
key generation.
|
||||||
|
@ -228,15 +214,15 @@ UseDNS no
|
||||||
|
|
||||||
|
|
||||||
class DhcpService(UtilService):
|
class DhcpService(UtilService):
|
||||||
name = "DHCP"
|
name: str = "DHCP"
|
||||||
configs = ("/etc/dhcp/dhcpd.conf",)
|
configs: Tuple[str, ...] = ("/etc/dhcp/dhcpd.conf",)
|
||||||
dirs = ("/etc/dhcp", "/var/lib/dhcp")
|
dirs: Tuple[str, ...] = ("/etc/dhcp", "/var/lib/dhcp")
|
||||||
startup = ("touch /var/lib/dhcp/dhcpd.leases", "dhcpd")
|
startup: Tuple[str, ...] = ("touch /var/lib/dhcp/dhcpd.leases", "dhcpd")
|
||||||
shutdown = ("killall dhcpd",)
|
shutdown: Tuple[str, ...] = ("killall dhcpd",)
|
||||||
validate = ("pidof dhcpd",)
|
validate: Tuple[str, ...] = ("pidof dhcpd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a dhcpd config file using the network address of
|
Generate a dhcpd config file using the network address of
|
||||||
each interface.
|
each interface.
|
||||||
|
@ -261,7 +247,7 @@ ddns-update-style none;
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def subnetentry(x):
|
def subnetentry(x: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a subnet declaration block given an IPv4 prefix string
|
Generate a subnet declaration block given an IPv4 prefix string
|
||||||
for inclusion in the dhcpd3 config file.
|
for inclusion in the dhcpd3 config file.
|
||||||
|
@ -297,14 +283,14 @@ class DhcpClientService(UtilService):
|
||||||
Use a DHCP client for all interfaces for addressing.
|
Use a DHCP client for all interfaces for addressing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "DHCPClient"
|
name: str = "DHCPClient"
|
||||||
configs = ("startdhcpclient.sh",)
|
configs: Tuple[str, ...] = ("startdhcpclient.sh",)
|
||||||
startup = ("sh startdhcpclient.sh",)
|
startup: Tuple[str, ...] = ("sh startdhcpclient.sh",)
|
||||||
shutdown = ("killall dhclient",)
|
shutdown: Tuple[str, ...] = ("killall dhclient",)
|
||||||
validate = ("pidof dhclient",)
|
validate: Tuple[str, ...] = ("pidof dhclient",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a script to invoke dhclient on all interfaces.
|
Generate a script to invoke dhclient on all interfaces.
|
||||||
"""
|
"""
|
||||||
|
@ -313,7 +299,6 @@ class DhcpClientService(UtilService):
|
||||||
cfg += "# uncomment this mkdir line and symlink line to enable client-"
|
cfg += "# uncomment this mkdir line and symlink line to enable client-"
|
||||||
cfg += "side DNS\n# resolution based on the DHCP server response.\n"
|
cfg += "side DNS\n# resolution based on the DHCP server response.\n"
|
||||||
cfg += "#mkdir -p /var/run/resolvconf/interface\n"
|
cfg += "#mkdir -p /var/run/resolvconf/interface\n"
|
||||||
|
|
||||||
for iface in node.get_ifaces(control=False):
|
for iface in node.get_ifaces(control=False):
|
||||||
cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % iface.name
|
cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % iface.name
|
||||||
cfg += " /var/run/resolvconf/resolv.conf\n"
|
cfg += " /var/run/resolvconf/resolv.conf\n"
|
||||||
|
@ -327,15 +312,15 @@ class FtpService(UtilService):
|
||||||
Start a vsftpd server.
|
Start a vsftpd server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "FTP"
|
name: str = "FTP"
|
||||||
configs = ("vsftpd.conf",)
|
configs: Tuple[str, ...] = ("vsftpd.conf",)
|
||||||
dirs = ("/var/run/vsftpd/empty", "/var/ftp")
|
dirs: Tuple[str, ...] = ("/var/run/vsftpd/empty", "/var/ftp")
|
||||||
startup = ("vsftpd ./vsftpd.conf",)
|
startup: Tuple[str, ...] = ("vsftpd ./vsftpd.conf",)
|
||||||
shutdown = ("killall vsftpd",)
|
shutdown: Tuple[str, ...] = ("killall vsftpd",)
|
||||||
validate = ("pidof vsftpd",)
|
validate: Tuple[str, ...] = ("pidof vsftpd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a vsftpd.conf configuration file.
|
Generate a vsftpd.conf configuration file.
|
||||||
"""
|
"""
|
||||||
|
@ -360,13 +345,13 @@ class HttpService(UtilService):
|
||||||
Start an apache server.
|
Start an apache server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "HTTP"
|
name: str = "HTTP"
|
||||||
configs = (
|
configs: Tuple[str, ...] = (
|
||||||
"/etc/apache2/apache2.conf",
|
"/etc/apache2/apache2.conf",
|
||||||
"/etc/apache2/envvars",
|
"/etc/apache2/envvars",
|
||||||
"/var/www/index.html",
|
"/var/www/index.html",
|
||||||
)
|
)
|
||||||
dirs = (
|
dirs: Tuple[str, ...] = (
|
||||||
"/etc/apache2",
|
"/etc/apache2",
|
||||||
"/var/run/apache2",
|
"/var/run/apache2",
|
||||||
"/var/log/apache2",
|
"/var/log/apache2",
|
||||||
|
@ -374,14 +359,14 @@ class HttpService(UtilService):
|
||||||
"/var/lock/apache2",
|
"/var/lock/apache2",
|
||||||
"/var/www",
|
"/var/www",
|
||||||
)
|
)
|
||||||
startup = ("chown www-data /var/lock/apache2", "apache2ctl start")
|
startup: Tuple[str, ...] = ("chown www-data /var/lock/apache2", "apache2ctl start")
|
||||||
shutdown = ("apache2ctl stop",)
|
shutdown: Tuple[str, ...] = ("apache2ctl stop",)
|
||||||
validate = ("pidof apache2",)
|
validate: Tuple[str, ...] = ("pidof apache2",)
|
||||||
|
APACHEVER22: int = 22
|
||||||
APACHEVER22, APACHEVER24 = (22, 24)
|
APACHEVER24: int = 24
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate an apache2.conf configuration file.
|
Generate an apache2.conf configuration file.
|
||||||
"""
|
"""
|
||||||
|
@ -395,7 +380,7 @@ class HttpService(UtilService):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def detectversionfromcmd(cls):
|
def detectversionfromcmd(cls) -> int:
|
||||||
"""
|
"""
|
||||||
Detect the apache2 version using the 'a2query' command.
|
Detect the apache2 version using the 'a2query' command.
|
||||||
"""
|
"""
|
||||||
|
@ -405,14 +390,12 @@ class HttpService(UtilService):
|
||||||
except CoreCommandError as e:
|
except CoreCommandError as e:
|
||||||
status = e.returncode
|
status = e.returncode
|
||||||
result = e.stderr
|
result = e.stderr
|
||||||
|
|
||||||
if status == 0 and result[:3] == "2.4":
|
if status == 0 and result[:3] == "2.4":
|
||||||
return cls.APACHEVER24
|
return cls.APACHEVER24
|
||||||
|
|
||||||
return cls.APACHEVER22
|
return cls.APACHEVER22
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateapache2conf(cls, node, filename):
|
def generateapache2conf(cls, node: CoreNode, filename: str) -> str:
|
||||||
lockstr = {
|
lockstr = {
|
||||||
cls.APACHEVER22: "LockFile ${APACHE_LOCK_DIR}/accept.lock\n",
|
cls.APACHEVER22: "LockFile ${APACHE_LOCK_DIR}/accept.lock\n",
|
||||||
cls.APACHEVER24: "Mutex file:${APACHE_LOCK_DIR} default\n",
|
cls.APACHEVER24: "Mutex file:${APACHE_LOCK_DIR} default\n",
|
||||||
|
@ -421,22 +404,18 @@ class HttpService(UtilService):
|
||||||
cls.APACHEVER22: "",
|
cls.APACHEVER22: "",
|
||||||
cls.APACHEVER24: "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n",
|
cls.APACHEVER24: "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
permstr = {
|
permstr = {
|
||||||
cls.APACHEVER22: " Order allow,deny\n Deny from all\n Satisfy all\n",
|
cls.APACHEVER22: " Order allow,deny\n Deny from all\n Satisfy all\n",
|
||||||
cls.APACHEVER24: " Require all denied\n",
|
cls.APACHEVER24: " Require all denied\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
authstr = {
|
authstr = {
|
||||||
cls.APACHEVER22: "LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n",
|
cls.APACHEVER22: "LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n",
|
||||||
cls.APACHEVER24: "LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n",
|
cls.APACHEVER24: "LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
permstr2 = {
|
permstr2 = {
|
||||||
cls.APACHEVER22: "\t\tOrder allow,deny\n\t\tallow from all\n",
|
cls.APACHEVER22: "\t\tOrder allow,deny\n\t\tallow from all\n",
|
||||||
cls.APACHEVER24: "\t\tRequire all granted\n",
|
cls.APACHEVER24: "\t\tRequire all granted\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
version = cls.detectversionfromcmd()
|
version = cls.detectversionfromcmd()
|
||||||
cfg = "# apache2.conf generated by utility.py:HttpService\n"
|
cfg = "# apache2.conf generated by utility.py:HttpService\n"
|
||||||
cfg += lockstr[version]
|
cfg += lockstr[version]
|
||||||
|
@ -552,7 +531,7 @@ TraceEnable Off
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateenvvars(cls, node, filename):
|
def generateenvvars(cls, node: CoreNode, filename: str) -> str:
|
||||||
return """\
|
return """\
|
||||||
# this file is used by apache2ctl - generated by utility.py:HttpService
|
# this file is used by apache2ctl - generated by utility.py:HttpService
|
||||||
# these settings come from a default Ubuntu apache2 installation
|
# these settings come from a default Ubuntu apache2 installation
|
||||||
|
@ -567,7 +546,7 @@ export LANG
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatehtml(cls, node, filename):
|
def generatehtml(cls, node: CoreNode, filename: str) -> str:
|
||||||
body = (
|
body = (
|
||||||
"""\
|
"""\
|
||||||
<!-- generated by utility.py:HttpService -->
|
<!-- generated by utility.py:HttpService -->
|
||||||
|
@ -587,16 +566,15 @@ class PcapService(UtilService):
|
||||||
Pcap service for logging packets.
|
Pcap service for logging packets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "pcap"
|
name: str = "pcap"
|
||||||
configs = ("pcap.sh",)
|
configs: Tuple[str, ...] = ("pcap.sh",)
|
||||||
dirs = ()
|
startup: Tuple[str, ...] = ("sh pcap.sh start",)
|
||||||
startup = ("sh pcap.sh start",)
|
shutdown: Tuple[str, ...] = ("sh pcap.sh stop",)
|
||||||
shutdown = ("sh pcap.sh stop",)
|
validate: Tuple[str, ...] = ("pidof tcpdump",)
|
||||||
validate = ("pidof tcpdump",)
|
meta: str = "logs network traffic to pcap packet capture files"
|
||||||
meta = "logs network traffic to pcap packet capture files"
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a startpcap.sh traffic logging script.
|
Generate a startpcap.sh traffic logging script.
|
||||||
"""
|
"""
|
||||||
|
@ -630,15 +608,17 @@ fi;
|
||||||
|
|
||||||
|
|
||||||
class RadvdService(UtilService):
|
class RadvdService(UtilService):
|
||||||
name = "radvd"
|
name: str = "radvd"
|
||||||
configs = ("/etc/radvd/radvd.conf",)
|
configs: Tuple[str, ...] = ("/etc/radvd/radvd.conf",)
|
||||||
dirs = ("/etc/radvd",)
|
dirs: Tuple[str, ...] = ("/etc/radvd",)
|
||||||
startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",)
|
startup: Tuple[str, ...] = (
|
||||||
shutdown = ("pkill radvd",)
|
"radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",
|
||||||
validate = ("pidof radvd",)
|
)
|
||||||
|
shutdown: Tuple[str, ...] = ("pkill radvd",)
|
||||||
|
validate: Tuple[str, ...] = ("pidof radvd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a RADVD router advertisement daemon config file
|
Generate a RADVD router advertisement daemon config file
|
||||||
using the network address of each interface.
|
using the network address of each interface.
|
||||||
|
@ -678,7 +658,7 @@ interface %s
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def subnetentry(x):
|
def subnetentry(x: str) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a subnet declaration block given an IPv6 prefix string
|
Generate a subnet declaration block given an IPv6 prefix string
|
||||||
for inclusion in the RADVD config file.
|
for inclusion in the RADVD config file.
|
||||||
|
@ -695,14 +675,14 @@ class AtdService(UtilService):
|
||||||
Atd service for scheduling at jobs
|
Atd service for scheduling at jobs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "atd"
|
name: str = "atd"
|
||||||
configs = ("startatd.sh",)
|
configs: Tuple[str, ...] = ("startatd.sh",)
|
||||||
dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
|
dirs: Tuple[str, ...] = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
|
||||||
startup = ("sh startatd.sh",)
|
startup: Tuple[str, ...] = ("sh startatd.sh",)
|
||||||
shutdown = ("pkill atd",)
|
shutdown: Tuple[str, ...] = ("pkill atd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return """
|
return """
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo 00001 > /var/spool/cron/atjobs/.SEQ
|
echo 00001 > /var/spool/cron/atjobs/.SEQ
|
||||||
|
@ -717,5 +697,5 @@ class UserDefinedService(UtilService):
|
||||||
Dummy service allowing customization of anything.
|
Dummy service allowing customization of anything.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "UserDefined"
|
name: str = "UserDefined"
|
||||||
meta = "Customize this service to do anything upon startup."
|
meta: str = "Customize this service to do anything upon startup."
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
xorp.py: defines routing services provided by the XORP routing suite.
|
xorp.py: defines routing services provided by the XORP routing suite.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
|
from core.nodes.interface import CoreInterface
|
||||||
from core.services.coreservices import CoreService
|
from core.services.coreservices import CoreService
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,20 +17,20 @@ class XorpRtrmgr(CoreService):
|
||||||
enabled XORP services, and launches necessary daemons upon startup.
|
enabled XORP services, and launches necessary daemons upon startup.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "xorp_rtrmgr"
|
name: str = "xorp_rtrmgr"
|
||||||
executables = ("xorp_rtrmgr",)
|
group: str = "XORP"
|
||||||
group = "XORP"
|
executables: Tuple[str, ...] = ("xorp_rtrmgr",)
|
||||||
dirs = ("/etc/xorp",)
|
dirs: Tuple[str, ...] = ("/etc/xorp",)
|
||||||
configs = ("/etc/xorp/config.boot",)
|
configs: Tuple[str, ...] = ("/etc/xorp/config.boot",)
|
||||||
startup = (
|
startup: Tuple[str, ...] = (
|
||||||
"xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid"
|
"xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid"
|
||||||
% (configs[0], name, name),
|
% (configs[0], name, name),
|
||||||
)
|
)
|
||||||
shutdown = ("killall xorp_rtrmgr",)
|
shutdown: Tuple[str, ...] = ("killall xorp_rtrmgr",)
|
||||||
validate = ("pidof xorp_rtrmgr",)
|
validate: Tuple[str, ...] = ("pidof xorp_rtrmgr",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Returns config.boot configuration file text. Other services that
|
Returns config.boot configuration file text. Other services that
|
||||||
depend on this will have generatexorpconfig() hooks that are
|
depend on this will have generatexorpconfig() hooks that are
|
||||||
|
@ -45,16 +47,15 @@ class XorpRtrmgr(CoreService):
|
||||||
cfg += "}\n\n"
|
cfg += "}\n\n"
|
||||||
|
|
||||||
for s in node.services:
|
for s in node.services:
|
||||||
try:
|
if cls.name not in s.dependencies:
|
||||||
s.dependencies.index(cls.name)
|
continue
|
||||||
cfg += s.generatexorpconfig(node)
|
if not (isinstance(s, XorpService) or issubclass(s, XorpService)):
|
||||||
except ValueError:
|
continue
|
||||||
logging.exception("error getting value from service: %s", cls.name)
|
cfg += s.generate_xorp_config(node)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def addrstr(x):
|
def addrstr(x: str) -> str:
|
||||||
"""
|
"""
|
||||||
helper for mapping IP addresses to XORP config statements
|
helper for mapping IP addresses to XORP config statements
|
||||||
"""
|
"""
|
||||||
|
@ -65,7 +66,7 @@ class XorpRtrmgr(CoreService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lladdrstr(iface):
|
def lladdrstr(iface: CoreInterface) -> str:
|
||||||
"""
|
"""
|
||||||
helper for adding link-local address entries (required by OSPFv3)
|
helper for adding link-local address entries (required by OSPFv3)
|
||||||
"""
|
"""
|
||||||
|
@ -81,18 +82,16 @@ class XorpService(CoreService):
|
||||||
common to XORP's routing daemons.
|
common to XORP's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name: Optional[str] = None
|
||||||
executables = ("xorp_rtrmgr",)
|
group: str = "XORP"
|
||||||
group = "XORP"
|
executables: Tuple[str, ...] = ("xorp_rtrmgr",)
|
||||||
dependencies = ("xorp_rtrmgr",)
|
dependencies: Tuple[str, ...] = ("xorp_rtrmgr",)
|
||||||
dirs = ()
|
meta: str = (
|
||||||
configs = ()
|
"The config file for this service can be found in the xorp_rtrmgr service."
|
||||||
startup = ()
|
)
|
||||||
shutdown = ()
|
|
||||||
meta = "The config file for this service can be found in the xorp_rtrmgr service."
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fea(forwarding):
|
def fea(forwarding: str) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to add a forwarding engine entry to the config file.
|
Helper to add a forwarding engine entry to the config file.
|
||||||
"""
|
"""
|
||||||
|
@ -104,17 +103,14 @@ class XorpService(CoreService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mfea(forwarding, ifaces):
|
def mfea(forwarding, node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to add a multicast forwarding engine entry to the config file.
|
Helper to add a multicast forwarding engine entry to the config file.
|
||||||
"""
|
"""
|
||||||
names = []
|
names = []
|
||||||
for iface in ifaces:
|
for iface in node.get_ifaces(control=False):
|
||||||
if hasattr(iface, "control") and iface.control is True:
|
|
||||||
continue
|
|
||||||
names.append(iface.name)
|
names.append(iface.name)
|
||||||
names.append("register_vif")
|
names.append("register_vif")
|
||||||
|
|
||||||
cfg = "plumbing {\n"
|
cfg = "plumbing {\n"
|
||||||
cfg += " %s {\n" % forwarding
|
cfg += " %s {\n" % forwarding
|
||||||
for name in names:
|
for name in names:
|
||||||
|
@ -128,7 +124,7 @@ class XorpService(CoreService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def policyexportconnected():
|
def policyexportconnected() -> str:
|
||||||
"""
|
"""
|
||||||
Helper to add a policy statement for exporting connected routes.
|
Helper to add a policy statement for exporting connected routes.
|
||||||
"""
|
"""
|
||||||
|
@ -144,7 +140,7 @@ class XorpService(CoreService):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routerid(node):
|
def router_id(node: CoreNode) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
|
@ -153,15 +149,14 @@ class XorpService(CoreService):
|
||||||
a = a.split("/")[0]
|
a = a.split("/")[0]
|
||||||
if netaddr.valid_ipv4(a):
|
if netaddr.valid_ipv4(a):
|
||||||
return a
|
return a
|
||||||
# raise ValueError, "no IPv4 address found for router ID"
|
|
||||||
return "0.0.0.0"
|
return "0.0.0.0"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_config(cls, node, filename):
|
def generate_config(cls, node: CoreNode, filename: str) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,12 +167,12 @@ class XorpOspfv2(XorpService):
|
||||||
unified XORP configuration file.
|
unified XORP configuration file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_OSPFv2"
|
name: str = "XORP_OSPFv2"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.fea("unicast-forwarding4")
|
cfg = cls.fea("unicast-forwarding4")
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " ospf4 {\n"
|
cfg += " ospf4 {\n"
|
||||||
cfg += "\trouter-id: %s\n" % rtrid
|
cfg += "\trouter-id: %s\n" % rtrid
|
||||||
|
@ -206,12 +201,12 @@ class XorpOspfv3(XorpService):
|
||||||
unified XORP configuration file.
|
unified XORP configuration file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_OSPFv3"
|
name: str = "XORP_OSPFv3"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.fea("unicast-forwarding6")
|
cfg = cls.fea("unicast-forwarding6")
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " ospf6 0 { /* Instance ID 0 */\n"
|
cfg += " ospf6 0 { /* Instance ID 0 */\n"
|
||||||
cfg += "\trouter-id: %s\n" % rtrid
|
cfg += "\trouter-id: %s\n" % rtrid
|
||||||
|
@ -232,16 +227,16 @@ class XorpBgp(XorpService):
|
||||||
IPv4 inter-domain routing. AS numbers and peers must be customized.
|
IPv4 inter-domain routing. AS numbers and peers must be customized.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_BGP"
|
name: str = "XORP_BGP"
|
||||||
custom_needed = True
|
custom_needed: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = "/* This is a sample config that should be customized with\n"
|
cfg = "/* This is a sample config that should be customized with\n"
|
||||||
cfg += " appropriate AS numbers and peers */\n"
|
cfg += " appropriate AS numbers and peers */\n"
|
||||||
cfg += cls.fea("unicast-forwarding4")
|
cfg += cls.fea("unicast-forwarding4")
|
||||||
cfg += cls.policyexportconnected()
|
cfg += cls.policyexportconnected()
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " bgp {\n"
|
cfg += " bgp {\n"
|
||||||
cfg += "\tbgp-id: %s\n" % rtrid
|
cfg += "\tbgp-id: %s\n" % rtrid
|
||||||
|
@ -262,10 +257,10 @@ class XorpRip(XorpService):
|
||||||
RIP IPv4 unicast routing.
|
RIP IPv4 unicast routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_RIP"
|
name: str = "XORP_RIP"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.fea("unicast-forwarding4")
|
cfg = cls.fea("unicast-forwarding4")
|
||||||
cfg += cls.policyexportconnected()
|
cfg += cls.policyexportconnected()
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
|
@ -293,10 +288,10 @@ class XorpRipng(XorpService):
|
||||||
RIP NG IPv6 unicast routing.
|
RIP NG IPv6 unicast routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_RIPNG"
|
name: str = "XORP_RIPNG"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.fea("unicast-forwarding6")
|
cfg = cls.fea("unicast-forwarding6")
|
||||||
cfg += cls.policyexportconnected()
|
cfg += cls.policyexportconnected()
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
|
@ -320,12 +315,11 @@ class XorpPimSm4(XorpService):
|
||||||
PIM Sparse Mode IPv4 multicast routing.
|
PIM Sparse Mode IPv4 multicast routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_PIMSM4"
|
name: str = "XORP_PIMSM4"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.mfea("mfea4", node.get_ifaces())
|
cfg = cls.mfea("mfea4", node)
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " igmp {\n"
|
cfg += " igmp {\n"
|
||||||
names = []
|
names = []
|
||||||
|
@ -338,7 +332,6 @@ class XorpPimSm4(XorpService):
|
||||||
cfg += "\t}\n"
|
cfg += "\t}\n"
|
||||||
cfg += " }\n"
|
cfg += " }\n"
|
||||||
cfg += "}\n"
|
cfg += "}\n"
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " pimsm4 {\n"
|
cfg += " pimsm4 {\n"
|
||||||
|
|
||||||
|
@ -361,10 +354,8 @@ class XorpPimSm4(XorpService):
|
||||||
cfg += "\t\t}\n"
|
cfg += "\t\t}\n"
|
||||||
cfg += "\t }\n"
|
cfg += "\t }\n"
|
||||||
cfg += "\t}\n"
|
cfg += "\t}\n"
|
||||||
|
|
||||||
cfg += " }\n"
|
cfg += " }\n"
|
||||||
cfg += "}\n"
|
cfg += "}\n"
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " fib2mrib {\n"
|
cfg += " fib2mrib {\n"
|
||||||
cfg += "\tdisable: false\n"
|
cfg += "\tdisable: false\n"
|
||||||
|
@ -378,12 +369,11 @@ class XorpPimSm6(XorpService):
|
||||||
PIM Sparse Mode IPv6 multicast routing.
|
PIM Sparse Mode IPv6 multicast routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_PIMSM6"
|
name: str = "XORP_PIMSM6"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.mfea("mfea6", node.get_ifaces())
|
cfg = cls.mfea("mfea6", node)
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " mld {\n"
|
cfg += " mld {\n"
|
||||||
names = []
|
names = []
|
||||||
|
@ -396,7 +386,6 @@ class XorpPimSm6(XorpService):
|
||||||
cfg += "\t}\n"
|
cfg += "\t}\n"
|
||||||
cfg += " }\n"
|
cfg += " }\n"
|
||||||
cfg += "}\n"
|
cfg += "}\n"
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " pimsm6 {\n"
|
cfg += " pimsm6 {\n"
|
||||||
|
|
||||||
|
@ -419,10 +408,8 @@ class XorpPimSm6(XorpService):
|
||||||
cfg += "\t\t}\n"
|
cfg += "\t\t}\n"
|
||||||
cfg += "\t }\n"
|
cfg += "\t }\n"
|
||||||
cfg += "\t}\n"
|
cfg += "\t}\n"
|
||||||
|
|
||||||
cfg += " }\n"
|
cfg += " }\n"
|
||||||
cfg += "}\n"
|
cfg += "}\n"
|
||||||
|
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " fib2mrib {\n"
|
cfg += " fib2mrib {\n"
|
||||||
cfg += "\tdisable: false\n"
|
cfg += "\tdisable: false\n"
|
||||||
|
@ -436,12 +423,12 @@ class XorpOlsr(XorpService):
|
||||||
OLSR IPv4 unicast MANET routing.
|
OLSR IPv4 unicast MANET routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "XORP_OLSR"
|
name: str = "XORP_OLSR"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generate_xorp_config(cls, node: CoreNode) -> str:
|
||||||
cfg = cls.fea("unicast-forwarding4")
|
cfg = cls.fea("unicast-forwarding4")
|
||||||
rtrid = cls.routerid(node)
|
rtrid = cls.router_id(node)
|
||||||
cfg += "\nprotocols {\n"
|
cfg += "\nprotocols {\n"
|
||||||
cfg += " olsr4 {\n"
|
cfg += " olsr4 {\n"
|
||||||
cfg += "\tmain-address: %s\n" % rtrid
|
cfg += "\tmain-address: %s\n" % rtrid
|
||||||
|
|
Loading…
Reference in a new issue