finished converting quagga services to config services
This commit is contained in:
parent
fcc445bb72
commit
b9cbbf5709
2 changed files with 249 additions and 2 deletions
|
@ -1,12 +1,15 @@
|
||||||
import abc
|
import abc
|
||||||
|
import logging
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core.configservice.base import ConfigService, ConfigServiceMode
|
from core.configservice.base import ConfigService, ConfigServiceMode
|
||||||
|
from core.emane.nodes import EmaneNet
|
||||||
from core.nodes.base import CoreNodeBase
|
from core.nodes.base import CoreNodeBase
|
||||||
from core.nodes.interface import CoreInterface
|
from core.nodes.interface import CoreInterface
|
||||||
|
from core.nodes.network import WlanNode
|
||||||
|
|
||||||
GROUP = "Quagga"
|
GROUP = "Quagga"
|
||||||
|
|
||||||
|
@ -27,6 +30,20 @@ def has_mtu_mismatch(ifc: CoreInterface) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_min_mtu(ifc):
|
||||||
|
"""
|
||||||
|
Helper to discover the minimum MTU of interfaces linked with the
|
||||||
|
given interface.
|
||||||
|
"""
|
||||||
|
mtu = ifc.mtu
|
||||||
|
if not ifc.net:
|
||||||
|
return mtu
|
||||||
|
for i in ifc.net.netifs():
|
||||||
|
if i.mtu < mtu:
|
||||||
|
mtu = i.mtu
|
||||||
|
return mtu
|
||||||
|
|
||||||
|
|
||||||
def get_router_id(node: CoreNodeBase) -> str:
|
def get_router_id(node: CoreNodeBase) -> str:
|
||||||
"""
|
"""
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
|
@ -168,3 +185,231 @@ class Ospfv2(QuaggaService, ConfigService):
|
||||||
!
|
!
|
||||||
"""
|
"""
|
||||||
return self.render_text(text, data)
|
return self.render_text(text, data)
|
||||||
|
|
||||||
|
|
||||||
|
class Ospfv3(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
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"
|
||||||
|
shutdown = ("killall ospf6d",)
|
||||||
|
validate = ("pidof ospf6d",)
|
||||||
|
ipv4_routing = True
|
||||||
|
ipv6_routing = True
|
||||||
|
|
||||||
|
def quagga_interface_config(self, ifc: CoreInterface) -> str:
|
||||||
|
mtu = get_min_mtu(ifc)
|
||||||
|
if mtu < ifc.mtu:
|
||||||
|
return f"ipv6 ospf6 ifmtu {mtu}"
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def quagga_config(self) -> str:
|
||||||
|
router_id = get_router_id(self.node)
|
||||||
|
ifnames = []
|
||||||
|
for ifc in self.node.netifs():
|
||||||
|
if getattr(ifc, "control", False):
|
||||||
|
continue
|
||||||
|
ifnames.append(ifc.name)
|
||||||
|
data = dict(router_id=router_id, ifnames=ifnames)
|
||||||
|
text = """
|
||||||
|
router ospf6
|
||||||
|
instance-id 65
|
||||||
|
router-id ${router_id}
|
||||||
|
% for ifname in ifnames:
|
||||||
|
interface ${ifname} area 0.0.0.0
|
||||||
|
% endfor
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
return self.render_text(text, data)
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "OSPFv3MDR"
|
||||||
|
|
||||||
|
def data(self) -> Dict[str, Any]:
|
||||||
|
for ifc in self.node.netifs():
|
||||||
|
is_wireless = isinstance(ifc.net, (WlanNode, EmaneNet))
|
||||||
|
logging.info("MDR wireless: %s", is_wireless)
|
||||||
|
return dict()
|
||||||
|
|
||||||
|
def quagga_interface_config(self, ifc: CoreInterface) -> str:
|
||||||
|
config = super().quagga_interface_config(ifc)
|
||||||
|
if isinstance(ifc.net, (WlanNode, EmaneNet)):
|
||||||
|
config = self.clean_text(
|
||||||
|
f"""
|
||||||
|
{config}
|
||||||
|
ipv6 ospf6 hello-interval 2
|
||||||
|
ipv6 ospf6 dead-interval 6
|
||||||
|
ipv6 ospf6 retransmit-interval 5
|
||||||
|
ipv6 ospf6 network manet-designated-router
|
||||||
|
ipv6 ospf6 twohoprefresh 3
|
||||||
|
ipv6 ospf6 adjacencyconnectivity uniconnected
|
||||||
|
ipv6 ospf6 lsafullness mincostlsa
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
class Bgp(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
The BGP service provides interdomain routing.
|
||||||
|
Peers must be manually configured, with a full mesh for those
|
||||||
|
having the same AS number.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "BGP"
|
||||||
|
shutdown = ["killall bgpd"]
|
||||||
|
validate = ["pidof bgpd"]
|
||||||
|
ipv4_routing = True
|
||||||
|
ipv6_routing = True
|
||||||
|
|
||||||
|
def quagga_interface_config(self, ifc: CoreInterface) -> str:
|
||||||
|
router_id = get_router_id(self.node)
|
||||||
|
text = f"""
|
||||||
|
! BGP configuration
|
||||||
|
! You should configure the AS number below
|
||||||
|
! along with this router's peers.
|
||||||
|
router bgp {self.node.id}
|
||||||
|
bgp router-id {router_id}
|
||||||
|
redistribute connected
|
||||||
|
!neighbor 1.2.3.4 remote-as 555
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
class Rip(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
The RIP service provides IPv4 routing for wired networks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "RIP"
|
||||||
|
shutdown = ["killall ripd"]
|
||||||
|
validate = ["pidof ripd"]
|
||||||
|
ipv4_routing = True
|
||||||
|
|
||||||
|
def quagga_config(self) -> str:
|
||||||
|
text = """
|
||||||
|
router rip
|
||||||
|
redistribute static
|
||||||
|
redistribute connected
|
||||||
|
redistribute ospf
|
||||||
|
network 0.0.0.0/0
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
class Ripng(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
The RIP NG service provides IPv6 routing for wired networks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "RIPNG"
|
||||||
|
shutdown = ["killall ripngd"]
|
||||||
|
validate = ["pidof ripngd"]
|
||||||
|
ipv6_routing = True
|
||||||
|
|
||||||
|
def quagga_config(self) -> str:
|
||||||
|
text = """
|
||||||
|
router ripng
|
||||||
|
redistribute static
|
||||||
|
redistribute connected
|
||||||
|
redistribute ospf6
|
||||||
|
network ::/0
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
class Babel(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
The Babel service provides a loop-avoiding distance-vector routing
|
||||||
|
protocol for IPv6 and IPv4 with fast convergence properties.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Babel"
|
||||||
|
shutdown = ["killall babeld"]
|
||||||
|
validate = ["pidof babeld"]
|
||||||
|
ipv6_routing = True
|
||||||
|
|
||||||
|
def quagga_config(self) -> str:
|
||||||
|
ifnames = []
|
||||||
|
for ifc in self.node.netifs():
|
||||||
|
if getattr(ifc, "control", False):
|
||||||
|
continue
|
||||||
|
ifnames.append(ifc.name)
|
||||||
|
text = """
|
||||||
|
router babel
|
||||||
|
% for ifname in ifnames:
|
||||||
|
network ${ifname}
|
||||||
|
% endfor
|
||||||
|
redistribute static
|
||||||
|
redistribute connected
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
data = dict(ifnames=ifnames)
|
||||||
|
return self.render_text(text, data)
|
||||||
|
|
||||||
|
def quagga_interface_config(self, ifc: CoreInterface) -> str:
|
||||||
|
if isinstance(ifc.net, (WlanNode, EmaneNet)):
|
||||||
|
text = """
|
||||||
|
babel wireless
|
||||||
|
no babel split-horizon
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
text = """
|
||||||
|
babel wired
|
||||||
|
babel split-horizon
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
class Xpimd(QuaggaService, ConfigService):
|
||||||
|
"""
|
||||||
|
PIM multicast routing based on XORP.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "Xpimd"
|
||||||
|
shutdown = ["killall xpimd"]
|
||||||
|
validate = ["pidof xpimd"]
|
||||||
|
ipv4_routing = True
|
||||||
|
|
||||||
|
def quagga_config(self) -> str:
|
||||||
|
ifname = "eth0"
|
||||||
|
for ifc in self.node.netifs():
|
||||||
|
if ifc.name != "lo":
|
||||||
|
ifname = ifc.name
|
||||||
|
break
|
||||||
|
|
||||||
|
text = f"""
|
||||||
|
router mfea
|
||||||
|
!
|
||||||
|
router igmp
|
||||||
|
!
|
||||||
|
router pim
|
||||||
|
!ip pim rp-address 10.0.0.1
|
||||||
|
ip pim bsr-candidate {ifname}
|
||||||
|
ip pim rp-candidate {ifname}
|
||||||
|
!ip pim spt-threshold interval 10 bytes 80000
|
||||||
|
!
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
||||||
|
def quagga_interface_config(self, ifc: CoreInterface) -> str:
|
||||||
|
text = """
|
||||||
|
ip mfea
|
||||||
|
ip pim
|
||||||
|
"""
|
||||||
|
return self.clean_text(text)
|
||||||
|
|
|
@ -10,9 +10,11 @@ interface ${ifc.name}
|
||||||
ipv6 address ${addr}
|
ipv6 address ${addr}
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
% endif
|
||||||
% if is_control:
|
% if not is_control:
|
||||||
% for service in services:
|
% for service in services:
|
||||||
${service.quagga_interface_config(ifc)}
|
% for line in service.quagga_interface_config(ifc).split("\n"):
|
||||||
|
${line}
|
||||||
|
% endfor
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
% endif
|
||||||
!
|
!
|
||||||
|
|
Loading…
Add table
Reference in a new issue