summaryrefslogtreecommitdiff
path: root/src/conf_mode/protocols_bfd.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/protocols_bfd.py')
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py177
1 files changed, 121 insertions, 56 deletions
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index 04549f4b4..9ca194edd 100755
--- a/src/conf_mode/protocols_bfd.py
+++ b/src/conf_mode/protocols_bfd.py
@@ -31,7 +31,7 @@ config_tmpl = """
!
bfd
{% for peer in old_peers -%}
- no peer {{ peer }}
+ no peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %}
{% endfor -%}
!
{% for peer in new_peers -%}
@@ -39,6 +39,8 @@ bfd
detect-multiplier {{ peer.multiplier }}
receive-interval {{ peer.rx_interval }}
transmit-interval {{ peer.tx_interval }}
+ {% if peer.echo_mode %}echo-mode{% endif %}
+ {% if peer.echo_interval != '' %}echo-interval {{ peer.echo_interval }}{% endif %}
{% if not peer.shutdown %}no {% endif %}shutdown
{% endfor -%}
!
@@ -49,6 +51,86 @@ default_config_data = {
'old_peers' : []
}
+# get configuration for BFD peer from proposed or effective configuration
+def get_bfd_peer_config(peer, conf_mode="proposed"):
+ conf = Config()
+ conf.set_level('protocols bfd peer {0}'.format(peer))
+
+ bfd_peer = {
+ 'remote': peer,
+ 'shutdown': False,
+ 'src_if': '',
+ 'src_addr': '',
+ 'multiplier': '3',
+ 'rx_interval': '300',
+ 'tx_interval': '300',
+ 'multihop': False,
+ 'echo_interval': '',
+ 'echo_mode': False,
+ }
+
+ # Check if individual peer is disabled
+ if conf_mode == "effective" and conf.exists_effective('shutdown'):
+ bfd_peer['shutdown'] = True
+ if conf_mode == "proposed" and conf.exists('shutdown'):
+ bfd_peer['shutdown'] = True
+
+ # Check if peer has a local source interface configured
+ if conf_mode == "effective" and conf.exists_effective('source interface'):
+ bfd_peer['src_if'] = conf.return_effective_value('source interface')
+ if conf_mode == "proposed" and conf.exists('source interface'):
+ bfd_peer['src_if'] = conf.return_value('source interface')
+
+ # Check if peer has a local source address configured - this is mandatory for IPv6
+ if conf_mode == "effective" and conf.exists_effective('source address'):
+ bfd_peer['src_addr'] = conf.return_effective_value('source address')
+ if conf_mode == "proposed" and conf.exists('source address'):
+ bfd_peer['src_addr'] = conf.return_value('source address')
+
+ # Tell BFD daemon that we should expect packets with TTL less than 254
+ # (because it will take more than one hop) and to listen on the multihop
+ # port (4784)
+ if conf_mode == "effective" and conf.exists_effective('multihop'):
+ bfd_peer['multihop'] = True
+ if conf_mode == "proposed" and conf.exists('multihop'):
+ bfd_peer['multihop'] = True
+
+ # Configures the minimum interval that this system is capable of receiving
+ # control packets. The default value is 300 milliseconds.
+ if conf_mode == "effective" and conf.exists_effective('interval receive'):
+ bfd_peer['rx_interval'] = conf.return_effective_value('interval receive')
+ if conf_mode == "proposed" and conf.exists('interval receive'):
+ bfd_peer['rx_interval'] = conf.return_value('interval receive')
+
+ # The minimum transmission interval (less jitter) that this system wants
+ # to use to send BFD control packets.
+ if conf_mode == "effective" and conf.exists_effective('interval transmit'):
+ bfd_peer['tx_interval'] = conf.return_effective_value('interval transmit')
+ if conf_mode == "proposed" and conf.exists('interval transmit'):
+ bfd_peer['tx_interval'] = conf.return_value('interval transmit')
+
+ # Configures the detection multiplier to determine packet loss. The remote
+ # transmission interval will be multiplied by this value to determine the
+ # connection loss detection timer. The default value is 3.
+ if conf_mode == "effective" and conf.exists_effective('interval multiplier'):
+ bfd_peer['multiplier'] = conf.return_effective_value('interval multiplier')
+ if conf_mode == "proposed" and conf.exists('interval multiplier'):
+ bfd_peer['multiplier'] = conf.return_value('interval multiplier')
+
+ # Configures the minimal echo receive transmission interval that this system is capable of handling
+ if conf_mode == "effective" and conf.exists_effective('interval echo-interval'):
+ bfd_peer['echo_interval'] = conf.return_effective_value('interval echo-interval')
+ if conf_mode == "proposed" and conf.exists('interval echo-interval'):
+ bfd_peer['echo_interval'] = conf.return_value('interval echo-interval')
+
+ # Enables or disables the echo transmission mode
+ if conf_mode == "effective" and conf.exists_effective('echo-mode'):
+ bfd_peer['echo_mode'] = True
+ if conf_mode == "proposed" and conf.exists('echo-mode'):
+ bfd_peer['echo_mode'] = True
+
+ return bfd_peer
+
def get_config():
bfd = copy.deepcopy(default_config_data)
conf = Config()
@@ -60,56 +142,16 @@ def get_config():
# as we have to use vtysh to talk to FRR we also need to know
# which peers are gone due to a config removal - thus we read in
# all peers (active or to delete)
- bfd['old_peers'] = conf.list_effective_nodes('peer')
+ for peer in conf.list_effective_nodes('peer'):
+ bfd['old_peers'].append(get_bfd_peer_config(peer, "effective"))
for peer in conf.list_nodes('peer'):
- conf.set_level('protocols bfd peer {0}'.format(peer))
- bfd_peer = {
- 'remote': peer,
- 'shutdown': False,
- 'src_if': '',
- 'src_addr': '',
- 'multiplier': '3',
- 'rx_interval': '300',
- 'tx_interval': '300',
- 'multihop': False
- }
-
- # Check if individual peer is disabled
- if conf.exists('shutdown'):
- bfd_peer['shutdown'] = True
-
- # Check if peer has a local source interface configured
- if conf.exists('source interface'):
- bfd_peer['src_if'] = conf.return_value('source interface')
-
- # Check if peer has a local source address configured - this is mandatory for IPv6
- if conf.exists('source address'):
- bfd_peer['src_addr'] = conf.return_value('source address')
-
- # Tell BFD daemon that we should expect packets with TTL less than 254
- # (because it will take more than one hop) and to listen on the multihop
- # port (4784)
- if conf.exists('multihop'):
- bfd_peer['multihop'] = True
-
- # Configures the minimum interval that this system is capable of receiving
- # control packets. The default value is 300 milliseconds.
- if conf.exists('interval receive'):
- bfd_peer['rx_interval'] = conf.return_value('interval receive')
-
- # The minimum transmission interval (less jitter) that this system wants
- # to use to send BFD control packets.
- if conf.exists('interval transmit'):
- bfd_peer['tx_interval'] = conf.return_value('interval transmit')
-
- # Configures the detection multiplier to determine packet loss. The remote
- # transmission interval will be multiplied by this value to determine the
- # connection loss detection timer. The default value is 3.
- if conf.exists('interval multiplier'):
- bfd_peer['multiplier'] = conf.return_value('interval multiplier')
-
- bfd['new_peers'].append(bfd_peer)
+ bfd['new_peers'].append(get_bfd_peer_config(peer))
+
+ # find deleted peers
+ set_new_peers = set(conf.list_nodes('peer'))
+ set_old_peers = set(conf.list_effective_nodes('peer'))
+ bfd['deleted_peers'] = set_old_peers - set_new_peers
return bfd
@@ -117,20 +159,43 @@ def verify(bfd):
if bfd is None:
return None
- for peer in bfd['new_peers']:
- # Bail out early if peer is shutdown
- if peer['shutdown']:
- continue
+ # some variables to use later
+ conf = Config()
+ for peer in bfd['new_peers']:
# IPv6 peers require an explicit local address/interface combination
if vyos.validate.is_ipv6(peer['remote']):
if not (peer['src_if'] and peer['src_addr']):
- raise ConfigError('BFD IPv6 peers require explicit local address/interface setting')
+ raise ConfigError('BFD IPv6 peers require explicit local address and interface setting')
+
+ # multihop require source address
+ if peer['multihop'] and not peer['src_addr']:
+ raise ConfigError('Multihop require source address')
+
+ # multihop and echo-mode cannot be used together
+ if peer['multihop'] and peer['echo_mode']:
+ raise ConfigError('Multihop and echo-mode cannot be used together')
# multihop doesn't accept interface names
if peer['multihop'] and peer['src_if']:
- raise ConfigError('multihop does not accept interface names')
-
+ raise ConfigError('Multihop and source interface cannot be used together')
+
+ # echo interval can be configured only with enabled echo-mode
+ if peer['echo_interval'] != '' and not peer['echo_mode']:
+ raise ConfigError('echo-interval can be configured only with enabled echo-mode')
+
+ # check if we deleted peers are not used in configuration
+ if conf.exists('protocols bgp'):
+ bgp_as = conf.list_nodes('protocols bgp')[0]
+
+ # check BGP neighbors
+ for peer in bfd['deleted_peers']:
+ if conf.exists('protocols bgp {0} neighbor {1} bfd'.format(bgp_as, peer)):
+ raise ConfigError('Cannot delete BFD peer {0}: it is used in BGP configuration'.format(peer))
+ if conf.exists('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer)):
+ peer_group = conf.return_value('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer))
+ if conf.exists('protocols bgp {0} peer-group {1} bfd'.format(bgp_as, peer_group)):
+ raise ConfigError('Cannot delete BFD peer {0}: it belongs to BGP peer-group {1} with enabled BFD'.format(peer, peer_group))
return None