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
|
# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
# - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in
# FRR, there is only a base, per neighbor dynamic capability, migrate config
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
base = ['protocols', 'bgp']
def migrate(config: ConfigTree) -> None:
if not config.exists(base):
# Nothing to do
return
# Check if BGP is actually configured and obtain the ASN
asn_list = config.list_nodes(base)
if asn_list:
# There's always just one BGP node, if any
bgp_base = base + [asn_list[0]]
for neighbor_type in ['neighbor', 'peer-group']:
if not config.exists(bgp_base + [neighbor_type]):
continue
for neighbor in config.list_nodes(bgp_base + [neighbor_type]):
# T2844 - add IPv4 AFI disable-send-community support
send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community']
if config.exists(send_comm_path):
new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast']
config.set(new_base)
config.copy(send_comm_path, new_base + ['disable-send-community'])
config.delete(send_comm_path)
cap_dynamic = False
peer_group = None
for afi in ['ipv4-unicast', 'ipv6-unicast']:
afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi]
# Exit loop early if AFI does not exist
if not config.exists(afi_path):
continue
cap_path = afi_path + ['capability', 'dynamic']
if config.exists(cap_path):
cap_dynamic = True
config.delete(cap_path)
# We have now successfully migrated the address-family
# specific dynamic capability to the neighbor/peer-group
# level. If this has been the only option under the
# address-family nodes, we can clean them up by checking if
# no other nodes are left under that tree and if so, delete
# the parent.
#
# We walk from the most inner node to the most outer one.
cleanup = -1
while len(config.list_nodes(cap_path[:cleanup])) == 0:
config.delete(cap_path[:cleanup])
cleanup -= 1
peer_group_path = afi_path + ['peer-group']
if config.exists(peer_group_path):
if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or
(is_ipv6(neighbor) and afi == 'ipv6-unicast')):
peer_group = config.return_value(peer_group_path)
config.delete(peer_group_path)
# We have now successfully migrated the address-family
# specific peer-group to the neighbor level. If this has
# been the only option under the address-family nodes, we
# can clean them up by checking if no other nodes are left
# under that tree and if so, delete the parent.
#
# We walk from the most inner node to the most outer one.
cleanup = -1
while len(config.list_nodes(peer_group_path[:cleanup])) == 0:
config.delete(peer_group_path[:cleanup])
cleanup -= 1
if cap_dynamic:
config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic'])
if peer_group:
config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group)
|