Merge branch 'develop' into bugfix/quagga-ipv6-only-and-fast-convergence
This commit is contained in:
commit
3c49d0676a
454 changed files with 44907 additions and 26019 deletions
|
@ -1,12 +1,14 @@
|
|||
"""
|
||||
quagga.py: defines routing services provided by Quagga.
|
||||
"""
|
||||
import netaddr
|
||||
|
||||
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.emane.nodes import EmaneNet
|
||||
from core.emulator.enumerations import LinkTypes
|
||||
from core.nodes.network import PtpNet, WlanNode
|
||||
from core.nodes.physical import Rj45Node
|
||||
from core.services.coreservices import CoreService
|
||||
|
||||
|
||||
class Zebra(CoreService):
|
||||
|
@ -16,7 +18,7 @@ class Zebra(CoreService):
|
|||
configs = (
|
||||
"/usr/local/etc/quagga/Quagga.conf",
|
||||
"quaggaboot.sh",
|
||||
"/usr/local/etc/quagga/vtysh.conf"
|
||||
"/usr/local/etc/quagga/vtysh.conf",
|
||||
)
|
||||
startup = ("sh quaggaboot.sh zebra",)
|
||||
shutdown = ("killall zebra",)
|
||||
|
@ -34,7 +36,9 @@ class Zebra(CoreService):
|
|||
elif filename == cls.configs[2]:
|
||||
return cls.generateVtyshConf(node)
|
||||
else:
|
||||
raise ValueError("file name (%s) is not a known configuration: %s", filename, cls.configs)
|
||||
raise ValueError(
|
||||
"file name (%s) is not a known configuration: %s", filename, cls.configs
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def generateVtyshConf(cls, node):
|
||||
|
@ -55,7 +59,7 @@ class Zebra(CoreService):
|
|||
for ifc in node.netifs():
|
||||
cfg += "interface %s\n" % ifc.name
|
||||
# include control interfaces in addressing but not routing daemons
|
||||
if hasattr(ifc, 'control') and ifc.control is True:
|
||||
if hasattr(ifc, "control") and ifc.control is True:
|
||||
cfg += " "
|
||||
cfg += "\n ".join(map(cls.addrstr, ifc.addrlist))
|
||||
cfg += "\n"
|
||||
|
@ -77,13 +81,17 @@ class Zebra(CoreService):
|
|||
cfgv4 += ifccfg
|
||||
|
||||
if want_ipv4:
|
||||
ipv4list = filter(lambda x: ipaddress.is_ipv4_address(x.split('/')[0]), ifc.addrlist)
|
||||
ipv4list = filter(
|
||||
lambda x: netaddr.valid_ipv4(x.split("/")[0]), ifc.addrlist
|
||||
)
|
||||
cfg += " "
|
||||
cfg += "\n ".join(map(cls.addrstr, ipv4list))
|
||||
cfg += "\n"
|
||||
cfg += cfgv4
|
||||
if want_ipv6:
|
||||
ipv6list = filter(lambda x: ipaddress.is_ipv6_address(x.split('/')[0]), ifc.addrlist)
|
||||
ipv6list = filter(
|
||||
lambda x: netaddr.valid_ipv6(x.split("/")[0]), ifc.addrlist
|
||||
)
|
||||
cfg += " "
|
||||
cfg += "\n ".join(map(cls.addrstr, ipv6list))
|
||||
cfg += "\n"
|
||||
|
@ -101,9 +109,10 @@ class Zebra(CoreService):
|
|||
"""
|
||||
helper for mapping IP addresses to zebra config statements
|
||||
"""
|
||||
if x.find(".") >= 0:
|
||||
addr = x.split("/")[0]
|
||||
if netaddr.valid_ipv4(addr):
|
||||
return "ip address %s" % x
|
||||
elif x.find(":") >= 0:
|
||||
elif netaddr.valid_ipv6(addr):
|
||||
return "ipv6 address %s" % x
|
||||
else:
|
||||
raise ValueError("invalid address: %s", x)
|
||||
|
@ -113,10 +122,12 @@ class Zebra(CoreService):
|
|||
"""
|
||||
Generate a shell script used to boot the Quagga daemons.
|
||||
"""
|
||||
quagga_bin_search = node.session.options.get_config("quagga_bin_search",
|
||||
default='"/usr/local/bin /usr/bin /usr/lib/quagga"')
|
||||
quagga_sbin_search = node.session.options.get_config('quagga_sbin_search',
|
||||
default='"/usr/local/sbin /usr/sbin /usr/lib/quagga"')
|
||||
quagga_bin_search = node.session.options.get_config(
|
||||
"quagga_bin_search", default='"/usr/local/bin /usr/bin /usr/lib/quagga"'
|
||||
)
|
||||
quagga_sbin_search = node.session.options.get_config(
|
||||
"quagga_sbin_search", default='"/usr/local/sbin /usr/sbin /usr/lib/quagga"'
|
||||
)
|
||||
return """\
|
||||
#!/bin/sh
|
||||
# auto-generated by zebra service (quagga.py)
|
||||
|
@ -192,7 +203,7 @@ bootquagga()
|
|||
|
||||
bootdaemon "zebra"
|
||||
for r in rip ripng ospf6 ospf bgp babel; do
|
||||
if grep -q "^router \<${r}\>" $QUAGGA_CONF; then
|
||||
if grep -q "^router \\<${r}\\>" $QUAGGA_CONF; then
|
||||
bootdaemon "${r}d"
|
||||
fi
|
||||
done
|
||||
|
@ -210,7 +221,12 @@ if [ "$1" != "zebra" ]; then
|
|||
fi
|
||||
confcheck
|
||||
bootquagga
|
||||
""" % (cls.configs[0], quagga_sbin_search, quagga_bin_search, constants.QUAGGA_STATE_DIR)
|
||||
""" % (
|
||||
cls.configs[0],
|
||||
quagga_sbin_search,
|
||||
quagga_bin_search,
|
||||
constants.QUAGGA_STATE_DIR,
|
||||
)
|
||||
|
||||
|
||||
class QuaggaService(CoreService):
|
||||
|
@ -218,6 +234,7 @@ class QuaggaService(CoreService):
|
|||
Parent class for Quagga services. Defines properties and methods
|
||||
common to Quagga's routing daemons.
|
||||
"""
|
||||
|
||||
name = None
|
||||
group = "Quagga"
|
||||
dependencies = ("zebra",)
|
||||
|
@ -236,13 +253,14 @@ class QuaggaService(CoreService):
|
|||
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 is True:
|
||||
if hasattr(ifc, "control") and ifc.control is True:
|
||||
continue
|
||||
for a in ifc.addrlist:
|
||||
if a.find(".") >= 0:
|
||||
return a.split('/')[0]
|
||||
a = a.split("/")[0]
|
||||
if netaddr.valid_ipv4(a):
|
||||
return a
|
||||
# raise ValueError, "no IPv4 address found for router ID"
|
||||
return "0.0.0.%d" % node.objid
|
||||
return "0.0.0.%d" % node.id
|
||||
|
||||
@staticmethod
|
||||
def rj45check(ifc):
|
||||
|
@ -254,7 +272,7 @@ class QuaggaService(CoreService):
|
|||
for peerifc in ifc.net.netifs():
|
||||
if peerifc == ifc:
|
||||
continue
|
||||
if nodeutils.is_node(peerifc, NodeTypes.RJ45):
|
||||
if isinstance(peerifc, Rj45Node):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -277,6 +295,7 @@ class Ospfv2(QuaggaService):
|
|||
not build its own configuration file but has hooks for adding to the
|
||||
unified Quagga.conf file.
|
||||
"""
|
||||
|
||||
name = "OSPFv2"
|
||||
startup = ()
|
||||
shutdown = ("killall ospfd",)
|
||||
|
@ -307,7 +326,7 @@ class Ospfv2(QuaggaService):
|
|||
Helper to detect whether interface is connected to a notional
|
||||
point-to-point link.
|
||||
"""
|
||||
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER):
|
||||
if isinstance(ifc.net, PtpNet):
|
||||
return " ip ospf network point-to-point\n"
|
||||
return ""
|
||||
|
||||
|
@ -318,13 +337,12 @@ class Ospfv2(QuaggaService):
|
|||
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 is True:
|
||||
if hasattr(ifc, "control") and ifc.control is True:
|
||||
continue
|
||||
for a in ifc.addrlist:
|
||||
if a.find(".") < 0:
|
||||
continue
|
||||
net = ipaddress.Ipv4Prefix(a)
|
||||
cfg += " network %s area 0\n" % net
|
||||
addr = a.split("/")[0]
|
||||
if netaddr.valid_ipv4(addr):
|
||||
cfg += " network %s area 0\n" % a
|
||||
cfg += "!\n"
|
||||
return cfg
|
||||
|
||||
|
@ -335,7 +353,6 @@ class Ospfv2(QuaggaService):
|
|||
if cls.rj45check(ifc):
|
||||
return cfg
|
||||
cfg += cls.ptpcheck(ifc)
|
||||
|
||||
return cfg + """\
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 6
|
||||
|
@ -348,6 +365,7 @@ class Ospfv3(QuaggaService):
|
|||
not build its own configuration file but has hooks for adding to the
|
||||
unified Quagga.conf file.
|
||||
"""
|
||||
|
||||
name = "OSPFv3"
|
||||
startup = ()
|
||||
shutdown = ("killall ospf6d",)
|
||||
|
@ -388,7 +406,7 @@ class Ospfv3(QuaggaService):
|
|||
Helper to detect whether interface is connected to a notional
|
||||
point-to-point link.
|
||||
"""
|
||||
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER):
|
||||
if isinstance(ifc.net, PtpNet):
|
||||
return " ipv6 ospf6 network point-to-point\n"
|
||||
return ""
|
||||
|
||||
|
@ -396,9 +414,10 @@ class Ospfv3(QuaggaService):
|
|||
def generatequaggaconfig(cls, node):
|
||||
cfg = "router ospf6\n"
|
||||
rtrid = cls.routerid(node)
|
||||
cfg += " instance-id 65\n"
|
||||
cfg += " router-id %s\n" % rtrid
|
||||
for ifc in node.netifs():
|
||||
if hasattr(ifc, 'control') and ifc.control is True:
|
||||
if hasattr(ifc, "control") and ifc.control is True:
|
||||
continue
|
||||
cfg += " interface %s area 0.0.0.0\n" % ifc.name
|
||||
cfg += "!\n"
|
||||
|
@ -407,19 +426,6 @@ class Ospfv3(QuaggaService):
|
|||
@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
|
||||
# """
|
||||
|
||||
|
||||
class Ospfv3mdr(Ospfv3):
|
||||
|
@ -429,24 +435,26 @@ class Ospfv3mdr(Ospfv3):
|
|||
configuration file but has hooks for adding to the
|
||||
unified Quagga.conf file.
|
||||
"""
|
||||
|
||||
name = "OSPFv3MDR"
|
||||
ipv4_routing = True
|
||||
|
||||
@classmethod
|
||||
def generatequaggaifcconfig(cls, node, ifc):
|
||||
cfg = cls.mtucheck(ifc)
|
||||
# Uncomment the following line to use Address Family Translation for IPv4
|
||||
cfg += " ipv6 ospf6 instance-id 65\n"
|
||||
if ifc.net is not None and nodeutils.is_node(ifc.net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
|
||||
return cfg + """\
|
||||
if ifc.net is not None and isinstance(ifc.net, (WlanNode, EmaneNet)):
|
||||
return (
|
||||
cfg
|
||||
+ """\
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 6
|
||||
ipv6 ospf6 retransmit-interval 5
|
||||
ipv6 ospf6 network manet-designated-router
|
||||
ipv6 ospf6 diffhellos
|
||||
ipv6 ospf6 twohoprefresh 3
|
||||
ipv6 ospf6 adjacencyconnectivity uniconnected
|
||||
ipv6 ospf6 lsafullness mincostlsa
|
||||
"""
|
||||
)
|
||||
else:
|
||||
return cfg
|
||||
|
||||
|
@ -457,6 +465,7 @@ class Bgp(QuaggaService):
|
|||
Peers must be manually configured, with a full mesh for those
|
||||
having the same AS number.
|
||||
"""
|
||||
|
||||
name = "BGP"
|
||||
startup = ()
|
||||
shutdown = ("killall bgpd",)
|
||||
|
@ -470,7 +479,7 @@ class Bgp(QuaggaService):
|
|||
cfg = "!\n! BGP configuration\n!\n"
|
||||
cfg += "! You should configure the AS number below,\n"
|
||||
cfg += "! along with this router's peers.\n!\n"
|
||||
cfg += "router bgp %s\n" % node.objid
|
||||
cfg += "router bgp %s\n" % node.id
|
||||
rtrid = cls.routerid(node)
|
||||
cfg += " bgp router-id %s\n" % rtrid
|
||||
cfg += " redistribute connected\n"
|
||||
|
@ -482,6 +491,7 @@ class Rip(QuaggaService):
|
|||
"""
|
||||
The RIP service provides IPv4 routing for wired networks.
|
||||
"""
|
||||
|
||||
name = "RIP"
|
||||
startup = ()
|
||||
shutdown = ("killall ripd",)
|
||||
|
@ -505,6 +515,7 @@ class Ripng(QuaggaService):
|
|||
"""
|
||||
The RIP NG service provides IPv6 routing for wired networks.
|
||||
"""
|
||||
|
||||
name = "RIPNG"
|
||||
startup = ()
|
||||
shutdown = ("killall ripngd",)
|
||||
|
@ -529,6 +540,7 @@ class Babel(QuaggaService):
|
|||
The Babel service provides a loop-avoiding distance-vector routing
|
||||
protocol for IPv6 and IPv4 with fast convergence properties.
|
||||
"""
|
||||
|
||||
name = "Babel"
|
||||
startup = ()
|
||||
shutdown = ("killall babeld",)
|
||||
|
@ -547,8 +559,7 @@ class Babel(QuaggaService):
|
|||
|
||||
@classmethod
|
||||
def generatequaggaifcconfig(cls, node, ifc):
|
||||
type = "wired"
|
||||
if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS.value:
|
||||
if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS:
|
||||
return " babel wireless\n no babel split-horizon\n"
|
||||
else:
|
||||
return " babel wired\n babel split-horizon\n"
|
||||
|
@ -558,28 +569,29 @@ class Xpimd(QuaggaService):
|
|||
"""
|
||||
PIM multicast routing based on XORP.
|
||||
"""
|
||||
name = 'Xpimd'
|
||||
|
||||
name = "Xpimd"
|
||||
startup = ()
|
||||
shutdown = ('killall xpimd',)
|
||||
validate = ('pidof xpimd',)
|
||||
shutdown = ("killall xpimd",)
|
||||
validate = ("pidof xpimd",)
|
||||
ipv4_routing = True
|
||||
|
||||
@classmethod
|
||||
def generatequaggaconfig(cls, node):
|
||||
ifname = 'eth0'
|
||||
ifname = "eth0"
|
||||
for ifc in node.netifs():
|
||||
if ifc.name != 'lo':
|
||||
if ifc.name != "lo":
|
||||
ifname = ifc.name
|
||||
break
|
||||
cfg = 'router mfea\n!\n'
|
||||
cfg += 'router igmp\n!\n'
|
||||
cfg += 'router pim\n'
|
||||
cfg += ' !ip pim rp-address 10.0.0.1\n'
|
||||
cfg += ' ip pim bsr-candidate %s\n' % ifname
|
||||
cfg += ' ip pim rp-candidate %s\n' % ifname
|
||||
cfg += ' !ip pim spt-threshold interval 10 bytes 80000\n'
|
||||
cfg = "router mfea\n!\n"
|
||||
cfg += "router igmp\n!\n"
|
||||
cfg += "router pim\n"
|
||||
cfg += " !ip pim rp-address 10.0.0.1\n"
|
||||
cfg += " ip pim bsr-candidate %s\n" % ifname
|
||||
cfg += " ip pim rp-candidate %s\n" % ifname
|
||||
cfg += " !ip pim spt-threshold interval 10 bytes 80000\n"
|
||||
return cfg
|
||||
|
||||
@classmethod
|
||||
def generatequaggaifcconfig(cls, node, ifc):
|
||||
return ' ip mfea\n ip igmp\n ip pim\n'
|
||||
return " ip mfea\n ip igmp\n ip pim\n"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue