blob: 3d60f5358bb3e60a27203539a3d6e6d5e5f7b4c0 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
#!/usr/bin/env python3
#
# Copyright (C) 2019 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import sys
import jinja2
import copy
import os
import vyos.validate
from vyos import ConfigError
from vyos.config import Config
config_file = r'/tmp/bfd.frr'
# Please be careful if you edit the template.
config_tmpl = """
!
bfd
{% for peer in old_peers -%}
no peer {{ peer }}
{% endfor -%}
!
{% for peer in new_peers -%}
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 %}
detect-multiplier {{ peer.multiplier }}
{% if not peer.shutdown %}no {% endif %}shutdown
{% endfor -%}
!
"""
default_config_data = {
'new_peers': [],
'old_peers' : []
}
def get_config():
bfd = copy.deepcopy(default_config_data)
conf = Config()
if not (conf.exists('protocols bfd') or conf.exists_effective('protocols bfd')):
return None
else:
conf.set_level('protocols bfd')
# 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_nodes('peer'):
conf.set_level('protocols bfd peer {0}'.format(peer))
bfd_peer = {
'remote': peer,
'shutdown': False,
'src_if': '',
'src_addr': '',
'multiplier': '3',
'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')
# 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('multiplier'):
bfd_peer['multiplier'] = conf.return_value('multiplier')
# 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
bfd['new_peers'].append(bfd_peer)
return bfd
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
# 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')
# multihop doesn't accept interface names
if peer['multihop'] and peer['src_if']:
raise ConfigError('multihop does not accept interface names')
return None
def generate(bfd):
if bfd is None:
return None
return None
def apply(bfd):
if bfd is None:
return None
tmpl = jinja2.Template(config_tmpl)
config_text = tmpl.render(bfd)
with open(config_file, 'w') as f:
f.write(config_text)
os.system("sudo vtysh -d bfdd -f " + config_file)
if os.path.exists(config_file):
os.remove(config_file)
return None
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
sys.exit(1)
|