mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-29 23:09:34 +00:00
Merge pull request #10048 from qlyoung/fix-reload-doc-comments
Fix reload comments
This commit is contained in:
commit
fd7d888003
@ -172,7 +172,6 @@ class Vtysh(object):
|
||||
|
||||
|
||||
class Context(object):
|
||||
|
||||
"""
|
||||
A Context object represents a section of frr configuration such as:
|
||||
!
|
||||
@ -234,7 +233,6 @@ def get_normalized_mac_ip_line(line):
|
||||
|
||||
|
||||
class Config(object):
|
||||
|
||||
"""
|
||||
A frr configuration is stored in a Config object. A Config object
|
||||
contains a dictionary of Context objects where the Context keys
|
||||
@ -265,22 +263,20 @@ class Config(object):
|
||||
if ":" in line:
|
||||
line = get_normalized_mac_ip_line(line)
|
||||
|
||||
"""
|
||||
vrf static routes can be added in two ways. The old way is:
|
||||
|
||||
"ip route x.x.x.x/x y.y.y.y vrf <vrfname>"
|
||||
|
||||
but it's rendered in the configuration as the new way::
|
||||
|
||||
vrf <vrf-name>
|
||||
ip route x.x.x.x/x y.y.y.y
|
||||
exit-vrf
|
||||
|
||||
this difference causes frr-reload to not consider them a
|
||||
match and delete vrf static routes incorrectly.
|
||||
fix the old way to match new "show running" output so a
|
||||
proper match is found.
|
||||
"""
|
||||
# vrf static routes can be added in two ways. The old way is:
|
||||
#
|
||||
# "ip route x.x.x.x/x y.y.y.y vrf <vrfname>"
|
||||
#
|
||||
# but it's rendered in the configuration as the new way::
|
||||
#
|
||||
# vrf <vrf-name>
|
||||
# ip route x.x.x.x/x y.y.y.y
|
||||
# exit-vrf
|
||||
#
|
||||
# this difference causes frr-reload to not consider them a
|
||||
# match and delete vrf static routes incorrectly.
|
||||
# fix the old way to match new "show running" output so a
|
||||
# proper match is found.
|
||||
if (
|
||||
line.startswith("ip route ") or line.startswith("ipv6 route ")
|
||||
) and " vrf " in line:
|
||||
@ -326,14 +322,12 @@ class Config(object):
|
||||
"""
|
||||
Return the lines read in from the configuration
|
||||
"""
|
||||
|
||||
return "\n".join(self.lines)
|
||||
|
||||
def get_contexts(self):
|
||||
"""
|
||||
Return the parsed context as strings for display, log etc.
|
||||
"""
|
||||
|
||||
for (_, ctx) in sorted(iteritems(self.contexts)):
|
||||
print(str(ctx) + "\n")
|
||||
|
||||
@ -341,18 +335,15 @@ class Config(object):
|
||||
"""
|
||||
Save the provided key and lines as a context
|
||||
"""
|
||||
|
||||
if not key:
|
||||
return
|
||||
|
||||
"""
|
||||
IP addresses specified in "network" statements, "ip prefix-lists"
|
||||
etc. can differ in the host part of the specification the user
|
||||
provides and what the running config displays. For example, user
|
||||
can specify 11.1.1.1/24, and the running config displays this as
|
||||
11.1.1.0/24. Ensure we don't do a needless operation for such
|
||||
lines. IS-IS & OSPFv3 have no "network" support.
|
||||
"""
|
||||
# IP addresses specified in "network" statements, "ip prefix-lists"
|
||||
# etc. can differ in the host part of the specification the user
|
||||
# provides and what the running config displays. For example, user can
|
||||
# specify 11.1.1.1/24, and the running config displays this as
|
||||
# 11.1.1.0/24. Ensure we don't do a needless operation for such lines.
|
||||
# IS-IS & OSPFv3 have no "network" support.
|
||||
re_key_rt = re.match(r"(ip|ipv6)\s+route\s+([A-Fa-f:.0-9/]+)(.*)$", key[0])
|
||||
if re_key_rt:
|
||||
addr = re_key_rt.group(2)
|
||||
@ -430,10 +421,8 @@ class Config(object):
|
||||
newlines.append(line)
|
||||
lines = newlines
|
||||
|
||||
"""
|
||||
More fixups in user specification and what running config shows.
|
||||
"null0" in routes must be replaced by Null0.
|
||||
"""
|
||||
# More fixups in user specification and what running config shows.
|
||||
# "null0" in routes must be replaced by Null0.
|
||||
if (
|
||||
key[0].startswith("ip route")
|
||||
or key[0].startswith("ipv6 route")
|
||||
@ -441,10 +430,8 @@ class Config(object):
|
||||
):
|
||||
key[0] = re.sub(r"\s+null0(\s*$)", " Null0", key[0])
|
||||
|
||||
"""
|
||||
Similar to above, but when the static is in a vrf, it turns into a
|
||||
blackhole nexthop for both null0 and Null0. Fix it accordingly
|
||||
"""
|
||||
# Similar to above, but when the static is in a vrf, it turns into a
|
||||
# blackhole nexthop for both null0 and Null0. Fix it accordingly
|
||||
if lines and key[0].startswith("vrf "):
|
||||
newlines = []
|
||||
for line in lines:
|
||||
@ -474,71 +461,69 @@ class Config(object):
|
||||
def load_contexts(self):
|
||||
"""
|
||||
Parse the configuration and create contexts for each appropriate block
|
||||
"""
|
||||
|
||||
"""
|
||||
The end of a context is flagged via the 'end' keyword:
|
||||
|
||||
!
|
||||
interface swp52
|
||||
ipv6 nd suppress-ra
|
||||
link-detect
|
||||
!
|
||||
end
|
||||
router bgp 10
|
||||
bgp router-id 10.0.0.1
|
||||
bgp log-neighbor-changes
|
||||
no bgp default ipv4-unicast
|
||||
neighbor EBGP peer-group
|
||||
neighbor EBGP advertisement-interval 1
|
||||
neighbor EBGP timers connect 10
|
||||
neighbor 2001:40:1:4::6 remote-as 40
|
||||
neighbor 2001:40:1:8::a remote-as 40
|
||||
!
|
||||
end
|
||||
address-family ipv6
|
||||
neighbor IBGPv6 activate
|
||||
neighbor 2001:10::2 peer-group IBGPv6
|
||||
neighbor 2001:10::3 peer-group IBGPv6
|
||||
exit-address-family
|
||||
!
|
||||
end
|
||||
address-family evpn
|
||||
neighbor LEAF activate
|
||||
advertise-all-vni
|
||||
vni 10100
|
||||
rd 65000:10100
|
||||
route-target import 10.1.1.1:10100
|
||||
route-target export 10.1.1.1:10100
|
||||
exit-vni
|
||||
exit-address-family
|
||||
!
|
||||
end
|
||||
router ospf
|
||||
ospf router-id 10.0.0.1
|
||||
log-adjacency-changes detail
|
||||
timers throttle spf 0 50 5000
|
||||
!
|
||||
end
|
||||
!
|
||||
interface swp52
|
||||
ipv6 nd suppress-ra
|
||||
link-detect
|
||||
!
|
||||
end
|
||||
router bgp 10
|
||||
bgp router-id 10.0.0.1
|
||||
bgp log-neighbor-changes
|
||||
no bgp default ipv4-unicast
|
||||
neighbor EBGP peer-group
|
||||
neighbor EBGP advertisement-interval 1
|
||||
neighbor EBGP timers connect 10
|
||||
neighbor 2001:40:1:4::6 remote-as 40
|
||||
neighbor 2001:40:1:8::a remote-as 40
|
||||
!
|
||||
end
|
||||
address-family ipv6
|
||||
neighbor IBGPv6 activate
|
||||
neighbor 2001:10::2 peer-group IBGPv6
|
||||
neighbor 2001:10::3 peer-group IBGPv6
|
||||
exit-address-family
|
||||
!
|
||||
end
|
||||
address-family evpn
|
||||
neighbor LEAF activate
|
||||
advertise-all-vni
|
||||
vni 10100
|
||||
rd 65000:10100
|
||||
route-target import 10.1.1.1:10100
|
||||
route-target export 10.1.1.1:10100
|
||||
exit-vni
|
||||
exit-address-family
|
||||
!
|
||||
end
|
||||
router ospf
|
||||
ospf router-id 10.0.0.1
|
||||
log-adjacency-changes detail
|
||||
timers throttle spf 0 50 5000
|
||||
!
|
||||
end
|
||||
|
||||
The code assumes that its working on the output from the "vtysh -m"
|
||||
command. That provides the appropriate markers to signify end of
|
||||
a context. This routine uses that to build the contexts for the
|
||||
config.
|
||||
|
||||
There are single line contexts such as "log file /media/node/zebra.log"
|
||||
and multi-line contexts such as "router ospf" and subcontexts
|
||||
within a context such as "address-family" within "router bgp"
|
||||
In each of these cases, the first line of the context becomes the
|
||||
key of the context. So "router bgp 10" is the key for the non-address
|
||||
family part of bgp, "router bgp 10, address-family ipv6 unicast" is
|
||||
the key for the subcontext and so on.
|
||||
|
||||
This dictionary contains a tree of all commands that we know start a
|
||||
new multi-line context. All other commands are treated either as
|
||||
commands inside a multi-line context or as single-line contexts. This
|
||||
dictionary should be updated whenever a new node is added to FRR.
|
||||
"""
|
||||
|
||||
# The code assumes that its working on the output from the "vtysh -m"
|
||||
# command. That provides the appropriate markers to signify end of
|
||||
# a context. This routine uses that to build the contexts for the
|
||||
# config.
|
||||
#
|
||||
# There are single line contexts such as "log file /media/node/zebra.log"
|
||||
# and multi-line contexts such as "router ospf" and subcontexts
|
||||
# within a context such as "address-family" within "router bgp"
|
||||
# In each of these cases, the first line of the context becomes the
|
||||
# key of the context. So "router bgp 10" is the key for the non-address
|
||||
# family part of bgp, "router bgp 10, address-family ipv6 unicast" is
|
||||
# the key for the subcontext and so on.
|
||||
|
||||
# This dictionary contains a tree of all commands that we know start a
|
||||
# new multi-line context. All other commands are treated either as
|
||||
# commands inside a multi-line context or as single-line contexts. This
|
||||
# dictionary should be updated whenever a new node is added to FRR.
|
||||
ctx_keywords = {
|
||||
"router bgp ": {
|
||||
"address-family ": {
|
||||
@ -788,16 +773,12 @@ def check_for_exit_vrf(lines_to_add, lines_to_del):
|
||||
return (lines_to_add, lines_to_del)
|
||||
|
||||
|
||||
"""
|
||||
This method handles deletion of bgp peer group config.
|
||||
The objective is to delete config lines related to peers
|
||||
associated with the peer-group and move the peer-group
|
||||
config line to the end of the lines_to_del list.
|
||||
"""
|
||||
|
||||
|
||||
def delete_move_lines(lines_to_add, lines_to_del):
|
||||
|
||||
"""
|
||||
This function handles deletion of bgp peer group config. The objective is
|
||||
to delete config lines related to peers associated with the peer-group and
|
||||
move the peer-group config line to the end of the lines_to_del list.
|
||||
"""
|
||||
del_dict = dict()
|
||||
# Stores the lines to move to the end of the pending list.
|
||||
lines_to_del_to_del = []
|
||||
@ -805,54 +786,51 @@ def delete_move_lines(lines_to_add, lines_to_del):
|
||||
lines_to_del_to_app = []
|
||||
found_pg_del_cmd = False
|
||||
|
||||
"""
|
||||
When "neighbor <pg_name> peer-group" under a bgp instance is removed,
|
||||
it also deletes the associated peer config. Any config line below no form of
|
||||
peer-group related to a peer are errored out as the peer no longer exists.
|
||||
To cleanup peer-group and associated peer(s) configs:
|
||||
- Remove all the peers config lines from the pending list (lines_to_del list).
|
||||
- Move peer-group deletion line to the end of the pending list, to allow
|
||||
removal of any of the peer-group specific configs.
|
||||
# When "neighbor <pg_name> peer-group" under a bgp instance is removed,
|
||||
# it also deletes the associated peer config. Any config line below no form of
|
||||
# peer-group related to a peer are errored out as the peer no longer exists.
|
||||
# To cleanup peer-group and associated peer(s) configs:
|
||||
# - Remove all the peers config lines from the pending list (lines_to_del list).
|
||||
# - Move peer-group deletion line to the end of the pending list, to allow
|
||||
# removal of any of the peer-group specific configs.
|
||||
#
|
||||
# Create a dictionary of config context (i.e. router bgp vrf x).
|
||||
# Under each context node, create a dictionary of a peer-group name.
|
||||
# Append a peer associated to the peer-group into a list under a peer-group node.
|
||||
# Remove all of the peer associated config lines from the pending list.
|
||||
# Append peer-group deletion line to end of the pending list.
|
||||
#
|
||||
# Example:
|
||||
# neighbor underlay peer-group
|
||||
# neighbor underlay remote-as external
|
||||
# neighbor underlay advertisement-interval 0
|
||||
# neighbor underlay timers 3 9
|
||||
# neighbor underlay timers connect 10
|
||||
# neighbor swp1 interface peer-group underlay
|
||||
# neighbor swp1 advertisement-interval 0
|
||||
# neighbor swp1 timers 3 9
|
||||
# neighbor swp1 timers connect 10
|
||||
# neighbor swp2 interface peer-group underlay
|
||||
# neighbor swp2 advertisement-interval 0
|
||||
# neighbor swp2 timers 3 9
|
||||
# neighbor swp2 timers connect 10
|
||||
# neighbor swp3 interface peer-group underlay
|
||||
# neighbor uplink1 interface remote-as internal
|
||||
# neighbor uplink1 advertisement-interval 0
|
||||
# neighbor uplink1 timers 3 9
|
||||
# neighbor uplink1 timers connect 10
|
||||
|
||||
Create a dictionary of config context (i.e. router bgp vrf x).
|
||||
Under each context node, create a dictionary of a peer-group name.
|
||||
Append a peer associated to the peer-group into a list under a peer-group node.
|
||||
Remove all of the peer associated config lines from the pending list.
|
||||
Append peer-group deletion line to end of the pending list.
|
||||
|
||||
Example:
|
||||
neighbor underlay peer-group
|
||||
neighbor underlay remote-as external
|
||||
neighbor underlay advertisement-interval 0
|
||||
neighbor underlay timers 3 9
|
||||
neighbor underlay timers connect 10
|
||||
neighbor swp1 interface peer-group underlay
|
||||
neighbor swp1 advertisement-interval 0
|
||||
neighbor swp1 timers 3 9
|
||||
neighbor swp1 timers connect 10
|
||||
neighbor swp2 interface peer-group underlay
|
||||
neighbor swp2 advertisement-interval 0
|
||||
neighbor swp2 timers 3 9
|
||||
neighbor swp2 timers connect 10
|
||||
neighbor swp3 interface peer-group underlay
|
||||
neighbor uplink1 interface remote-as internal
|
||||
neighbor uplink1 advertisement-interval 0
|
||||
neighbor uplink1 timers 3 9
|
||||
neighbor uplink1 timers connect 10
|
||||
|
||||
New order:
|
||||
"router bgp 200 no bgp bestpath as-path multipath-relax"
|
||||
"router bgp 200 no neighbor underlay advertisement-interval 0"
|
||||
"router bgp 200 no neighbor underlay timers 3 9"
|
||||
"router bgp 200 no neighbor underlay timers connect 10"
|
||||
"router bgp 200 no neighbor uplink1 advertisement-interval 0"
|
||||
"router bgp 200 no neighbor uplink1 timers 3 9"
|
||||
"router bgp 200 no neighbor uplink1 timers connect 10"
|
||||
"router bgp 200 no neighbor underlay remote-as external"
|
||||
"router bgp 200 no neighbor uplink1 interface remote-as internal"
|
||||
"router bgp 200 no neighbor underlay peer-group"
|
||||
|
||||
"""
|
||||
# New order:
|
||||
# "router bgp 200 no bgp bestpath as-path multipath-relax"
|
||||
# "router bgp 200 no neighbor underlay advertisement-interval 0"
|
||||
# "router bgp 200 no neighbor underlay timers 3 9"
|
||||
# "router bgp 200 no neighbor underlay timers connect 10"
|
||||
# "router bgp 200 no neighbor uplink1 advertisement-interval 0"
|
||||
# "router bgp 200 no neighbor uplink1 timers 3 9"
|
||||
# "router bgp 200 no neighbor uplink1 timers connect 10"
|
||||
# "router bgp 200 no neighbor underlay remote-as external"
|
||||
# "router bgp 200 no neighbor uplink1 interface remote-as internal"
|
||||
# "router bgp 200 no neighbor underlay peer-group"
|
||||
|
||||
for (ctx_keys, line) in lines_to_del:
|
||||
if (
|
||||
@ -860,37 +838,33 @@ def delete_move_lines(lines_to_add, lines_to_del):
|
||||
and line
|
||||
and line.startswith("neighbor ")
|
||||
):
|
||||
"""
|
||||
When 'neighbor <peer> remote-as <>' is removed it deletes the peer,
|
||||
there might be a peer associated config which also needs to be removed
|
||||
prior to peer.
|
||||
Append the 'neighbor <peer> remote-as <>' to the lines_to_del.
|
||||
Example:
|
||||
# When 'neighbor <peer> remote-as <>' is removed it deletes the peer,
|
||||
# there might be a peer associated config which also needs to be removed
|
||||
# prior to peer.
|
||||
# Append the 'neighbor <peer> remote-as <>' to the lines_to_del.
|
||||
# Example:
|
||||
#
|
||||
# neighbor uplink1 interface remote-as internal
|
||||
# neighbor uplink1 advertisement-interval 0
|
||||
# neighbor uplink1 timers 3 9
|
||||
# neighbor uplink1 timers connect 10
|
||||
|
||||
neighbor uplink1 interface remote-as internal
|
||||
neighbor uplink1 advertisement-interval 0
|
||||
neighbor uplink1 timers 3 9
|
||||
neighbor uplink1 timers connect 10
|
||||
|
||||
Move to end:
|
||||
neighbor uplink1 advertisement-interval 0
|
||||
neighbor uplink1 timers 3 9
|
||||
neighbor uplink1 timers connect 10
|
||||
...
|
||||
|
||||
neighbor uplink1 interface remote-as internal
|
||||
|
||||
"""
|
||||
# Move to end:
|
||||
# neighbor uplink1 advertisement-interval 0
|
||||
# neighbor uplink1 timers 3 9
|
||||
# neighbor uplink1 timers connect 10
|
||||
# ...
|
||||
#
|
||||
# neighbor uplink1 interface remote-as internal
|
||||
#
|
||||
# 'no neighbor peer [interface] remote-as <>'
|
||||
nb_remoteas = "neighbor (\S+) .*remote-as (\S+)"
|
||||
re_nb_remoteas = re.search(nb_remoteas, line)
|
||||
if re_nb_remoteas:
|
||||
lines_to_del_to_app.append((ctx_keys, line))
|
||||
|
||||
"""
|
||||
{'router bgp 65001': {'PG': [], 'PG1': []},
|
||||
'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}}
|
||||
"""
|
||||
# {'router bgp 65001': {'PG': [], 'PG1': []},
|
||||
# 'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}}
|
||||
if ctx_keys[0] not in del_dict:
|
||||
del_dict[ctx_keys[0]] = dict()
|
||||
# find 'no neighbor <pg_name> peer-group'
|
||||
@ -905,10 +879,8 @@ def delete_move_lines(lines_to_add, lines_to_del):
|
||||
if found_pg_del_cmd == False:
|
||||
return (lines_to_add, lines_to_del)
|
||||
|
||||
"""
|
||||
{'router bgp 65001': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']},
|
||||
'router bgp 65001 vrf vrf1': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}}
|
||||
"""
|
||||
# {'router bgp 65001': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']},
|
||||
# 'router bgp 65001 vrf vrf1': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}}
|
||||
for (ctx_keys, line) in lines_to_del:
|
||||
if (
|
||||
ctx_keys[0].startswith("router bgp")
|
||||
@ -982,25 +954,22 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
if ctx_keys[0].startswith("router bgp") and line:
|
||||
|
||||
if line.startswith("neighbor "):
|
||||
"""
|
||||
BGP changed how it displays swpX peers that are part of peer-group. Older
|
||||
versions of frr would display these on separate lines:
|
||||
neighbor swp1 interface
|
||||
neighbor swp1 peer-group FOO
|
||||
|
||||
but today we display via a single line
|
||||
neighbor swp1 interface peer-group FOO
|
||||
|
||||
This change confuses frr-reload.py so check to see if we are deleting
|
||||
neighbor swp1 interface peer-group FOO
|
||||
|
||||
and adding
|
||||
neighbor swp1 interface
|
||||
neighbor swp1 peer-group FOO
|
||||
|
||||
If so then chop the del line and the corresponding add lines
|
||||
"""
|
||||
|
||||
# BGP changed how it displays swpX peers that are part of peer-group. Older
|
||||
# versions of frr would display these on separate lines:
|
||||
# neighbor swp1 interface
|
||||
# neighbor swp1 peer-group FOO
|
||||
#
|
||||
# but today we display via a single line
|
||||
# neighbor swp1 interface peer-group FOO
|
||||
#
|
||||
# This change confuses frr-reload.py so check to see if we are deleting
|
||||
# neighbor swp1 interface peer-group FOO
|
||||
#
|
||||
# and adding
|
||||
# neighbor swp1 interface
|
||||
# neighbor swp1 peer-group FOO
|
||||
#
|
||||
# If so then chop the del line and the corresponding add lines
|
||||
re_swpx_int_peergroup = re.search(
|
||||
"neighbor (\S+) interface peer-group (\S+)", line
|
||||
)
|
||||
@ -1052,12 +1021,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_add_to_del.append((ctx_keys, swpx_interface))
|
||||
lines_to_add_to_del.append((tmp_ctx_keys, swpx_peergroup))
|
||||
|
||||
"""
|
||||
Changing the bfd timers on neighbors is allowed without doing
|
||||
a delete/add process. Since doing a "no neighbor blah bfd ..."
|
||||
will cause the peer to bounce unnecessarily, just skip the delete
|
||||
and just do the add.
|
||||
"""
|
||||
# Changing the bfd timers on neighbors is allowed without doing
|
||||
# a delete/add process. Since doing a "no neighbor blah bfd
|
||||
# ..." will cause the peer to bounce unnecessarily, just skip
|
||||
# the delete and just do the add.
|
||||
re_nbr_bfd_timers = re.search(
|
||||
r"neighbor (\S+) bfd (\S+) (\S+) (\S+)", line
|
||||
)
|
||||
@ -1081,16 +1048,14 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
if found_add_bfd_nbr:
|
||||
lines_to_del_to_del.append((ctx_keys, line))
|
||||
|
||||
"""
|
||||
Neighbor changes of route-maps need to be accounted for in that we
|
||||
do not want to do a `no route-map...` `route-map ....` when changing
|
||||
a route-map. This is bad mojo as that we will send/receive
|
||||
data we don't want.
|
||||
Additionally we need to ensure that if we have different afi/safi
|
||||
variants that they actually match and if we are going from a very
|
||||
old style command such that the neighbor command is under the
|
||||
`router bgp ..` node that we need to handle that appropriately
|
||||
"""
|
||||
# Neighbor changes of route-maps need to be accounted for in
|
||||
# that we do not want to do a `no route-map...` `route-map
|
||||
# ....` when changing a route-map. This is bad mojo as that we
|
||||
# will send/receive data we don't want. Additionally we need
|
||||
# to ensure that if we have different afi/safi variants that
|
||||
# they actually match and if we are going from a very old style
|
||||
# command such that the neighbor command is under the `router
|
||||
# bgp ..` node that we need to handle that appropriately
|
||||
re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line)
|
||||
if re_nbr_rm:
|
||||
adjust_for_bgp_node = 0
|
||||
@ -1128,29 +1093,27 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
if save_line == dl_line:
|
||||
lines_to_del_to_del.append((ctx_keys_dl, save_line))
|
||||
|
||||
"""
|
||||
We changed how we display the neighbor interface command. Older
|
||||
versions of frr would display the following:
|
||||
neighbor swp1 interface
|
||||
neighbor swp1 remote-as external
|
||||
neighbor swp1 capability extended-nexthop
|
||||
|
||||
but today we display via a single line
|
||||
neighbor swp1 interface remote-as external
|
||||
|
||||
and capability extended-nexthop is no longer needed because we
|
||||
automatically enable it when the neighbor is of type interface.
|
||||
|
||||
This change confuses frr-reload.py so check to see if we are deleting
|
||||
neighbor swp1 interface remote-as (external|internal|ASNUM)
|
||||
|
||||
and adding
|
||||
neighbor swp1 interface
|
||||
neighbor swp1 remote-as (external|internal|ASNUM)
|
||||
neighbor swp1 capability extended-nexthop
|
||||
|
||||
If so then chop the del line and the corresponding add lines
|
||||
"""
|
||||
# We changed how we display the neighbor interface command. Older
|
||||
# versions of frr would display the following:
|
||||
# neighbor swp1 interface
|
||||
# neighbor swp1 remote-as external
|
||||
# neighbor swp1 capability extended-nexthop
|
||||
#
|
||||
# but today we display via a single line
|
||||
# neighbor swp1 interface remote-as external
|
||||
#
|
||||
# and capability extended-nexthop is no longer needed because we
|
||||
# automatically enable it when the neighbor is of type interface.
|
||||
#
|
||||
# This change confuses frr-reload.py so check to see if we are deleting
|
||||
# neighbor swp1 interface remote-as (external|internal|ASNUM)
|
||||
#
|
||||
# and adding
|
||||
# neighbor swp1 interface
|
||||
# neighbor swp1 remote-as (external|internal|ASNUM)
|
||||
# neighbor swp1 capability extended-nexthop
|
||||
#
|
||||
# If so then chop the del line and the corresponding add lines
|
||||
re_swpx_int_remoteas = re.search(
|
||||
"neighbor (\S+) interface remote-as (\S+)", line
|
||||
)
|
||||
@ -1186,15 +1149,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_add_to_del.append((ctx_keys, swpx_interface))
|
||||
lines_to_add_to_del.append((tmp_ctx_keys, swpx_remoteas))
|
||||
|
||||
"""
|
||||
We made the 'bgp bestpath as-path multipath-relax' command
|
||||
automatically assume 'no-as-set' since the lack of this option caused
|
||||
weird routing problems. When the running config is shown in
|
||||
releases with this change, the no-as-set keyword is not shown as it
|
||||
is the default. This causes frr-reload to unnecessarily unapply
|
||||
this option only to apply it back again, causing unnecessary session
|
||||
resets.
|
||||
"""
|
||||
# We made the 'bgp bestpath as-path multipath-relax' command
|
||||
# automatically assume 'no-as-set' since the lack of this option
|
||||
# caused weird routing problems. When the running config is shown
|
||||
# in releases with this change, the no-as-set keyword is not shown
|
||||
# as it is the default. This causes frr-reload to unnecessarily
|
||||
# unapply this option only to apply it back again, causing
|
||||
# unnecessary session resets.
|
||||
if "multipath-relax" in line:
|
||||
re_asrelax_new = re.search(
|
||||
"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line
|
||||
@ -1207,25 +1168,21 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_del_to_del.append((ctx_keys, line))
|
||||
lines_to_add_to_del.append((ctx_keys, old_asrelax_cmd))
|
||||
|
||||
"""
|
||||
If we are modifying the BGP table-map we need to avoid a del/add and
|
||||
instead modify the table-map in place via an add. This is needed to
|
||||
avoid installing all routes in the RIB the second the 'no table-map'
|
||||
is issued.
|
||||
"""
|
||||
# If we are modifying the BGP table-map we need to avoid a del/add
|
||||
# and instead modify the table-map in place via an add. This is
|
||||
# needed to avoid installing all routes in the RIB the second the
|
||||
# 'no table-map' is issued.
|
||||
if line.startswith("table-map"):
|
||||
found_table_map = line_exist(lines_to_add, ctx_keys, "table-map", False)
|
||||
|
||||
if found_table_map:
|
||||
lines_to_del_to_del.append((ctx_keys, line))
|
||||
|
||||
"""
|
||||
More old-to-new config handling. ip import-table no longer accepts
|
||||
distance, but we honor the old syntax. But 'show running' shows only
|
||||
the new syntax. This causes an unnecessary 'no import-table' followed
|
||||
by the same old 'ip import-table' which causes perturbations in
|
||||
announced routes leading to traffic blackholes. Fix this issue.
|
||||
"""
|
||||
# More old-to-new config handling. ip import-table no longer accepts
|
||||
# distance, but we honor the old syntax. But 'show running' shows only
|
||||
# the new syntax. This causes an unnecessary 'no import-table' followed
|
||||
# by the same old 'ip import-table' which causes perturbations in
|
||||
# announced routes leading to traffic blackholes. Fix this issue.
|
||||
re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0])
|
||||
if re_importtbl:
|
||||
table_num = re_importtbl.group(1)
|
||||
@ -1236,17 +1193,16 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
)
|
||||
lines_to_add_to_del.append((ctx[0], None))
|
||||
|
||||
"""
|
||||
ip/ipv6 prefix-lists and access-lists can be specified without a seq number.
|
||||
However, the running config always adds 'seq x', where x is a number
|
||||
incremented by 5 for every element of the prefix/access list.
|
||||
So, ignore such lines as well. Sample prefix-list and acces-list lines:
|
||||
ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
|
||||
ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
|
||||
ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
|
||||
access-list FOO seq 5 permit 2.2.2.2/32
|
||||
ipv6 access-list BAR seq 5 permit 2:2:2::2/128
|
||||
"""
|
||||
# ip/ipv6 prefix-lists and access-lists can be specified without a seq
|
||||
# number. However, the running config always adds 'seq x', where x is
|
||||
# a number incremented by 5 for every element of the prefix/access
|
||||
# list. So, ignore such lines as well. Sample prefix-list and
|
||||
# acces-list lines:
|
||||
# ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
|
||||
# ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
|
||||
# ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
|
||||
# access-list FOO seq 5 permit 2.2.2.2/32
|
||||
# ipv6 access-list BAR seq 5 permit 2:2:2::2/128
|
||||
re_acl_pfxlst = re.search(
|
||||
"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
|
||||
ctx_keys[0],
|
||||
@ -1265,12 +1221,9 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_del_to_del.append((ctx_keys, None))
|
||||
lines_to_add_to_del.append(((tmpline,), None))
|
||||
found = True
|
||||
"""
|
||||
If prefix-lists or access-lists are being deleted and
|
||||
not added (see comment above), add command with 'no' to
|
||||
lines_to_add and remove from lines_to_del to improve
|
||||
scaling performance.
|
||||
"""
|
||||
# If prefix-lists or access-lists are being deleted and not added
|
||||
# (see comment above), add command with 'no' to lines_to_add and
|
||||
# remove from lines_to_del to improve scaling performance.
|
||||
if found is False:
|
||||
add_cmd = ("no " + ctx_keys[0],)
|
||||
lines_to_add.append((add_cmd, None))
|
||||
@ -1302,16 +1255,12 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_add, ctx_keys, route_target_both_line
|
||||
)
|
||||
|
||||
"""
|
||||
If the running configs has
|
||||
route-target import 1:1
|
||||
route-target export 1:1
|
||||
|
||||
and the config we are reloading against has
|
||||
route-target both 1:1
|
||||
|
||||
then we can ignore deleting the import/export and ignore adding the 'both'
|
||||
"""
|
||||
# If the running configs has
|
||||
# route-target import 1:1
|
||||
# route-target export 1:1
|
||||
# and the config we are reloading against has
|
||||
# route-target both 1:1
|
||||
# then we can ignore deleting the import/export and ignore adding the 'both'
|
||||
if found_route_target_export_line and found_route_target_both_line:
|
||||
lines_to_del_to_del.append((ctx_keys, route_target_import_line))
|
||||
lines_to_del_to_del.append((ctx_keys, route_target_export_line))
|
||||
@ -1333,23 +1282,21 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
|
||||
lines_to_del_to_del.append((ctx_keys, line))
|
||||
lines_to_add_to_del.append((ctx_keys, line))
|
||||
else:
|
||||
"""
|
||||
We have commands that used to be displayed in the global part
|
||||
of 'router bgp' that are now displayed under 'address-family ipv4 unicast'
|
||||
|
||||
# old way
|
||||
router bgp 64900
|
||||
neighbor ISL advertisement-interval 0
|
||||
|
||||
vs.
|
||||
|
||||
# new way
|
||||
router bgp 64900
|
||||
address-family ipv4 unicast
|
||||
neighbor ISL advertisement-interval 0
|
||||
|
||||
Look to see if we are deleting it in one format just to add it back in the other
|
||||
"""
|
||||
# We have commands that used to be displayed in the global part
|
||||
# of 'router bgp' that are now displayed under 'address-family ipv4 unicast'
|
||||
#
|
||||
# # old way
|
||||
# router bgp 64900
|
||||
# neighbor ISL advertisement-interval 0
|
||||
#
|
||||
# vs.
|
||||
#
|
||||
# # new way
|
||||
# router bgp 64900
|
||||
# address-family ipv4 unicast
|
||||
# neighbor ISL advertisement-interval 0
|
||||
#
|
||||
# Look to see if we are deleting it in one format just to add it back in the other
|
||||
if (
|
||||
ctx_keys[0].startswith("router bgp")
|
||||
and len(ctx_keys) > 1
|
||||
@ -1382,19 +1329,22 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del):
|
||||
|
||||
for (ctx_keys, line) in lines_to_del:
|
||||
|
||||
if (
|
||||
ctx_keys[0].startswith("frr version")
|
||||
or ctx_keys[0].startswith("frr defaults")
|
||||
or ctx_keys[0].startswith("username")
|
||||
or ctx_keys[0].startswith("password")
|
||||
or ctx_keys[0].startswith("line vty")
|
||||
or
|
||||
# This is technically "no"able but if we did so frr-reload would
|
||||
# stop working so do not let the user shoot themselves in the foot
|
||||
# by removing this.
|
||||
ctx_keys[0].startswith("service integrated-vtysh-config")
|
||||
# The integrated-vtysh-config one is technically "no"able but if we did
|
||||
# so frr-reload would stop working so do not let the user shoot
|
||||
# themselves in the foot by removing this.
|
||||
if any(
|
||||
[
|
||||
ctx_keys[0].startswith(x)
|
||||
for x in [
|
||||
"frr version",
|
||||
"frr defaults",
|
||||
"username",
|
||||
"password",
|
||||
"line vty",
|
||||
"service integrated-vtysh-config",
|
||||
]
|
||||
]
|
||||
):
|
||||
|
||||
log.info('"%s" cannot be removed' % (ctx_keys[-1],))
|
||||
lines_to_del_to_del.append((ctx_keys, line))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user