core-extra/daemon/core/services/bird.py
2013-08-29 14:21:13 +00:00

249 lines
7 KiB
Python

#
# 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, addservice
from core.misc.ipaddr import IPv4Prefix
from core.constants import *
class Bird(CoreService):
''' Bird router support
'''
_name = "bird"
_group = "BIRD"
_depends = ()
_dirs = ("/etc/bird",)
_configs = ("/etc/bird/bird.conf",)
_startindex = 35
_startup = ("bird -c %s" % (_configs[0]),)
_shutdown = ("killall bird", )
_validate = ("pidof bird", )
@classmethod
def generateconfig(cls, node, filename, services):
''' Return the bird.conf file contents.
'''
if filename == cls._configs[0]:
return cls.generateBirdConf(node, services)
else:
raise ValueError
@staticmethod
def routerid(node):
''' 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 "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 = """\
/* 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;
#debug commands 2;
router id %s; # Mandatory for IPv6, may be automatic for IPv4
protocol kernel {
persist; # Don\'t remove routes on BIRD shutdown
scan time 200; # Scan kernel routing table every 200 seconds
export all;
import all;
}
protocol device {
scan time 10; # Scan interfaces every 10 seconds
}
""" % (cls._name, cls.routerid(node))
# Generate protocol specific configurations
for s in services:
if cls._name not in s._depends:
continue
cfg += s.generatebirdconfig(node)
return cfg
class BirdService(CoreService):
''' Parent class for Bird services. Defines properties and methods
common to Bird's routing daemons.
'''
_name = "BirdDaemon"
_group = "BIRD"
_depends = ("bird", )
_dirs = ()
_configs = ()
_startindex = 40
_startup = ()
_shutdown = ()
_meta = "The config file for this service can be found in the bird service."
@classmethod
def generatebirdconfig(cls, node):
return ""
@classmethod
def generatebirdifcconfig(cls, node):
''' Use only bare interfaces descriptions in generated protocol
configurations. This has the slight advantage of being the same
everywhere.
'''
cfg = ""
for ifc in node.netifs():
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)'''
_name = "BIRD_BGP"
_custom_needed = True
@classmethod
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 */
protocol bgp {
local as 65000; # Customize your AS number
neighbor 198.51.100.130 as 64496; # Customize neighbor AS number && IP
export filter { # We use non-trivial export rules
# This is an example. You should advertise only *your routes*
if (source = RTS_DEVICE) || (source = RTS_OSPF) then {
# bgp_community.add((65000,64501)); # Assign our community
accept;
}
reject;
};
import all;
}
"""
class BirdOspf(BirdService):
'''OSPF BIRD Service (configuration generation)'''
_name = "BIRD_OSPFv2"
@classmethod
def generatebirdconfig(cls, node):
cfg = 'protocol ospf {\n'
cfg += ' export filter {\n'
cfg += ' if source = RTS_BGP then {\n'
cfg += ' ospf_metric1 = 100;\n'
cfg += ' accept;\n'
cfg += ' }\n'
cfg += ' accept;\n'
cfg += ' };\n'
cfg += ' area 0.0.0.0 {\n'
cfg += cls.generatebirdifcconfig(node)
cfg += ' };\n'
cfg += '}\n\n'
return cfg
class BirdRadv(BirdService):
'''RADV BIRD Service (configuration generation)'''
_name = "BIRD_RADV"
@classmethod
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 += ' # Advertise DNS\n'
cfg += ' rdnss {\n'
cfg += '# lifetime mult 10;\n'
cfg += '# lifetime mult 10;\n'
cfg += '# ns 2001:0DB8:1234::11;\n'
cfg += '# ns 2001:0DB8:1234::11;\n'
cfg += '# ns 2001:0DB8:1234::12;\n'
cfg += '# ns 2001:0DB8:1234::12;\n'
cfg += ' };\n'
cfg += '}\n\n'
return cfg
class BirdRip(BirdService):
'''RIP BIRD Service (configuration generation)'''
_name = "BIRD_RIP"
@classmethod
def generatebirdconfig(cls, node):
cfg = 'protocol rip {\n'
cfg += ' period 10;\n'
cfg += ' garbage time 60;\n'
cfg += cls.generatebirdifcconfig(node)
cfg += ' honor neighbor;\n'
cfg += ' authentication none;\n'
cfg += ' import all;\n'
cfg += ' export all;\n'
cfg += '}\n\n'
return cfg
class BirdStatic(BirdService):
'''Static Bird Service (configuration generation)'''
_name = "BIRD_static"
_custom_needed = True
@classmethod
def generatebirdconfig(cls, node):
cfg = '/* This is a sample config that must be customized */\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 203.0.113.0/24 reject; # Sink route\n'
cfg += '# route 10.2.0.0/24 via "arc0"; # Secondary network\n'
cfg += '}\n\n'
return cfg
# Register all protocols
addservice(Bird)
addservice(BirdOspf)
addservice(BirdBgp)
#addservice(BirdRadv) # untested
addservice(BirdRip)
addservice(BirdStatic)