initial commit after bringing over cleaned up code and testing some examples

This commit is contained in:
Blake J. Harnden 2017-04-25 08:45:34 -07:00
parent c4858e6e0d
commit 00f4ebf5a9
93 changed files with 15189 additions and 13083 deletions

View file

@ -1,6 +1,6 @@
"""Services
"""
Services
Services available to nodes can be put in this directory. Everything listed in
__all__ is automatically loaded by the main core module.
"""
__all__ = ["quagga", "nrl", "xorp", "bird", "utility", "security", "ucarp", "dockersvc", 'startup']

View file

@ -1,24 +1,15 @@
#
# CORE
# Copyright (c)2012 Jean-Tiare Le Bigot.
# See the LICENSE file included in this distribution.
#
# authors: Jean-Tiare Le Bigot <admin@jtlebi.fr>
# Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
"""
bird.py: defines routing services provided by the BIRD Internet Routing Daemon.
'''
"""
import os
from core.service import CoreService
from core.service import ServiceManager
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix
from core.constants import *
class Bird(CoreService):
''' Bird router support
'''
"""
Bird router support
"""
_name = "bird"
_group = "BIRD"
_depends = ()
@ -26,13 +17,14 @@ class Bird(CoreService):
_configs = ("/etc/bird/bird.conf",)
_startindex = 35
_startup = ("bird -c %s" % (_configs[0]),)
_shutdown = ("killall bird", )
_validate = ("pidof bird", )
_shutdown = ("killall bird",)
_validate = ("pidof bird",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the bird.conf file contents.
'''
"""
Return the bird.conf file contents.
"""
if filename == cls._configs[0]:
return cls.generateBirdConf(node, services)
else:
@ -40,28 +32,30 @@ class Bird(CoreService):
@staticmethod
def routerid(node):
''' 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.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a .split('/') [0]
#raise ValueError, "no IPv4 address found for router ID"
return a.split('/')[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@classmethod
def generateBirdConf(cls, node, services):
''' Returns configuration file text. Other services that depend on bird
will have generatebirdifcconfig() and generatebirdconfig()
hooks that are invoked here.
'''
cfg = """\
"""
Returns configuration file text. Other services that depend on bird
will have generatebirdifcconfig() and generatebirdconfig()
hooks that are invoked here.
"""
cfg = """\
/* Main configuration file for BIRD. This is ony a template,
* you will *need* to customize it according to your needs
* Beware that only double quotes \'"\' are valid. No singles. */
log "/var/log/%s.log" all;
#debug protocols all;
@ -90,14 +84,16 @@ protocol device {
return cfg
class BirdService(CoreService):
''' Parent class for Bird services. Defines properties and methods
"""
Parent class for Bird services. Defines properties and methods
common to Bird's routing daemons.
'''
"""
_name = "BirdDaemon"
_group = "BIRD"
_depends = ("bird", )
_depends = ("bird",)
_dirs = ()
_configs = ()
_startindex = 40
@ -106,7 +102,7 @@ class BirdService(CoreService):
_meta = "The config file for this service can be found in the bird service."
@classmethod
def generatebirdconfig(cls, node):
def generatebirdconfig(cls, node):
return ""
@classmethod
@ -118,20 +114,23 @@ class BirdService(CoreService):
cfg = ""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True: continue
cfg += ' interface "%s";\n'% ifc.name
if hasattr(ifc, 'control') and ifc.control == True:
continue
cfg += ' interface "%s";\n' % ifc.name
return cfg
class BirdBgp(BirdService):
'''BGP BIRD Service (configuration generation)'''
"""
BGP BIRD Service (configuration generation)
"""
_name = "BIRD_BGP"
_custom_needed = True
@classmethod
def generatebirdconfig(cls, node):
def generatebirdconfig(cls, node):
return """
/* This is a sample config that should be customized with appropriate AS numbers
* and peers; add one section like this for each neighbor */
@ -152,13 +151,16 @@ protocol bgp {
"""
class BirdOspf(BirdService):
'''OSPF BIRD Service (configuration generation)'''
"""
OSPF BIRD Service (configuration generation)
"""
_name = "BIRD_OSPFv2"
@classmethod
def generatebirdconfig(cls, node):
def generatebirdconfig(cls, node):
cfg = 'protocol ospf {\n'
cfg += ' export filter {\n'
cfg += ' if source = RTS_BGP then {\n'
@ -168,7 +170,7 @@ class BirdOspf(BirdService):
cfg += ' accept;\n'
cfg += ' };\n'
cfg += ' area 0.0.0.0 {\n'
cfg += cls.generatebirdifcconfig(node)
cfg += cls.generatebirdifcconfig(node)
cfg += ' };\n'
cfg += '}\n\n'
@ -176,17 +178,19 @@ class BirdOspf(BirdService):
class BirdRadv(BirdService):
'''RADV BIRD Service (configuration generation)'''
"""
RADV BIRD Service (configuration generation)
"""
_name = "BIRD_RADV"
@classmethod
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\n'
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\n'
cfg += 'protocol radv {\n'
cfg += ' # auto configuration on all interfaces\n'
cfg += cls.generatebirdifcconfig(node)
cfg += cls.generatebirdifcconfig(node)
cfg += ' # Advertise DNS\n'
cfg += ' rdnss {\n'
cfg += '# lifetime mult 10;\n'
@ -202,16 +206,18 @@ class BirdRadv(BirdService):
class BirdRip(BirdService):
'''RIP BIRD Service (configuration generation)'''
"""
RIP BIRD Service (configuration generation)
"""
_name = "BIRD_RIP"
@classmethod
def generatebirdconfig(cls, node):
def generatebirdconfig(cls, node):
cfg = 'protocol rip {\n'
cfg += ' period 10;\n'
cfg += ' garbage time 60;\n'
cfg += cls.generatebirdifcconfig(node)
cfg += cls.generatebirdifcconfig(node)
cfg += ' honor neighbor;\n'
cfg += ' authentication none;\n'
cfg += ' import all;\n'
@ -222,13 +228,15 @@ class BirdRip(BirdService):
class BirdStatic(BirdService):
'''Static Bird Service (configuration generation)'''
"""
Static Bird Service (configuration generation)
"""
_name = "BIRD_static"
_custom_needed = True
@classmethod
def generatebirdconfig(cls, node):
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\n'
cfg += 'protocol static {\n'
@ -240,10 +248,11 @@ class BirdStatic(BirdService):
return cfg
# Register all protocols
addservice(Bird)
addservice(BirdOspf)
addservice(BirdBgp)
#addservice(BirdRadv) # untested
addservice(BirdRip)
addservice(BirdStatic)
def load_services():
# Register all protocols
ServiceManager.add(Bird)
ServiceManager.add(BirdOspf)
ServiceManager.add(BirdBgp)
# ServiceManager.add(BirdRadv) # untested
ServiceManager.add(BirdRip)
ServiceManager.add(BirdStatic)

View file

@ -1,12 +1,5 @@
#
# CORE
# Copyright (c)2014 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# authors: Stuart Marsden
# Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
''' Docker service allows running docker containers within CORE nodes.
"""
Docker service allows running docker containers within CORE nodes.
The running of Docker within a CORE node allows for additional extensibility to
the CORE services. This allows network applications and protocols to be easily
@ -20,7 +13,7 @@ service to the Docker group. The image will then be auto run if that service is
selected.
This requires a recent version of Docker. This was tested using a PPA on Ubuntu
with version 1.2.0. The version in the standard Ubuntu repo is to old for
with version 1.2.0. The version in the standard Ubuntu repo is to old for
this purpose (we need --net host).
It also requires docker-py (https://pypi.python.org/pypi/docker-py) which can be
@ -47,13 +40,13 @@ The id will be different on your machine so use it in the following command:
sudo docker tag 4833487e66d2 stuartmarsden/multicastping:core
This image will be listed in the services after we restart the core-daemon:
This image will be listed in the services after we restart the core-daemon:
sudo service core-daemon restart
You can set up a simple network with a number of PCs connected to a switch. Set
the stuartmarsden/multicastping service for all the PCs. When started they will
all begin sending Multicast pings.
all begin sending Multicast pings.
In order to see what is happening you can go in to the terminal of a node and
look at the docker log. Easy shorthand is:
@ -89,11 +82,11 @@ Datagram 'Client: Ping' received from ('10.0.5.20', 8005)
Limitations:
1. Docker images must be downloaded on the host as usually a CORE node does not
1. Docker images must be downloaded on the host as usually a CORE node does not
have access to the internet.
2. Each node isolates running containers (keeps things simple)
3. Recent version of docker needed so that --net host can be used. This does
not further abstract the network within a node and allows multicast which
3. Recent version of docker needed so that --net host can be used. This does
not further abstract the network within a node and allows multicast which
is not enabled within Docker containers at the moment.
4. The core-daemon must be restarted for new images to show up.
5. A Docker-daemon is run within each node but the images are shared. This
@ -101,43 +94,46 @@ Limitations:
host. At startup all the nodes will try to access this and it will be locked
for most due to contention. The service just does a hackish wait for 1 second
and retry. This means all the docker containers can take a while to come up
depending on how many nodes you have.
depending on how many nodes you have.
"""
'''
from core.misc import log
from core.service import CoreService
from core.service import ServiceManager
logger = log.get_logger(__name__)
import os
import sys
try:
from docker import Client
except Exception:
pass
except ImportError:
logger.error("failure to import docker")
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix, IPv6Prefix
class DockerService(CoreService):
''' This is a service which will allow running docker containers in a CORE
node.
'''
"""
This is a service which will allow running docker containers in a CORE
node.
"""
_name = "Docker"
_group = "Docker"
_depends = ()
_dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',)
_configs = ('docker.sh', )
_configs = ('docker.sh',)
_startindex = 50
_startup = ('sh docker.sh',)
_shutdown = ('service docker stop', )
_shutdown = ('service docker stop',)
# Container image to start
_image = ""
@classmethod
def generateconfig(cls, node, filename, services):
''' Returns a string having contents of a docker.sh script that
can be modified to start a specific docker image.
'''
"""
Returns a string having contents of a docker.sh script that
can be modified to start a specific docker image.
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by Docker (docker.py)\n"
# Docker likes to think it has DNS set up or it complains.
# Docker likes to think it has DNS set up or it complains.
# Unless your network was attached to the Internet this is
# non-functional but hides error messages.
cfg += 'echo "nameserver 8.8.8.8" > /run/resolvconf/resolv.conf\n'
@ -156,27 +152,30 @@ until [ $result -eq 0 ]; do
# this is to alleviate contention to docker's SQLite database
sleep 0.3
done
""" % (cls._image, )
""" % (cls._image,)
return cfg
addservice(DockerService)
# This auto-loads Docker images having a :core tag, adding them to the list
# of services under the "Docker" group.
if 'Client' in globals():
client = Client(version='1.10')
images = client.images()
del client
else:
images = []
for image in images:
if u'<none>' in image['RepoTags'][0]:
continue
for repo in image['RepoTags']:
if u':core' not in repo:
def load_services():
ServiceManager.add(DockerService)
# This auto-loads Docker images having a :core tag, adding them to the list
# of services under the "Docker" group.
# TODO: change this logic, should be a proper configurable, or docker needs to be a required library
# TODO: also should make this call possible real time for reloading removing "magic" auto loading on import
if 'Client' in globals():
client = Client(version='1.10')
images = client.images()
del client
else:
images = []
for image in images:
if u'<none>' in image['RepoTags'][0]:
continue
dockerid = repo.encode('ascii','ignore').split(':')[0]
SubClass = type('SubClass', (DockerService,),
{'_name': dockerid, '_image': dockerid})
addservice(SubClass)
del images
for repo in image['RepoTags']:
if u':core' not in repo:
continue
dockerid = repo.encode('ascii', 'ignore').split(':')[0]
sub_class = type('SubClass', (DockerService,), {'_name': dockerid, '_image': dockerid})
ServiceManager.add(sub_class)
del images

View file

@ -1,24 +1,19 @@
#
# CORE
# Copyright (c)2010-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
"""
nrl.py: defines services provided by NRL protolib tools hosted here:
http://www.nrl.navy.mil/itd/ncs/products
'''
"""
from core.misc import utils
from core.misc.ipaddress import Ipv4Prefix
from core.service import CoreService
from core.service import ServiceManager
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix, IPv6Prefix
from core.misc.utils import *
from core.constants import *
class NrlService(CoreService):
''' Parent class for NRL services. Defines properties and methods
common to NRL's routing daemons.
'''
"""
Parent class for NRL services. Defines properties and methods
common to NRL's routing daemons.
"""""
_name = "Protean"
_group = "ProtoSvc"
_depends = ()
@ -29,108 +24,111 @@ class NrlService(CoreService):
_shutdown = ()
@classmethod
def generateconfig(cls, node, filename, services):
def generateconfig(cls, node, filename, services):
return ""
@staticmethod
def firstipv4prefix(node, prefixlen=24):
''' 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
interface's prefix length, so e.g. '/32' can turn into '/24'.
'''
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
addr = a.split('/')[0]
pre = IPv4Prefix("%s/%s" % (addr, prefixlen))
pre = Ipv4Prefix("%s/%s" % (addr, prefixlen))
return str(pre)
#raise ValueError, "no IPv4 address found"
# raise ValueError, "no IPv4 address found"
return "0.0.0.0/%s" % prefixlen
class MgenSinkService(NrlService):
_name = "MGEN_Sink"
_configs = ("sink.mgen", )
_configs = ("sink.mgen",)
_startindex = 5
_startup = ("mgen input sink.mgen", )
_validate = ("pidof mgen", )
_shutdown = ("killall mgen", )
_startup = ("mgen input sink.mgen",)
_validate = ("pidof mgen",)
_shutdown = ("killall mgen",)
@classmethod
def generateconfig(cls, node, filename, services):
cfg = "0.0 LISTEN UDP 5000\n"
for ifc in node.netifs():
name = sysctldevname(ifc.name)
name = utils.sysctldevname(ifc.name)
cfg += "0.0 Join 224.225.1.2 INTERFACE %s\n" % name
return cfg
@classmethod
def getstartup(cls, node, services):
cmd =cls._startup[0]
def getstartup(cls, node, services):
cmd = cls._startup[0]
cmd += " output /tmp/mgen_%s.log" % node.name
return (cmd, )
return cmd,
addservice(MgenSinkService)
class NrlNhdp(NrlService):
''' NeighborHood Discovery Protocol for MANET networks.
'''
"""
NeighborHood Discovery Protocol for MANET networks.
"""
_name = "NHDP"
_startup = ("nrlnhdp", )
_shutdown = ("killall nrlnhdp", )
_validate = ("pidof nrlnhdp", )
_startup = ("nrlnhdp",)
_shutdown = ("killall nrlnhdp",)
_validate = ("pidof nrlnhdp",)
@classmethod
def getstartup(cls, node, services):
''' Generate the appropriate command-line based on node interfaces.
'''
def getstartup(cls, node, services):
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls._startup[0]
cmd += " -l /var/log/nrlnhdp.log"
cmd += " -rpipe %s_nhdp" % node.name
servicenames = map(lambda x: x._name, services)
servicenames = map(lambda x: x._name, services)
if "SMF" in servicenames:
cmd += " -flooding ecds-etx sticky"
cmd += " -smfClient %s_smf" % node.name
netifs = filter(lambda x: not getattr(x, 'control', False), \
node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return (cmd, )
addservice(NrlNhdp)
return cmd,
class NrlSmf(NrlService):
''' Simplified Multicast Forwarding for MANET networks.
'''
"""
Simplified Multicast Forwarding for MANET networks.
"""
_name = "SMF"
_startup = ("sh startsmf.sh", )
_shutdown = ("killall nrlsmf", )
_validate = ("pidof nrlsmf", )
_configs = ("startsmf.sh", )
_startup = ("sh startsmf.sh",)
_shutdown = ("killall nrlsmf",)
_validate = ("pidof nrlsmf",)
_configs = ("startsmf.sh",)
@classmethod
def generateconfig(cls, node, filename, services):
''' 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
directly using vcmd.
'''
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by nrl.py:NrlSmf.generateconfig()\n"
comments = ""
cmd = "nrlsmf instance %s_smf" % (node.name)
cmd = "nrlsmf instance %s_smf" % node.name
servicenames = map(lambda x: x._name, services)
netifs = filter(lambda x: not getattr(x, 'control', False), \
node.netifs())
servicenames = map(lambda x: x._name, services)
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
if len(netifs) == 0:
return ()
if "arouted" in servicenames:
comments += "# arouted service is enabled\n"
cmd += " tap %s_tap" % (node.name,)
@ -145,29 +143,30 @@ class NrlSmf(NrlService):
cmd += " smpr "
else:
cmd += " cf "
interfacenames = map(lambda x: x.name, netifs)
interfacenames = map(lambda x: x.name, netifs)
cmd += ",".join(interfacenames)
cmd += " hash MD5"
cmd += " log /var/log/nrlsmf.log"
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
return cfg
addservice(NrlSmf)
class NrlOlsr(NrlService):
''' Optimized Link State Routing protocol for MANET networks.
'''
"""
Optimized Link State Routing protocol for MANET networks.
"""
_name = "OLSR"
_startup = ("nrlolsrd", )
_shutdown = ("killall nrlolsrd", )
_validate = ("pidof nrlolsrd", )
_startup = ("nrlolsrd",)
_shutdown = ("killall nrlolsrd",)
_validate = ("pidof nrlolsrd",)
@classmethod
def getstartup(cls, node, services):
''' Generate the appropriate command-line based on node interfaces.
'''
def getstartup(cls, node, services):
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls._startup[0]
# are multiple interfaces supported? No.
netifs = list(node.netifs())
@ -177,78 +176,80 @@ class NrlOlsr(NrlService):
cmd += " -l /var/log/nrlolsrd.log"
cmd += " -rpipe %s_olsr" % node.name
servicenames = map(lambda x: x._name, services)
servicenames = map(lambda x: x._name, services)
if "SMF" in servicenames and not "NHDP" in servicenames:
cmd += " -flooding s-mpr"
cmd += " -smfClient %s_smf" % node.name
if "zebra" in servicenames:
cmd += " -z"
return (cmd, )
addservice(NrlOlsr)
return cmd,
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"
_startup = ("nrlolsrv2", )
_shutdown = ("killall nrlolsrv2", )
_validate = ("pidof nrlolsrv2", )
_startup = ("nrlolsrv2",)
_shutdown = ("killall nrlolsrv2",)
_validate = ("pidof nrlolsrv2",)
@classmethod
def getstartup(cls, node, services):
''' Generate the appropriate command-line based on node interfaces.
'''
def getstartup(cls, node, services):
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls._startup[0]
cmd += " -l /var/log/nrlolsrv2.log"
cmd += " -rpipe %s_olsrv2" % node.name
servicenames = map(lambda x: x._name, services)
servicenames = map(lambda x: x._name, services)
if "SMF" in servicenames:
cmd += " -flooding ecds"
cmd += " -smfClient %s_smf" % node.name
cmd += " -p olsr"
netifs = filter(lambda x: not getattr(x, 'control', False), \
node.netifs())
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return (cmd, )
addservice(NrlOlsrv2)
return cmd,
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"
_configs = ("/etc/olsrd/olsrd.conf",)
_dirs = ("/etc/olsrd",)
_startup = ("olsrd", )
_shutdown = ("killall olsrd", )
_validate = ("pidof olsrd", )
_startup = ("olsrd",)
_shutdown = ("killall olsrd",)
_validate = ("pidof olsrd",)
@classmethod
def getstartup(cls, node, services):
''' Generate the appropriate command-line based on node interfaces.
'''
def getstartup(cls, node, services):
"""
Generate the appropriate command-line based on node interfaces.
"""
cmd = cls._startup[0]
netifs = filter(lambda x: not getattr(x, 'control', False), \
node.netifs())
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
if len(netifs) > 0:
interfacenames = map(lambda x: x.name, netifs)
cmd += " -i "
cmd += " -i ".join(interfacenames)
return (cmd, )
return cmd,
@classmethod
def generateconfig(cls, node, filename, services):
''' 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 = """\
#
# OLSR.org routing daemon config file
@ -314,7 +315,7 @@ class OlsrOrg(NrlService):
# 1 gets remapped by olsrd to 0 UNSPECIFIED (1 is reserved for ICMP redirects)
# 2 KERNEL routes (not very wise to use)
# 3 BOOT (should in fact not be used by routing daemons)
# 4 STATIC
# 4 STATIC
# 8 .. 15 various routing daemons (gated, zebra, bird, & co)
# (defaults to 0 which gets replaced by an OS-specific default value
# under linux 3 (BOOT) (for backward compatibility)
@ -510,7 +511,7 @@ LinkQualityFishEye 0
# Olsrd plugins to load
# This must be the absolute path to the file
# or the loader will use the following scheme:
# - Try the paths in the LD_LIBRARY_PATH
# - Try the paths in the LD_LIBRARY_PATH
# environment variable.
# - The list of libraries cached in /etc/ld.so.cache
# - /lib, followed by /usr/lib
@ -566,11 +567,11 @@ InterfaceDefaults {
"""
return cfg
addservice(OlsrOrg)
class MgenActor(NrlService):
''' ZpcMgenActor.
'''
"""
ZpcMgenActor.
"""
# a unique name is required, without spaces
_name = "MgenActor"
@ -582,53 +583,53 @@ class MgenActor(NrlService):
_dirs = ()
# generated files (without a full path this file goes in the node's dir,
# e.g. /tmp/pycore.12345/n1.conf/)
_configs = ('start_mgen_actor.sh', )
_configs = ('start_mgen_actor.sh',)
# this controls the starting order vs other enabled services
_startindex = 50
# list of startup commands, also may be generated during startup
_startup = ("sh start_mgen_actor.sh", )
_startup = ("sh start_mgen_actor.sh",)
# list of validation commands
_validate = ("pidof mgen", )
_validate = ("pidof mgen",)
# list of shutdown commands
_shutdown = ("killall mgen", )
_shutdown = ("killall mgen",)
@classmethod
def generateconfig(cls, node, filename, services):
''' 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
directly using vcmd.
'''
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by nrl.py:MgenActor.generateconfig()\n"
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
servicenames = map(lambda x: x._name, services)
netifs = filter(lambda x: not getattr(x, 'control', False), \
node.netifs())
servicenames = map(lambda x: x._name, services)
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
if len(netifs) == 0:
return ()
cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n"
return cfg
# this line is required to add the above class to the list of available services
addservice(MgenActor)
class Arouted(NrlService):
''' Adaptive Routing
'''
"""
Adaptive Routing
"""
_name = "arouted"
_configs = ("startarouted.sh", )
_configs = ("startarouted.sh",)
_startindex = NrlService._startindex + 10
_startup = ("sh startarouted.sh", )
_shutdown = ("pkill arouted", )
_validate = ("pidof arouted", )
_startup = ("sh startarouted.sh",)
_shutdown = ("pkill arouted",)
_validate = ("pidof arouted",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the Quagga.conf or quaggaboot.sh file contents.
'''
"""
Return the Quagga.conf or quaggaboot.sh file contents.
"""
cfg = """
#!/bin/sh
for f in "/tmp/%s_smf"; do
@ -643,12 +644,23 @@ for f in "/tmp/%s_smf"; do
done
done
""" % (node.name)
""" % node.name
cfg += "ip route add %s dev lo\n" % cls.firstipv4prefix(node, 24)
cfg += "arouted instance %s_smf tap %s_tap" % (node.name, node.name)
cfg += " stability 10" # seconds to consider a new route valid
# seconds to consider a new route valid
cfg += " stability 10"
cfg += " 2>&1 > /var/log/arouted.log &\n\n"
return cfg
# experimental
#addservice(Arouted)
def load_services():
ServiceManager.add(MgenSinkService)
ServiceManager.add(NrlNhdp)
ServiceManager.add(NrlSmf)
ServiceManager.add(NrlOlsr)
ServiceManager.add(NrlOlsrv2)
ServiceManager.add(OlsrOrg)
# this line is required to add the above class to the list of available services
ServiceManager.add(MgenActor)
# experimental
# ServiceManager.add(Arouted)

View file

@ -1,48 +1,39 @@
#
# CORE
# Copyright (c)2010-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
quagga.py: defines routing services provided by Quagga.
'''
"""
quagga.py: defines routing services provided by Quagga.
"""
import os
if os.uname()[0] == "Linux":
from core.netns import nodes
elif os.uname()[0] == "FreeBSD":
from core.bsd import nodes
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix, isIPv4Address, isIPv6Address
from core.api import coreapi
from core.constants import *
from core import constants
from core.enumerations import LinkTypes, NodeTypes
from core.misc import ipaddress
from core.misc import nodeutils
from core.service import CoreService
from core.service import ServiceManager
QUAGGA_USER="root"
QUAGGA_GROUP="root"
QUAGGA_USER = "root"
QUAGGA_GROUP = "root"
if os.uname()[0] == "FreeBSD":
QUAGGA_GROUP="wheel"
QUAGGA_GROUP = "wheel"
class Zebra(CoreService):
'''
'''
_name = "zebra"
_group = "Quagga"
_depends = ("vtysh", )
_dirs = ("/usr/local/etc/quagga", "/var/run/quagga")
_depends = ("vtysh",)
_dirs = ("/usr/local/etc/quagga", "/var/run/quagga")
_configs = ("/usr/local/etc/quagga/Quagga.conf",
"quaggaboot.sh","/usr/local/etc/quagga/vtysh.conf")
"quaggaboot.sh", "/usr/local/etc/quagga/vtysh.conf")
_startindex = 35
_startup = ("sh quaggaboot.sh zebra",)
_shutdown = ("killall zebra", )
_validate = ("pidof zebra", )
_shutdown = ("killall zebra",)
_validate = ("pidof zebra",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the Quagga.conf or quaggaboot.sh file contents.
'''
"""
Return the Quagga.conf or quaggaboot.sh file contents.
"""
if filename == cls._configs[0]:
return cls.generateQuaggaConf(node, services)
elif filename == cls._configs[1]:
@ -51,19 +42,21 @@ class Zebra(CoreService):
return cls.generateVtyshConf(node, services)
else:
raise ValueError
@classmethod
def generateVtyshConf(cls, node, services):
''' Returns configuration file text.
'''
"""
Returns configuration file text.
"""
return "service integrated-vtysh-config\n"
@classmethod
def generateQuaggaConf(cls, node, services):
''' Returns configuration file text. Other services that depend on zebra
will have generatequaggaifcconfig() and generatequaggaconfig()
hooks that are invoked here.
'''
"""
Returns configuration file text. Other services that depend on zebra
will have generatequaggaifcconfig() and generatequaggaconfig()
hooks that are invoked here.
"""
# we could verify here that filename == Quagga.conf
cfg = ""
for ifc in node.netifs():
@ -81,7 +74,7 @@ class Zebra(CoreService):
for s in services:
if cls._name not in s._depends:
continue
ifccfg = s.generatequaggaifcconfig(node, ifc)
ifccfg = s.generatequaggaifcconfig(node, ifc)
if s._ipv4_routing:
want_ipv4 = True
if s._ipv6_routing:
@ -89,47 +82,47 @@ class Zebra(CoreService):
cfgv6 += ifccfg
else:
cfgv4 += ifccfg
if want_ipv4:
ipv4list = filter(lambda x: isIPv4Address(x.split('/')[0]),
ifc.addrlist)
ipv4list = filter(lambda x: ipaddress.is_ipv4_address(x.split('/')[0]), ifc.addrlist)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv4list))
cfg += "\n"
cfg += cfgv4
if want_ipv6:
ipv6list = filter(lambda x: isIPv6Address(x.split('/')[0]),
ifc.addrlist)
ipv6list = filter(lambda x: ipaddress.is_ipv6_address(x.split('/')[0]), ifc.addrlist)
cfg += " "
cfg += "\n ".join(map(cls.addrstr, ipv6list))
cfg += "\n"
cfg += cfgv6
cfg += "!\n"
for s in services:
if cls._name not in s._depends:
continue
cfg += s.generatequaggaconfig(node)
return cfg
@staticmethod
def addrstr(x):
''' helper for mapping IP addresses to zebra config statements
'''
"""
helper for mapping IP addresses to zebra config statements
"""
if x.find(".") >= 0:
return "ip address %s" % x
elif x.find(":") >= 0:
return "ipv6 address %s" % x
else:
raise Value, "invalid address: %s", x
raise ValueError("invalid address: %s", x)
@classmethod
def generateQuaggaBoot(cls, node, services):
''' Generate a shell script used to boot the Quagga daemons.
'''
"""
Generate a shell script used to boot the Quagga daemons.
"""
try:
quagga_bin_search = node.session.cfg['quagga_bin_search']
quagga_sbin_search = node.session.cfg['quagga_sbin_search']
quagga_bin_search = node.session.config['quagga_bin_search']
quagga_sbin_search = node.session.config['quagga_sbin_search']
except KeyError:
quagga_bin_search = '"/usr/local/bin /usr/bin /usr/lib/quagga"'
quagga_sbin_search = '"/usr/local/sbin /usr/sbin /usr/lib/quagga"'
@ -182,7 +175,7 @@ waitforvtyfiles()
sleep 0.1
count=$(($count + 1))
done
done
done
}
bootdaemon()
@ -243,85 +236,87 @@ elif [ "$1" = "vtysh" ]; then
else
bootdaemon $1
fi
""" % (cls._configs[0], quagga_sbin_search, quagga_bin_search, \
QUAGGA_STATE_DIR, QUAGGA_USER, QUAGGA_GROUP)
""" % (cls._configs[0], quagga_sbin_search, quagga_bin_search, constants.QUAGGA_STATE_DIR, QUAGGA_USER, QUAGGA_GROUP)
addservice(Zebra)
class QuaggaService(CoreService):
''' Parent class for Quagga services. Defines properties and methods
common to Quagga's routing daemons.
'''
"""
Parent class for Quagga services. Defines properties and methods
common to Quagga's routing daemons.
"""
_name = "QuaggaDaemon"
_group = "Quagga"
_depends = ("zebra", )
_depends = ("zebra",)
_dirs = ()
_configs = ()
_startindex = 40
_startup = ()
_shutdown = ()
_meta = "The config file for this service can be found in the Zebra service."
_ipv4_routing = False
_ipv6_routing = False
@staticmethod
def routerid(node):
''' 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.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a .split('/') [0]
#raise ValueError, "no IPv4 address found for router ID"
return a.split('/')[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@staticmethod
def rj45check(ifc):
''' Helper to detect whether interface is connected an external RJ45
"""
Helper to detect whether interface is connected an external RJ45
link.
'''
"""
if ifc.net:
for peerifc in ifc.net.netifs():
if peerifc == ifc:
continue
if isinstance(peerifc, nodes.RJ45Node):
if nodeutils.is_node(peerifc, NodeTypes.RJ45):
return True
return False
@classmethod
def generateconfig(cls, node, filename, services):
def generateconfig(cls, node, filename, services):
return ""
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
def generatequaggaifcconfig(cls, node, ifc):
return ""
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
return ""
class Ospfv2(QuaggaService):
''' The OSPFv2 service provides IPv4 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
'''
"""
The OSPFv2 service provides IPv4 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
_name = "OSPFv2"
_startup = ("sh quaggaboot.sh ospfd",)
_shutdown = ("killall ospfd", )
_validate = ("pidof ospfd", )
_shutdown = ("killall ospfd",)
_validate = ("pidof ospfd",)
_ipv4_routing = True
@staticmethod
def mtucheck(ifc):
''' 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
GreTap device.
'''
"""
if ifc.mtu != 1500:
# a workaround for PhysicalNode GreTap, which has no knowledge of
# the other nodes/nets
@ -335,64 +330,68 @@ class Ospfv2(QuaggaService):
@staticmethod
def ptpcheck(ifc):
''' Helper to detect whether interface is connected to a notional
"""
Helper to detect whether interface is connected to a notional
point-to-point link.
'''
if isinstance(ifc.net, nodes.PtpNet):
"""
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER):
return " ip ospf network point-to-point\n"
return ""
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = "router ospf\n"
rtrid = cls.routerid(node)
cfg += " router-id %s\n" % rtrid
# network 10.0.0.0/24 area 0
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") < 0:
continue
net = IPv4Prefix(a)
net = ipaddress.Ipv4Prefix(a)
cfg += " network %s area 0\n" % net
cfg += "!\n"
cfg += "!\n"
return cfg
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
return cls.mtucheck(ifc)
#cfg = cls.mtucheck(ifc)
# external RJ45 connections will use default OSPF timers
#if cls.rj45check(ifc):
# return cfg
#cfg += cls.ptpcheck(ifc)
#return cfg + """\
# ip ospf hello-interval 2
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
return cls.mtucheck(ifc)
# cfg = cls.mtucheck(ifc)
# external RJ45 connections will use default OSPF timers
# if cls.rj45check(ifc):
# return cfg
# cfg += cls.ptpcheck(ifc)
# return cfg + """\
# ip ospf hello-interval 2
# ip ospf dead-interval 6
# ip ospf retransmit-interval 5
#"""
addservice(Ospfv2)
# """
class Ospfv3(QuaggaService):
''' The OSPFv3 service provides IPv6 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
'''
"""
The OSPFv3 service provides IPv6 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
_name = "OSPFv3"
_startup = ("sh quaggaboot.sh ospf6d",)
_shutdown = ("killall ospf6d", )
_validate = ("pidof ospf6d", )
_shutdown = ("killall ospf6d",)
_validate = ("pidof ospf6d",)
_ipv4_routing = True
_ipv6_routing = True
@staticmethod
def minmtu(ifc):
''' Helper to discover the minimum MTU of interfaces linked with the
"""
Helper to discover the minimum MTU of interfaces linked with the
given interface.
'''
"""
mtu = ifc.mtu
if not ifc.net:
return mtu
@ -400,13 +399,14 @@ class Ospfv3(QuaggaService):
if i.mtu < mtu:
mtu = i.mtu
return mtu
@classmethod
def mtucheck(cls, ifc):
''' 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
GreTap device.
'''
"""
minmtu = cls.minmtu(ifc)
if minmtu < ifc.mtu:
return " ipv6 ospf6 ifmtu %d\n" % minmtu
@ -415,57 +415,59 @@ class Ospfv3(QuaggaService):
@staticmethod
def ptpcheck(ifc):
''' Helper to detect whether interface is connected to a notional
"""
Helper to detect whether interface is connected to a notional
point-to-point link.
'''
if isinstance(ifc.net, nodes.PtpNet):
"""
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER):
return " ipv6 ospf6 network point-to-point\n"
return ""
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = "router ospf6\n"
rtrid = cls.routerid(node)
cfg += " router-id %s\n" % rtrid
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += " interface %s area 0.0.0.0\n" % ifc.name
cfg += "!\n"
return cfg
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
return cls.mtucheck(ifc)
#cfg = cls.mtucheck(ifc)
# external RJ45 connections will use default OSPF timers
#if cls.rj45check(ifc):
# return cfg
#cfg += cls.ptpcheck(ifc)
#return cfg + """\
# ipv6 ospf6 hello-interval 2
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
return cls.mtucheck(ifc)
# cfg = cls.mtucheck(ifc)
# external RJ45 connections will use default OSPF timers
# if cls.rj45check(ifc):
# return cfg
# cfg += cls.ptpcheck(ifc)
# return cfg + """\
# ipv6 ospf6 hello-interval 2
# ipv6 ospf6 dead-interval 6
# ipv6 ospf6 retransmit-interval 5
#"""
# """
addservice(Ospfv3)
class Ospfv3mdr(Ospfv3):
''' The OSPFv3 MANET Designated Router (MDR) service provides IPv6
routing for wireless networks. It does not build its own
configuration file but has hooks for adding to the
unified Quagga.conf file.
'''
"""
The OSPFv3 MANET Designated Router (MDR) service provides IPv6
routing for wireless networks. It does not build its own
configuration file but has hooks for adding to the
unified Quagga.conf file.
"""
_name = "OSPFv3MDR"
_ipv4_routing = True
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
def generatequaggaifcconfig(cls, node, ifc):
cfg = cls.mtucheck(ifc)
cfg += " ipv6 ospf6 instance-id 65\n"
if ifc.net is not None and \
isinstance(ifc.net, (nodes.WlanNode, nodes.EmaneNode)):
if ifc.net is not None and nodeutils.is_node(ifc.net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
return cfg + """\
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 6
@ -478,23 +480,23 @@ class Ospfv3mdr(Ospfv3):
else:
return cfg
addservice(Ospfv3mdr)
class Bgp(QuaggaService):
'''' The BGP service provides interdomain routing.
Peers must be manually configured, with a full mesh for those
having the same AS number.
'''
"""
The BGP service provides interdomain routing.
Peers must be manually configured, with a full mesh for those
having the same AS number.
"""
_name = "BGP"
_startup = ("sh quaggaboot.sh bgpd",)
_shutdown = ("killall bgpd", )
_validate = ("pidof bgpd", )
_shutdown = ("killall bgpd",)
_validate = ("pidof bgpd",)
_custom_needed = True
_ipv4_routing = True
_ipv6_routing = True
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = "!\n! BGP configuration\n!\n"
cfg += "! You should configure the AS number below,\n"
cfg += "! along with this router's peers.\n!\n"
@ -505,19 +507,19 @@ class Bgp(QuaggaService):
cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n"
return cfg
addservice(Bgp)
class Rip(QuaggaService):
''' The RIP service provides IPv4 routing for wired networks.
'''
"""
The RIP service provides IPv4 routing for wired networks.
"""
_name = "RIP"
_startup = ("sh quaggaboot.sh ripd",)
_shutdown = ("killall ripd", )
_validate = ("pidof ripd", )
_shutdown = ("killall ripd",)
_validate = ("pidof ripd",)
_ipv4_routing = True
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = """\
router rip
redistribute static
@ -528,19 +530,19 @@ router rip
"""
return cfg
addservice(Rip)
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"
_startup = ("sh quaggaboot.sh ripngd",)
_shutdown = ("killall ripngd", )
_validate = ("pidof ripngd", )
_shutdown = ("killall ripngd",)
_validate = ("pidof ripngd",)
_ipv6_routing = True
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = """\
router ripng
redistribute static
@ -551,50 +553,49 @@ router ripng
"""
return cfg
addservice(Ripng)
class Babel(QuaggaService):
''' The Babel service provides a loop-avoiding distance-vector routing
"""
The Babel service provides a loop-avoiding distance-vector routing
protocol for IPv6 and IPv4 with fast convergence properties.
'''
"""
_name = "Babel"
_startup = ("sh quaggaboot.sh babeld",)
_shutdown = ("killall babeld", )
_validate = ("pidof babeld", )
_shutdown = ("killall babeld",)
_validate = ("pidof babeld",)
_ipv6_routing = True
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
cfg = "router babel\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += " network %s\n" % ifc.name
cfg += " redistribute static\n redistribute connected\n"
return cfg
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
def generatequaggaifcconfig(cls, node, ifc):
type = "wired"
if ifc.net and ifc.net.linktype == coreapi.CORE_LINK_WIRELESS:
if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS.value:
return " babel wireless\n no babel split-horizon\n"
else:
return " babel wired\n babel split-horizon\n"
addservice(Babel)
class Xpimd(QuaggaService):
'''\
"""
PIM multicast routing based on XORP.
'''
"""
_name = 'Xpimd'
_startup = ('sh quaggaboot.sh xpimd',)
_shutdown = ('killall xpimd', )
_validate = ('pidof xpimd', )
_shutdown = ('killall xpimd',)
_validate = ('pidof xpimd',)
_ipv4_routing = True
@classmethod
def generatequaggaconfig(cls, node):
def generatequaggaconfig(cls, node):
ifname = 'eth0'
for ifc in node.netifs():
if ifc.name != 'lo':
@ -610,15 +611,15 @@ class Xpimd(QuaggaService):
return cfg
@classmethod
def generatequaggaifcconfig(cls, node, ifc):
def generatequaggaifcconfig(cls, node, ifc):
return ' ip mfea\n ip igmp\n ip pim\n'
addservice(Xpimd)
class Vtysh(CoreService):
''' Simple service to run vtysh -b (boot) after all Quagga daemons have
started.
'''
"""
Simple service to run vtysh -b (boot) after all Quagga daemons have
started.
"""
_name = "vtysh"
_group = "Quagga"
_startindex = 45
@ -629,6 +630,15 @@ class Vtysh(CoreService):
def generateconfig(cls, node, filename, services):
return ""
addservice(Vtysh)
def load_services():
ServiceManager.add(Zebra)
ServiceManager.add(Ospfv2)
ServiceManager.add(Ospfv3)
ServiceManager.add(Ospfv3mdr)
ServiceManager.add(Bgp)
ServiceManager.add(Rip)
ServiceManager.add(Ripng)
ServiceManager.add(Babel)
ServiceManager.add(Xpimd)
ServiceManager.add(Vtysh)

View file

@ -1,83 +1,75 @@
#
# CORE - define security services : vpnclient, vpnserver, ipsec and firewall
#
# Copyright (c)2011-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
'''
security.py: defines security services (vpnclient, vpnserver, ipsec and
"""
security.py: defines security services (vpnclient, vpnserver, ipsec and
firewall)
'''
"""
import os
from core import constants
from core.misc import log
from core.service import CoreService
from core.service import ServiceManager
logger = log.get_logger(__name__)
from core.service import CoreService, addservice
from core.constants import *
class VPNClient(CoreService):
'''
'''
_name = "VPNClient"
_group = "Security"
_configs = ('vpnclient.sh', )
_configs = ('vpnclient.sh',)
_startindex = 60
_startup = ('sh vpnclient.sh',)
_shutdown = ("killall openvpn",)
_validate = ("pidof openvpn", )
_validate = ("pidof openvpn",)
_custom_needed = True
@classmethod
def generateconfig(cls, node, filename, services):
''' 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 += "# custom VPN Client configuration for service (security.py)\n"
fname = "%s/examples/services/sampleVPNClient" % CORE_DATA_DIR
fname = "%s/examples/services/sampleVPNClient" % constants.CORE_DATA_DIR
try:
cfg += open(fname, "rb").read()
except e:
print "Error opening VPN client configuration template (%s): %s" % \
(fname, e)
except IOError:
logger.exception("Error opening VPN client configuration template (%s)", fname)
return cfg
# this line is required to add the above class to the list of available services
addservice(VPNClient)
class VPNServer(CoreService):
'''
'''
_name = "VPNServer"
_group = "Security"
_configs = ('vpnserver.sh', )
_configs = ('vpnserver.sh',)
_startindex = 50
_startup = ('sh vpnserver.sh',)
_shutdown = ("killall openvpn",)
_validate = ("pidof openvpn", )
_validate = ("pidof openvpn",)
_custom_needed = True
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the sample server.conf and vpnserver.sh file contents to
GUI for user customization.
'''
"""
Return the sample server.conf and vpnserver.sh file contents to
GUI for user customization.
"""
cfg = "#!/bin/sh\n"
cfg += "# custom VPN Server Configuration for service (security.py)\n"
fname = "%s/examples/services/sampleVPNServer" % CORE_DATA_DIR
fname = "%s/examples/services/sampleVPNServer" % constants.CORE_DATA_DIR
try:
cfg += open(fname, "rb").read()
except e:
print "Error opening VPN server configuration template (%s): %s" % \
(fname, e)
except IOError:
logger.exception("Error opening VPN server configuration template (%s)", fname)
return cfg
addservice(VPNServer)
class IPsec(CoreService):
'''
'''
_name = "IPsec"
_group = "Security"
_configs = ('ipsec.sh', )
_configs = ('ipsec.sh',)
_startindex = 60
_startup = ('sh ipsec.sh',)
_shutdown = ("killall racoon",)
@ -85,45 +77,51 @@ class IPsec(CoreService):
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the ipsec.conf and racoon.conf file contents to
GUI for user customization.
'''
"""
Return the ipsec.conf and racoon.conf file contents to
GUI for user customization.
"""
cfg = "#!/bin/sh\n"
cfg += "# set up static tunnel mode security assocation for service "
cfg += "(security.py)\n"
fname = "%s/examples/services/sampleIPsec" % CORE_DATA_DIR
fname = "%s/examples/services/sampleIPsec" % constants.CORE_DATA_DIR
try:
cfg += open(fname, "rb").read()
except e:
print "Error opening IPsec configuration template (%s): %s" % \
(fname, e)
except IOError:
logger.exception("Error opening IPsec configuration template (%s)", fname)
return cfg
addservice(IPsec)
class Firewall(CoreService):
'''
'''
_name = "Firewall"
_group = "Security"
_configs = ('firewall.sh', )
_configs = ('firewall.sh',)
_startindex = 20
_startup = ('sh firewall.sh',)
_custom_needed = True
@classmethod
def generateconfig(cls, node, filename, services):
''' 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 += "# custom node firewall rules for service (security.py)\n"
fname = "%s/examples/services/sampleFirewall" % CORE_DATA_DIR
fname = "%s/examples/services/sampleFirewall" % constants.CORE_DATA_DIR
try:
cfg += open(fname, "rb").read()
except e:
print "Error opening Firewall configuration template (%s): %s" % \
(fname, e)
except IOError:
logger.exception("Error opening Firewall configuration template (%s)", fname)
return cfg
addservice(Firewall)
def load_services():
# this line is required to add the above class to the list of available services
ServiceManager.add(VPNClient)
ServiceManager.add(VPNServer)
ServiceManager.add(IPsec)
ServiceManager.add(Firewall)

View file

@ -1,23 +1,27 @@
from core.service import CoreService, addservice
from sys import maxint
from inspect import isclass
from sys import maxint
from core.service import CoreService
from core.service import ServiceManager
class Startup(CoreService):
'A CORE service to start other services in order, serially'
"""
A CORE service to start other services in order, serially
"""
_name = 'startup'
_group = 'Utility'
_depends = ()
_dirs = ()
_configs = ('startup.sh', )
_configs = ('startup.sh',)
_startindex = maxint
_startup = ('sh startup.sh', )
_startup = ('sh startup.sh',)
_shutdown = ()
_validate = ()
@staticmethod
def isStartupService(s):
return isinstance(s, Startup) or \
(isclass(s) and issubclass(s, Startup))
def is_startup_service(s):
return isinstance(s, Startup) or (isclass(s) and issubclass(s, Startup))
@classmethod
def generateconfig(cls, node, filename, services):
@ -26,12 +30,14 @@ class Startup(CoreService):
script = '#!/bin/sh\n' \
'# auto-generated by Startup (startup.py)\n\n' \
'exec > startup.log 2>&1\n\n'
for s in sorted(services, key = lambda x: x._startindex):
if cls.isStartupService(s) or len(str(s._starttime)) > 0:
for s in sorted(services, key=lambda x: x._startindex):
if cls.is_startup_service(s) or len(str(s._starttime)) > 0:
continue
start = '\n'.join(s.getstartup(node, services))
if start:
script += start + '\n'
return script
addservice(Startup)
def load_services():
ServiceManager.add(Startup)

View file

@ -1,189 +1,185 @@
#
# CORE configuration for UCARP
# Copyright (c) 2012 Jonathan deBoer
# See the LICENSE file included in this distribution.
#
#
# author: Jonathan deBoer <jdccdevel@gmail.com>
#
'''
ucarp.py: defines high-availability IP address controlled by ucarp
'''
import os
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix
from core.constants import *
UCARP_ETC="/usr/local/etc/ucarp"
class Ucarp(CoreService):
'''
'''
_name = "ucarp"
_group = "Utility"
_depends = ( )
_dirs = (UCARP_ETC, )
_configs = (UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",)
_startindex = 65
_startup = ("sh ucarpboot.sh",)
_shutdown = ("killall ucarp", )
_validate = ("pidof ucarp", )
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the default file contents
'''
if filename == cls._configs[0]:
return cls.generateUcarpConf(node, services)
elif filename == cls._configs[1]:
return cls.generateVipUp(node, services)
elif filename == cls._configs[2]:
return cls.generateVipDown(node, services)
elif filename == cls._configs[3]:
return cls.generateUcarpBoot(node, services)
else:
raise ValueError
@classmethod
def generateUcarpConf(cls, node, services):
''' Returns configuration file text.
'''
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/sh
# Location of UCARP executable
UCARP_EXEC=%s
# Location of the UCARP config directory
UCARP_CFGDIR=%s
# Logging Facility
FACILITY=daemon
# Instance ID
# Any number from 1 to 255
INSTANCE_ID=1
# Password
# Master and Backup(s) need to be the same
PASSWORD="changeme"
# The failover application address
VIRTUAL_ADDRESS=127.0.0.254
VIRTUAL_NET=8
# Interface for IP Address
INTERFACE=lo
# Maintanence address of the local machine
SOURCE_ADDRESS=127.0.0.1
# The ratio number to be considered before marking the node as dead
DEAD_RATIO=3
# UCARP base, lower number will be preferred master
# set to same to have master stay as long as possible
UCARP_BASE=1
SKEW=0
# UCARP options
# -z run shutdown script on exit
# -P force preferred master
# -n don't run down script at start up when we are backup
# -M use broadcast instead of multicast
# -S ignore interface state
OPTIONS="-z -n -M"
# Send extra parameter to down and up scripts
#XPARAM="-x <enter param here>"
XPARAM="-x ${VIRTUAL_NET}"
# The start and stop scripts
START_SCRIPT=${UCARP_CFGDIR}/default-up.sh
STOP_SCRIPT=${UCARP_CFGDIR}/default-down.sh
# These line should not need to be touched
UCARP_OPTS="$OPTIONS -b $UCARP_BASE -k $SKEW -i $INTERFACE -v $INSTANCE_ID -p $PASSWORD -u $START_SCRIPT -d $STOP_SCRIPT -a $VIRTUAL_ADDRESS -s $SOURCE_ADDRESS -f $FACILITY $XPARAM"
${UCARP_EXEC} -B ${UCARP_OPTS}
""" % (ucarp_bin, UCARP_ETC)
@classmethod
def generateUcarpBoot(cls, node, services):
''' Generate a shell script used to boot the Ucarp daemons.
'''
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/sh
# Location of the UCARP config directory
UCARP_CFGDIR=%s
chmod a+x ${UCARP_CFGDIR}/*.sh
# Start the default ucarp daemon configuration
${UCARP_CFGDIR}/default.sh
""" % (UCARP_ETC)
@classmethod
def generateVipUp(cls, node, services):
''' Generate a shell script used to start the virtual ip
'''
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/bash
# Should be invoked as "default-up.sh <dev> <ip>"
exec 2> /dev/null
IP="${2}"
NET="${3}"
if [ -z "$NET" ]; then
NET="24"
fi
/sbin/ip addr add ${IP}/${NET} dev "$1"
"""
@classmethod
def generateVipDown(cls, node, services):
''' Generate a shell script used to stop the virtual ip
'''
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/bash
# Should be invoked as "default-down.sh <dev> <ip>"
exec 2> /dev/null
IP="${2}"
NET="${3}"
if [ -z "$NET" ]; then
NET="24"
fi
/sbin/ip addr del ${IP}/${NET} dev "$1"
"""
addservice(Ucarp)
"""
ucarp.py: defines high-availability IP address controlled by ucarp
"""
from core.service import CoreService
from core.service import ServiceManager
UCARP_ETC = "/usr/local/etc/ucarp"
class Ucarp(CoreService):
_name = "ucarp"
_group = "Utility"
_depends = ( )
_dirs = (UCARP_ETC,)
_configs = (
UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",)
_startindex = 65
_startup = ("sh ucarpboot.sh",)
_shutdown = ("killall ucarp",)
_validate = ("pidof ucarp",)
@classmethod
def generateconfig(cls, node, filename, services):
"""
Return the default file contents
"""
if filename == cls._configs[0]:
return cls.generateUcarpConf(node, services)
elif filename == cls._configs[1]:
return cls.generateVipUp(node, services)
elif filename == cls._configs[2]:
return cls.generateVipDown(node, services)
elif filename == cls._configs[3]:
return cls.generateUcarpBoot(node, services)
else:
raise ValueError
@classmethod
def generateUcarpConf(cls, node, services):
"""
Returns configuration file text.
"""
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/sh
# Location of UCARP executable
UCARP_EXEC=%s
# Location of the UCARP config directory
UCARP_CFGDIR=%s
# Logging Facility
FACILITY=daemon
# Instance ID
# Any number from 1 to 255
INSTANCE_ID=1
# Password
# Master and Backup(s) need to be the same
PASSWORD="changeme"
# The failover application address
VIRTUAL_ADDRESS=127.0.0.254
VIRTUAL_NET=8
# Interface for IP Address
INTERFACE=lo
# Maintanence address of the local machine
SOURCE_ADDRESS=127.0.0.1
# The ratio number to be considered before marking the node as dead
DEAD_RATIO=3
# UCARP base, lower number will be preferred master
# set to same to have master stay as long as possible
UCARP_BASE=1
SKEW=0
# UCARP options
# -z run shutdown script on exit
# -P force preferred master
# -n don't run down script at start up when we are backup
# -M use broadcast instead of multicast
# -S ignore interface state
OPTIONS="-z -n -M"
# Send extra parameter to down and up scripts
#XPARAM="-x <enter param here>"
XPARAM="-x ${VIRTUAL_NET}"
# The start and stop scripts
START_SCRIPT=${UCARP_CFGDIR}/default-up.sh
STOP_SCRIPT=${UCARP_CFGDIR}/default-down.sh
# These line should not need to be touched
UCARP_OPTS="$OPTIONS -b $UCARP_BASE -k $SKEW -i $INTERFACE -v $INSTANCE_ID -p $PASSWORD -u $START_SCRIPT -d $STOP_SCRIPT -a $VIRTUAL_ADDRESS -s $SOURCE_ADDRESS -f $FACILITY $XPARAM"
${UCARP_EXEC} -B ${UCARP_OPTS}
""" % (ucarp_bin, UCARP_ETC)
@classmethod
def generateUcarpBoot(cls, node, services):
"""
Generate a shell script used to boot the Ucarp daemons.
"""
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/sh
# Location of the UCARP config directory
UCARP_CFGDIR=%s
chmod a+x ${UCARP_CFGDIR}/*.sh
# Start the default ucarp daemon configuration
${UCARP_CFGDIR}/default.sh
""" % UCARP_ETC
@classmethod
def generateVipUp(cls, node, services):
"""
Generate a shell script used to start the virtual ip
"""
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/bash
# Should be invoked as "default-up.sh <dev> <ip>"
exec 2> /dev/null
IP="${2}"
NET="${3}"
if [ -z "$NET" ]; then
NET="24"
fi
/sbin/ip addr add ${IP}/${NET} dev "$1"
"""
@classmethod
def generateVipDown(cls, node, services):
"""
Generate a shell script used to stop the virtual ip
"""
try:
ucarp_bin = node.session.cfg['ucarp_bin']
except KeyError:
ucarp_bin = "/usr/sbin/ucarp"
return """\
#!/bin/bash
# Should be invoked as "default-down.sh <dev> <ip>"
exec 2> /dev/null
IP="${2}"
NET="${3}"
if [ -z "$NET" ]; then
NET="24"
fi
/sbin/ip addr del ${IP}/${NET} dev "$1"
"""
def load_services():
ServiceManager.add(Ucarp)

View file

@ -1,24 +1,22 @@
#
# CORE
# Copyright (c)2010-2014 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
utility.py: defines miscellaneous utility services.
'''
"""
utility.py: defines miscellaneous utility services.
"""
import os
import subprocess
from core import constants
from core.misc import utils
from core.misc.ipaddress import Ipv4Prefix
from core.misc.ipaddress import Ipv6Prefix
from core.service import CoreService
from core.service import ServiceManager
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix, IPv6Prefix
from core.misc.utils import *
from core.constants import *
class UtilService(CoreService):
''' Parent class for utility services.
'''
"""
Parent class for utility services.
"""
_name = "UtilityProcess"
_group = "Utility"
_depends = ()
@ -29,15 +27,16 @@ class UtilService(CoreService):
_shutdown = ()
@classmethod
def generateconfig(cls, node, filename, services):
def generateconfig(cls, node, filename, services):
return ""
class IPForwardService(UtilService):
_name = "IPForward"
_configs = ("ipforward.sh", )
_configs = ("ipforward.sh",)
_startindex = 5
_startup = ("sh ipforward.sh", )
_startup = ("sh ipforward.sh",)
@classmethod
def generateconfig(cls, node, filename, services):
if os.uname()[0] == "Linux":
@ -60,13 +59,13 @@ class IPForwardService(UtilService):
%(sysctl)s -w net.ipv4.conf.default.send_redirects=0
%(sysctl)s -w net.ipv4.conf.all.rp_filter=0
%(sysctl)s -w net.ipv4.conf.default.rp_filter=0
""" % {'sysctl': SYSCTL_BIN}
""" % {'sysctl': constants.SYSCTL_BIN}
for ifc in node.netifs():
name = sysctldevname(ifc.name)
cfg += "%s -w net.ipv4.conf.%s.forwarding=1\n" % (SYSCTL_BIN, name)
name = utils.sysctldevname(ifc.name)
cfg += "%s -w net.ipv4.conf.%s.forwarding=1\n" % (constants.SYSCTL_BIN, name)
cfg += "%s -w net.ipv4.conf.%s.send_redirects=0\n" % \
(SYSCTL_BIN, name)
cfg += "%s -w net.ipv4.conf.%s.rp_filter=0\n" % (SYSCTL_BIN, name)
(constants.SYSCTL_BIN, name)
cfg += "%s -w net.ipv4.conf.%s.rp_filter=0\n" % (constants.SYSCTL_BIN, name)
return cfg
@classmethod
@ -78,9 +77,8 @@ class IPForwardService(UtilService):
%s -w net.inet6.ip6.forwarding=1
%s -w net.inet.icmp.bmcastecho=1
%s -w net.inet.icmp.icmplim=0
""" % (SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN)
""" % (constants.SYSCTL_BIN, constants.SYSCTL_BIN, constants.SYSCTL_BIN, constants.SYSCTL_BIN)
addservice(IPForwardService)
class DefaultRouteService(UtilService):
_name = "DefaultRoute"
@ -92,21 +90,21 @@ class DefaultRouteService(UtilService):
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by DefaultRoute service (utility.py)\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\n".join(map(cls.addrstr, ifc.addrlist))
cfg += "\n"
return cfg
@staticmethod
def addrstr(x):
if x.find(":") >= 0:
net = IPv6Prefix(x)
net = Ipv6Prefix(x)
fam = "inet6 ::"
else:
net = IPv4Prefix(x)
net = Ipv4Prefix(x)
fam = "inet 0.0.0.0"
if net.maxaddr() == net.minaddr():
if net.max_addr() == net.min_addr():
return ""
else:
if os.uname()[0] == "Linux":
@ -115,9 +113,8 @@ class DefaultRouteService(UtilService):
rtcmd = "route add -%s" % fam
else:
raise Exception, "unknown platform"
return "%s %s" % (rtcmd, net.minaddr())
addservice(DefaultRouteService)
return "%s %s" % (rtcmd, net.min_addr())
class DefaultMulticastRouteService(UtilService):
_name = "DefaultMulticastRoute"
@ -144,8 +141,7 @@ class DefaultMulticastRouteService(UtilService):
cfg += "\n"
break
return cfg
addservice(DefaultMulticastRouteService)
class StaticRouteService(UtilService):
_name = "StaticRoute"
@ -160,23 +156,23 @@ class StaticRouteService(UtilService):
cfg += "# NOTE: this service must be customized to be of any use\n"
cfg += "# Below are samples that you can uncomment and edit.\n#\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\n".join(map(cls.routestr, ifc.addrlist))
cfg += "\n"
return cfg
@staticmethod
def routestr(x):
if x.find(":") >= 0:
net = IPv6Prefix(x)
net = Ipv6Prefix(x)
fam = "inet6"
dst = "3ffe:4::/64"
else:
net = IPv4Prefix(x)
net = Ipv4Prefix(x)
fam = "inet"
dst = "10.9.8.0/24"
if net.maxaddr() == net.minaddr():
if net.max_addr() == net.min_addr():
return ""
else:
if os.uname()[0] == "Linux":
@ -185,9 +181,8 @@ class StaticRouteService(UtilService):
rtcmd = "#/sbin/route add -%s %s" % (fam, dst)
else:
raise Exception, "unknown platform"
return "%s %s" % (rtcmd, net.minaddr())
return "%s %s" % (rtcmd, net.min_addr())
addservice(StaticRouteService)
class SshService(UtilService):
_name = "SSH"
@ -200,12 +195,13 @@ class SshService(UtilService):
_startup = ("sh startsshd.sh",)
_shutdown = ("killall sshd",)
_validate = ()
@classmethod
def generateconfig(cls, node, filename, services):
''' Use a startup script for launching sshd in order to wait for host
key generation.
'''
"""
Use a startup script for launching sshd in order to wait for host
key generation.
"""
if os.uname()[0] == "FreeBSD":
sshcfgdir = node.nodedir
sshstatedir = node.nodedir
@ -264,7 +260,6 @@ UsePAM yes
UseDNS no
""" % (sshcfgdir, sshstatedir, sshlibdir)
addservice(SshService)
class DhcpService(UtilService):
_name = "DHCP"
@ -273,12 +268,13 @@ class DhcpService(UtilService):
_startup = ("dhcpd",)
_shutdown = ("killall dhcpd",)
_validate = ("pidof dhcpd",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate a dhcpd config file using the network address of
each interface.
'''
"""
Generate a dhcpd config file using the network address of
each interface.
"""
cfg = """\
# auto-generated by DHCP service (utility.py)
# NOTE: move these option lines into the desired pool { } block(s) below
@ -294,25 +290,26 @@ max-lease-time 7200;
ddns-update-style none;
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\n".join(map(cls.subnetentry, ifc.addrlist))
cfg += "\n"
return cfg
@staticmethod
def subnetentry(x):
''' Generate a subnet declaration block given an IPv4 prefix string
for inclusion in the dhcpd3 config file.
'''
"""
Generate a subnet declaration block given an IPv4 prefix string
for inclusion in the dhcpd3 config file.
"""
if x.find(":") >= 0:
return ""
else:
addr = x.split("/")[0]
net = IPv4Prefix(x)
net = Ipv4Prefix(x)
# divide the address space in half
rangelow = net.addr(net.numaddr() / 2)
rangehigh = net.maxaddr()
rangelow = net.addr(net.num_addr() / 2)
rangehigh = net.max_addr()
return """
subnet %s netmask %s {
pool {
@ -321,23 +318,24 @@ subnet %s netmask %s {
option routers %s;
}
}
""" % (net.prefixstr(), net.netmaskstr(), rangelow, rangehigh, addr)
""" % (net.prefix_str(), net.netmask_str(), rangelow, rangehigh, addr)
addservice(DhcpService)
class DhcpClientService(UtilService):
''' Use a DHCP client for all interfaces for addressing.
'''
"""
Use a DHCP client for all interfaces for addressing.
"""
_name = "DHCPClient"
_configs = ("startdhcpclient.sh",)
_startup = ("sh startdhcpclient.sh",)
_shutdown = ("killall dhclient",)
_validate = ("pidof dhclient",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate a script to invoke dhclient on all interfaces.
'''
"""
Generate a script to invoke dhclient on all interfaces.
"""
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by DHCPClient service (utility.py)\n"
cfg += "# uncomment this mkdir line and symlink line to enable client-"
@ -350,25 +348,26 @@ class DhcpClientService(UtilService):
cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % ifc.name
cfg += " /var/run/resolvconf/resolv.conf\n"
cfg += "/sbin/dhclient -nw -pf /var/run/dhclient-%s.pid" % ifc.name
cfg += " -lf /var/run/dhclient-%s.lease %s\n" % (ifc.name, ifc.name)
cfg += " -lf /var/run/dhclient-%s.lease %s\n" % (ifc.name, ifc.name)
return cfg
addservice(DhcpClientService)
class FtpService(UtilService):
''' Start a vsftpd server.
'''
"""
Start a vsftpd server.
"""
_name = "FTP"
_configs = ("vsftpd.conf",)
_dirs = ("/var/run/vsftpd/empty", "/var/ftp",)
_startup = ("vsftpd ./vsftpd.conf",)
_shutdown = ("killall vsftpd",)
_validate = ("pidof vsftpd",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate a vsftpd.conf configuration file.
'''
"""
Generate a vsftpd.conf configuration file.
"""
return """\
# vsftpd.conf auto-generated by FTP service (utility.py)
listen=YES
@ -384,26 +383,27 @@ secure_chroot_dir=/var/run/vsftpd/empty
anon_root=/var/ftp
"""
addservice(FtpService)
class HttpService(UtilService):
''' Start an apache server.
'''
"""
Start an apache server.
"""
_name = "HTTP"
_configs = ("/etc/apache2/apache2.conf", "/etc/apache2/envvars",
"/var/www/index.html",)
_dirs = ("/etc/apache2", "/var/run/apache2", "/var/log/apache2",
"/run/lock", "/var/lock/apache2", "/var/www", )
"/run/lock", "/var/lock/apache2", "/var/www",)
_startup = ("chown www-data /var/lock/apache2", "apache2ctl start",)
_shutdown = ("apache2ctl stop",)
_validate = ("pidof apache2",)
APACHEVER22, APACHEVER24 = (22, 24)
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate an apache2.conf configuration file.
'''
"""
Generate an apache2.conf configuration file.
"""
if filename == cls._configs[0]:
return cls.generateapache2conf(node, filename, services)
elif filename == cls._configs[1]:
@ -415,43 +415,45 @@ class HttpService(UtilService):
@classmethod
def detectversionfromcmd(cls):
''' Detect the apache2 version using the 'a2query' command.
'''
"""
Detect the apache2 version using the 'a2query' command.
"""
try:
status, result = cmdresult(['a2query', '-v'])
except Exception:
status, result = utils.cmdresult(['a2query', '-v'])
except subprocess.CalledProcessError:
status = -1
if status == 0 and result[:3] == '2.4':
return cls.APACHEVER24
return cls.APACHEVER22
return cls.APACHEVER22
@classmethod
def generateapache2conf(cls, node, filename, services):
lockstr = { cls.APACHEVER22:
'LockFile ${APACHE_LOCK_DIR}/accept.lock\n',
cls.APACHEVER24:
'Mutex file:${APACHE_LOCK_DIR} default\n', }
mpmstr = { cls.APACHEVER22: '', cls.APACHEVER24:
'LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n', }
lockstr = {cls.APACHEVER22:
'LockFile ${APACHE_LOCK_DIR}/accept.lock\n',
cls.APACHEVER24:
'Mutex file:${APACHE_LOCK_DIR} default\n', }
mpmstr = {cls.APACHEVER22: '', cls.APACHEVER24:
'LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n', }
permstr = { cls.APACHEVER22:
' Order allow,deny\n Deny from all\n Satisfy all\n',
cls.APACHEVER24:
' Require all denied\n', }
permstr = {cls.APACHEVER22:
' Order allow,deny\n Deny from all\n Satisfy all\n',
cls.APACHEVER24:
' Require all denied\n', }
authstr = { 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', }
authstr = {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', }
permstr2 = { cls.APACHEVER22:
'\t\tOrder allow,deny\n\t\tallow from all\n',
permstr2 = {cls.APACHEVER22:
'\t\tOrder allow,deny\n\t\tallow from all\n',
cls.APACHEVER24:
'\t\tRequire all granted\n', }
'\t\tRequire all granted\n', }
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 += """\
PidFile ${APACHE_PID_FILE}
@ -474,7 +476,7 @@ KeepAliveTimeout 5
<IfModule mpm_worker_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
@ -484,7 +486,7 @@ KeepAliveTimeout 5
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 150
@ -590,16 +592,16 @@ export LANG
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
continue
body += "<li>%s - %s</li>\n" % (ifc.name, ifc.addrlist)
body += "<li>%s - %s</li>\n" % (ifc.name, ifc.addrlist)
return "<html><body>%s</body></html>" % body
addservice(HttpService)
class PcapService(UtilService):
''' Pcap service for logging packets.
'''
"""
Pcap service for logging packets.
"""
_name = "pcap"
_configs = ("pcap.sh", )
_configs = ("pcap.sh",)
_dirs = ()
_startindex = 1
_startup = ("sh pcap.sh start",)
@ -609,8 +611,9 @@ class PcapService(UtilService):
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate a startpcap.sh traffic logging script.
'''
"""
Generate a startpcap.sh traffic logging script.
"""
cfg = """
#!/bin/sh
# set tcpdump options here (see 'man tcpdump' for help)
@ -625,7 +628,7 @@ if [ "x$1" = "xstart" ]; then
cfg += '# '
redir = "< /dev/null"
cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % \
(node.name, ifc.name, ifc.name, redir)
(node.name, ifc.name, ifc.name, redir)
cfg += """
elif [ "x$1" = "xstop" ]; then
@ -635,7 +638,6 @@ fi;
"""
return cfg
addservice(PcapService)
class RadvdService(UtilService):
_name = "radvd"
@ -644,12 +646,13 @@ class RadvdService(UtilService):
_startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",)
_shutdown = ("pkill radvd",)
_validate = ("pidof radvd",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Generate a RADVD router advertisement daemon config file
"""
Generate a RADVD router advertisement daemon config file
using the network address of each interface.
'''
"""
cfg = "# auto-generated by RADVD service (utility.py)\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
@ -679,29 +682,30 @@ interface %s
""" % prefix
cfg += "};\n"
return cfg
@staticmethod
def subnetentry(x):
''' Generate a subnet declaration block given an IPv6 prefix string
for inclusion in the RADVD config file.
'''
"""
Generate a subnet declaration block given an IPv6 prefix string
for inclusion in the RADVD config file.
"""
if x.find(":") >= 0:
net = IPv6Prefix(x)
net = Ipv6Prefix(x)
return str(net)
else:
return ""
addservice(RadvdService)
class AtdService(UtilService):
''' Atd service for scheduling at jobs
'''
"""
Atd service for scheduling at jobs
"""
_name = "atd"
_configs = ("startatd.sh",)
_dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
_startup = ("sh startatd.sh", )
_shutdown = ("pkill atd", )
_startup = ("sh startatd.sh",)
_shutdown = ("pkill atd",)
@classmethod
def generateconfig(cls, node, filename, services):
return """
@ -711,14 +715,28 @@ chown -R daemon /var/spool/cron/*
chmod -R 700 /var/spool/cron/*
atd
"""
addservice(AtdService)
class UserDefinedService(UtilService):
''' Dummy service allowing customization of anything.
'''
"""
Dummy service allowing customization of anything.
"""
_name = "UserDefined"
_startindex = 50
_meta = "Customize this service to do anything upon startup."
addservice(UserDefinedService)
def load_services():
ServiceManager.add(IPForwardService)
ServiceManager.add(DefaultRouteService)
ServiceManager.add(DefaultMulticastRouteService)
ServiceManager.add(StaticRouteService)
ServiceManager.add(SshService)
ServiceManager.add(DhcpService)
ServiceManager.add(DhcpClientService)
ServiceManager.add(FtpService)
ServiceManager.add(HttpService)
ServiceManager.add(PcapService)
ServiceManager.add(RadvdService)
ServiceManager.add(AtdService)
ServiceManager.add(UserDefinedService)

View file

@ -1,24 +1,19 @@
#
# CORE
# Copyright (c)2011-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
"""
xorp.py: defines routing services provided by the XORP routing suite.
'''
"""
import os
from core.misc import log
from core.service import CoreService
from core.service import ServiceManager
logger = log.get_logger(__name__)
from core.service import CoreService, addservice
from core.misc.ipaddr import IPv4Prefix
from core.constants import *
class XorpRtrmgr(CoreService):
''' XORP router manager service builds a config.boot file based on other
"""
XORP router manager service builds a config.boot file based on other
enabled XORP services, and launches necessary daemons upon startup.
'''
"""
_name = "xorp_rtrmgr"
_group = "XORP"
_depends = ()
@ -26,15 +21,16 @@ class XorpRtrmgr(CoreService):
_configs = ("/etc/xorp/config.boot",)
_startindex = 35
_startup = ("xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid" % (_configs[0], _name, _name),)
_shutdown = ("killall xorp_rtrmgr", )
_validate = ("pidof xorp_rtrmgr", )
_shutdown = ("killall xorp_rtrmgr",)
_validate = ("pidof xorp_rtrmgr",)
@classmethod
def generateconfig(cls, node, filename, services):
''' Returns config.boot configuration file text. Other services that
depend on this will have generatexorpconfig() hooks that are
"""
Returns config.boot configuration file text. Other services that
depend on this will have generatexorpconfig() hooks that are
invoked here. Filename currently ignored.
'''
"""
cfg = "interfaces {\n"
for ifc in node.netifs():
cfg += " interface %s {\n" % ifc.name
@ -50,40 +46,40 @@ class XorpRtrmgr(CoreService):
s._depends.index(cls._name)
cfg += s.generatexorpconfig(node)
except ValueError:
pass
logger.exception("error getting value from service: %s", cls._name)
return cfg
@staticmethod
def addrstr(x):
''' helper for mapping IP addresses to XORP config statements
'''
try:
(addr, plen) = x.split("/")
except Exception:
raise ValueError, "invalid address"
"""
helper for mapping IP addresses to XORP config statements
"""
addr, plen = x.split("/")
cfg = "\t address %s {\n" % addr
cfg += "\t\tprefix-length: %s\n" % plen
cfg +="\t }\n"
cfg += "\t }\n"
return cfg
@staticmethod
def lladdrstr(ifc):
''' helper for adding link-local address entries (required by OSPFv3)
'''
"""
helper for adding link-local address entries (required by OSPFv3)
"""
cfg = "\t address %s {\n" % ifc.hwaddr.tolinklocal()
cfg += "\t\tprefix-length: 64\n"
cfg += "\t }\n"
return cfg
addservice(XorpRtrmgr)
class XorpService(CoreService):
''' Parent class for XORP services. Defines properties and methods
common to XORP's routing daemons.
'''
"""
Parent class for XORP services. Defines properties and methods
common to XORP's routing daemons.
"""
_name = "XorpDaemon"
_group = "XORP"
_depends = ("xorp_rtrmgr", )
_depends = ("xorp_rtrmgr",)
_dirs = ()
_configs = ()
_startindex = 40
@ -93,22 +89,24 @@ class XorpService(CoreService):
@staticmethod
def fea(forwarding):
''' Helper to add a forwarding engine entry to the config file.
'''
"""
Helper to add a forwarding engine entry to the config file.
"""
cfg = "fea {\n"
cfg += " %s {\n" % forwarding
cfg += "\tdisable:false\n"
cfg += " }\n"
cfg += "}\n"
return cfg
@staticmethod
def mfea(forwarding, ifcs):
''' 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 = []
for ifc in ifcs:
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
names.append(ifc.name)
names.append("register_vif")
@ -125,11 +123,11 @@ class XorpService(CoreService):
cfg += "}\n"
return cfg
@staticmethod
def policyexportconnected():
''' Helper to add a policy statement for exporting connected routes.
'''
"""
Helper to add a policy statement for exporting connected routes.
"""
cfg = "policy {\n"
cfg += " policy-statement export-connected {\n"
cfg += "\tterm 100 {\n"
@ -143,34 +141,37 @@ class XorpService(CoreService):
@staticmethod
def routerid(node):
''' 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.
"""
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
for a in ifc.addrlist:
if a.find(".") >= 0:
return a.split('/')[0]
#raise ValueError, "no IPv4 address found for router ID"
return a.split('/')[0]
# raise ValueError, "no IPv4 address found for router ID"
return "0.0.0.0"
@classmethod
def generateconfig(cls, node, filename, services):
def generateconfig(cls, node, filename, services):
return ""
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
return ""
class XorpOspfv2(XorpService):
''' The OSPFv2 service provides IPv4 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
'''
"""
The OSPFv2 service provides IPv4 routing for wired networks. It does
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
"""
_name = "XORP_OSPFv2"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.fea("unicast-forwarding4")
rtrid = cls.routerid(node)
cfg += "\nprotocols {\n"
@ -178,7 +179,7 @@ class XorpOspfv2(XorpService):
cfg += "\trouter-id: %s\n" % rtrid
cfg += "\tarea 0.0.0.0 {\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\t interface %s {\n" % ifc.name
cfg += "\t\tvif %s {\n" % ifc.name
@ -194,18 +195,18 @@ class XorpOspfv2(XorpService):
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpOspfv2)
class XorpOspfv3(XorpService):
''' The OSPFv3 service provides IPv6 routing. It does
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
'''
"""
The OSPFv3 service provides IPv6 routing. It does
not build its own configuration file but has hooks for adding to the
unified XORP configuration file.
"""
_name = "XORP_OSPFv3"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.fea("unicast-forwarding6")
rtrid = cls.routerid(node)
cfg += "\nprotocols {\n"
@ -213,7 +214,7 @@ class XorpOspfv3(XorpService):
cfg += "\trouter-id: %s\n" % rtrid
cfg += "\tarea 0.0.0.0 {\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\t interface %s {\n" % ifc.name
cfg += "\t\tvif %s {\n" % ifc.name
@ -223,15 +224,15 @@ class XorpOspfv3(XorpService):
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpOspfv3)
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"
_custom_needed = True
@classmethod
def generatexorpconfig(cls, node):
cfg = "/* This is a sample config that should be customized with\n"
@ -253,22 +254,23 @@ class XorpBgp(XorpService):
cfg += "}\n"
return cfg
addservice(XorpBgp)
class XorpRip(XorpService):
''' RIP IPv4 unicast routing.
'''
"""
RIP IPv4 unicast routing.
"""
_name = "XORP_RIP"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.fea("unicast-forwarding4")
cfg += cls.policyexportconnected()
cfg += "\nprotocols {\n"
cfg += " rip {\n"
cfg += "\texport: \"export-connected\"\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
@ -284,68 +286,68 @@ class XorpRip(XorpService):
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpRip)
class XorpRipng(XorpService):
''' RIP NG IPv6 unicast routing.
'''
"""
RIP NG IPv6 unicast routing.
"""
_name = "XORP_RIPNG"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.fea("unicast-forwarding6")
cfg += cls.policyexportconnected()
cfg += "\nprotocols {\n"
cfg += " ripng {\n"
cfg += "\texport: \"export-connected\"\n"
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
# for a in ifc.addrlist:
# if a.find(":") < 0:
# continue
# addr = a.split("/")[0]
# cfg += "\t\taddress %s {\n" % addr
# cfg += "\t\t disable: false\n"
# cfg += "\t\t}\n"
# for a in ifc.addrlist:
# if a.find(":") < 0:
# continue
# addr = a.split("/")[0]
# cfg += "\t\taddress %s {\n" % addr
# cfg += "\t\t disable: false\n"
# cfg += "\t\t}\n"
cfg += "\t\taddress %s {\n" % ifc.hwaddr.tolinklocal()
cfg += "\t\t disable: false\n"
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t}\n"
cfg += "\t}\n"
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpRipng)
class XorpPimSm4(XorpService):
''' PIM Sparse Mode IPv4 multicast routing.
'''
"""
PIM Sparse Mode IPv4 multicast routing.
"""
_name = "XORP_PIMSM4"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.mfea("mfea4", node.netifs())
cfg += "\nprotocols {\n"
cfg += " igmp {\n"
names = []
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
names.append(ifc.name)
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
cfg += "\t\tdisable: false\n"
cfg += "\t }\n"
cfg += "\t}\n"
cfg += "\t}\n"
cfg += " }\n"
cfg += "}\n"
cfg += "\nprotocols {\n"
cfg += " pimsm4 {\n"
@ -368,46 +370,46 @@ class XorpPimSm4(XorpService):
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t}\n"
cfg += " }\n"
cfg += "}\n"
cfg += "\nprotocols {\n"
cfg += " fib2mrib {\n"
cfg += "\tdisable: false\n"
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpPimSm4)
class XorpPimSm6(XorpService):
''' PIM Sparse Mode IPv6 multicast routing.
'''
"""
PIM Sparse Mode IPv6 multicast routing.
"""
_name = "XORP_PIMSM6"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.mfea("mfea6", node.netifs())
cfg += "\nprotocols {\n"
cfg += " mld {\n"
names = []
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
names.append(ifc.name)
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
cfg += "\t\tdisable: false\n"
cfg += "\t }\n"
cfg += "\t}\n"
cfg += "\t}\n"
cfg += " }\n"
cfg += "}\n"
cfg += "\nprotocols {\n"
cfg += " pimsm6 {\n"
names.append("register_vif")
for name in names:
cfg += "\tinterface %s {\n" % name
@ -427,33 +429,33 @@ class XorpPimSm6(XorpService):
cfg += "\t\t}\n"
cfg += "\t }\n"
cfg += "\t}\n"
cfg += " }\n"
cfg += "}\n"
cfg += "\nprotocols {\n"
cfg += " fib2mrib {\n"
cfg += "\tdisable: false\n"
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpPimSm6)
class XorpOlsr(XorpService):
''' OLSR IPv4 unicast MANET routing.
'''
"""
OLSR IPv4 unicast MANET routing.
"""
_name = "XORP_OLSR"
@classmethod
def generatexorpconfig(cls, node):
def generatexorpconfig(cls, node):
cfg = cls.fea("unicast-forwarding4")
rtrid = cls.routerid(node)
cfg += "\nprotocols {\n"
cfg += " olsr4 {\n"
cfg += "\tmain-address: %s\n" % rtrid
for ifc in node.netifs():
if hasattr(ifc, 'control') and ifc.control == True:
if hasattr(ifc, 'control') and ifc.control is True:
continue
cfg += "\tinterface %s {\n" % ifc.name
cfg += "\t vif %s {\n" % ifc.name
@ -468,5 +470,15 @@ class XorpOlsr(XorpService):
cfg += " }\n"
cfg += "}\n"
return cfg
addservice(XorpOlsr)
def load_services():
ServiceManager.add(XorpRtrmgr)
ServiceManager.add(XorpOspfv2)
ServiceManager.add(XorpOspfv3)
ServiceManager.add(XorpBgp)
ServiceManager.add(XorpRip)
ServiceManager.add(XorpRipng)
ServiceManager.add(XorpPimSm4)
ServiceManager.add(XorpPimSm6)
ServiceManager.add(XorpOlsr)