summaryrefslogtreecommitdiff
path: root/tools/frr-reload.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/frr-reload.py')
-rwxr-xr-xtools/frr-reload.py357
1 files changed, 327 insertions, 30 deletions
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 3121551ee5..dca877dbfe 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -221,6 +221,7 @@ ip forwarding
for ligne in lines:
self.dlines[ligne] = True
+
def get_normalized_es_id(line):
"""
The es-id or es-sys-mac need to be converted to lower case
@@ -233,6 +234,7 @@ def get_normalized_es_id(line):
break
return line
+
def get_normalized_mac_ip_line(line):
if line.startswith("evpn mh es"):
return get_normalized_es_id(line)
@@ -242,6 +244,7 @@ def get_normalized_mac_ip_line(line):
return line
+
class Config(object):
"""
@@ -550,6 +553,7 @@ end
"dump ",
"enable ",
"frr ",
+ "fpm ",
"hostname ",
"ip ",
"ipv6 ",
@@ -576,6 +580,18 @@ end
if line.startswith("!") or line.startswith("#"):
continue
+ if (len(ctx_keys) == 2
+ and ctx_keys[0].startswith('bfd')
+ and ctx_keys[1].startswith('profile ')
+ and line == 'end'):
+ log.debug('LINE %-50s: popping from sub context, %-50s', line, ctx_keys)
+
+ if main_ctx_key:
+ self.save_contexts(ctx_keys, current_context_lines)
+ ctx_keys = copy.deepcopy(main_ctx_key)
+ current_context_lines = []
+ continue
+
# one line contexts
# there is one exception though: ldpd accepts a 'router-id' clause
# as part of its 'mpls ldp' config context. If we are processing
@@ -626,6 +642,22 @@ end
ctx_keys = []
current_context_lines = []
+ elif (
+ line == "exit"
+ and len(ctx_keys) > 1
+ and ctx_keys[0].startswith("segment-routing")
+ ):
+ self.save_contexts(ctx_keys, current_context_lines)
+
+ # Start a new context
+ ctx_keys = ctx_keys[:-1]
+ current_context_lines = []
+ log.debug(
+ "LINE %-50s: popping segment routing sub-context to ctx%-50s",
+ line,
+ ctx_keys,
+ )
+
elif line in ["exit-address-family", "exit", "exit-vnc"]:
# if this exit is for address-family ipv4 unicast, ignore the pop
if main_ctx_key:
@@ -665,6 +697,7 @@ end
current_context_lines = []
new_ctx = False
log.debug("LINE %-50s: entering new context, %-50s", line, ctx_keys)
+
elif (
line.startswith("address-family ")
or line.startswith("vnc defaults")
@@ -727,6 +760,156 @@ end
)
ctx_keys.append(line)
+ elif (
+ line.startswith("traffic-eng")
+ and len(ctx_keys) == 1
+ and ctx_keys[0].startswith("segment-routing")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ log.debug(
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("segment-list ")
+ and len(ctx_keys) == 2
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ log.debug(
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("policy ")
+ and len(ctx_keys) == 2
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ log.debug(
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("candidate-path ")
+ and line.endswith(" dynamic")
+ and len(ctx_keys) == 3
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ and ctx_keys[2].startswith("policy")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering candidate-path sub-context, append to ctx_keys",
+ line,
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("pcep")
+ and len(ctx_keys) == 2
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering pcep sub-context, append to ctx_keys", line
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("pce-config ")
+ and len(ctx_keys) == 3
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ and ctx_keys[2].startswith("pcep")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering pce-config sub-context, append to ctx_keys",
+ line,
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("pce ")
+ and len(ctx_keys) == 3
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ and ctx_keys[2].startswith("pcep")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering pce sub-context, append to ctx_keys", line
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith("pcc")
+ and len(ctx_keys) == 3
+ and ctx_keys[0].startswith("segment-routing")
+ and ctx_keys[1].startswith("traffic-eng")
+ and ctx_keys[2].startswith("pcep")
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering pcc sub-context, append to ctx_keys", line
+ )
+ ctx_keys.append(line)
+
+ elif (
+ line.startswith('profile ')
+ and len(ctx_keys) == 1
+ and ctx_keys[0].startswith('bfd')
+ ):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug(
+ "LINE %-50s: entering BFD profile sub-context, append to ctx_keys",
+ line
+ )
+ ctx_keys.append(line)
+
else:
# Continuing in an existing context, add non-commented lines to it
current_context_lines.append(line)
@@ -1083,30 +1266,44 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_add_to_del.append((ctx[0], None))
"""
- ip/ipv6 prefix-list 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, to the prefix list. So, ignore such lines as
- well. Sample prefix-list lines:
+ 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_ip_pfxlst = re.search(
- "^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ re_acl_pfxlst = re.search(
+ "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
ctx_keys[0],
)
- if re_ip_pfxlst:
+ if re_acl_pfxlst:
+ found = False
tmpline = (
- re_ip_pfxlst.group(1)
- + re_ip_pfxlst.group(2)
- + re_ip_pfxlst.group(3)
- + re_ip_pfxlst.group(5)
- + re_ip_pfxlst.group(6)
+ re_acl_pfxlst.group(1)
+ + re_acl_pfxlst.group(2)
+ + re_acl_pfxlst.group(3)
+ + re_acl_pfxlst.group(5)
+ + re_acl_pfxlst.group(6)
)
for ctx in lines_to_add:
if ctx[0][0] == tmpline:
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 found is False:
+ add_cmd = ("no " + ctx_keys[0],)
+ lines_to_add.append((add_cmd, None))
+ lines_to_del_to_del.append((ctx_keys, None))
if (
len(ctx_keys) == 3
@@ -1244,6 +1441,11 @@ def compare_context_objects(newconf, running):
# Compare the two Config objects to find the lines that we need to add/del
lines_to_add = []
lines_to_del = []
+ pollist_to_del = []
+ seglist_to_del = []
+ pceconf_to_del = []
+ pcclist_to_del = []
+ candidates_to_add = []
delete_bgpd = False
# Find contexts that are in newconf but not in running
@@ -1299,14 +1501,9 @@ def compare_context_objects(newconf, running):
# doing vtysh -c inefficient (and can time out.) For
# these commands, instead of adding them to lines_to_del,
# add the "no " version to lines_to_add.
- elif (
- running_ctx_keys[0].startswith("ip route")
- or running_ctx_keys[0].startswith("ipv6 route")
- or running_ctx_keys[0].startswith("access-list")
- or running_ctx_keys[0].startswith("ipv6 access-list")
- or running_ctx_keys[0].startswith("ip prefix-list")
- or running_ctx_keys[0].startswith("ipv6 prefix-list")
- ):
+ elif running_ctx_keys[0].startswith("ip route") or running_ctx_keys[
+ 0
+ ].startswith("ipv6 route"):
add_cmd = ("no " + running_ctx_keys[0],)
lines_to_add.append((add_cmd, None))
@@ -1321,11 +1518,64 @@ def compare_context_objects(newconf, running):
continue
# same thing for a pseudowire sub-context inside an l2vpn context
- elif (len(running_ctx_keys) > 1 and running_ctx_keys[0].startswith('l2vpn') and
- running_ctx_keys[1].startswith('member pseudowire') and
- (running_ctx_keys[:1], None) in lines_to_del):
+ elif (
+ len(running_ctx_keys) > 1
+ and running_ctx_keys[0].startswith("l2vpn")
+ and running_ctx_keys[1].startswith("member pseudowire")
+ and (running_ctx_keys[:1], None) in lines_to_del
+ ):
continue
+ # Segment routing and traffic engineering never need to be deleted
+ elif (
+ running_ctx_keys[0].startswith("segment-routing")
+ and len(running_ctx_keys) < 3
+ ):
+ continue
+
+ # Neither the pcep command
+ elif (
+ len(running_ctx_keys) == 3
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("pcep")
+ ):
+ continue
+
+ # Segment lists can only be deleted after we removed all the candidate paths that
+ # use them, so add them to a separate array that is going to be appended at the end
+ elif (
+ len(running_ctx_keys) == 3
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("segment-list")
+ ):
+ seglist_to_del.append((running_ctx_keys, None))
+
+ # Policies must be deleted after there candidate path, to be sure
+ # we add them to a separate array that is going to be appended at the end
+ elif (
+ len(running_ctx_keys) == 3
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("policy")
+ ):
+ pollist_to_del.append((running_ctx_keys, None))
+
+ # pce-config must be deleted after the pce, to be sure we add them
+ # to a separate array that is going to be appended at the end
+ elif (
+ len(running_ctx_keys) >= 4
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[3].startswith("pce-config")
+ ):
+ pceconf_to_del.append((running_ctx_keys, None))
+
+ # pcc must be deleted after the pce and pce-config too
+ elif (
+ len(running_ctx_keys) >= 4
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[3].startswith("pcc")
+ ):
+ pcclist_to_del.append((running_ctx_keys, None))
+
# Non-global context
elif running_ctx_keys and not any(
"address-family" in key for key in running_ctx_keys
@@ -1340,6 +1590,22 @@ def compare_context_objects(newconf, running):
for line in running_ctx.lines:
lines_to_del.append((running_ctx_keys, line))
+ # if we have some policies commands to delete, append them to lines_to_del
+ if len(pollist_to_del) > 0:
+ lines_to_del.extend(pollist_to_del)
+
+ # if we have some segment list commands to delete, append them to lines_to_del
+ if len(seglist_to_del) > 0:
+ lines_to_del.extend(seglist_to_del)
+
+ # if we have some pce list commands to delete, append them to lines_to_del
+ if len(pceconf_to_del) > 0:
+ lines_to_del.extend(pceconf_to_del)
+
+ # if we have some pcc list commands to delete, append them to lines_to_del
+ if len(pcclist_to_del) > 0:
+ lines_to_del.extend(pcclist_to_del)
+
# Find the lines within each context to add
# Find the lines within each context to del
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
@@ -1349,7 +1615,19 @@ def compare_context_objects(newconf, running):
for line in newconf_ctx.lines:
if line not in running_ctx.dlines:
- lines_to_add.append((newconf_ctx_keys, line))
+
+ # candidate paths can only be added after the policy and segment list,
+ # so add them to a separate array that is going to be appended at the end
+ if (
+ len(newconf_ctx_keys) == 3
+ and newconf_ctx_keys[0].startswith("segment-routing")
+ and newconf_ctx_keys[2].startswith("policy ")
+ and line.startswith("candidate-path ")
+ ):
+ candidates_to_add.append((newconf_ctx_keys, line))
+
+ else:
+ lines_to_add.append((newconf_ctx_keys, line))
for line in running_ctx.lines:
if line not in newconf_ctx.dlines:
@@ -1358,10 +1636,27 @@ def compare_context_objects(newconf, running):
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
if newconf_ctx_keys not in running.contexts:
- lines_to_add.append((newconf_ctx_keys, None))
- for line in newconf_ctx.lines:
- lines_to_add.append((newconf_ctx_keys, line))
+ # candidate paths can only be added after the policy and segment list,
+ # so add them to a separate array that is going to be appended at the end
+ if (
+ len(newconf_ctx_keys) == 4
+ and newconf_ctx_keys[0].startswith("segment-routing")
+ and newconf_ctx_keys[3].startswith("candidate-path")
+ ):
+ candidates_to_add.append((newconf_ctx_keys, None))
+ for line in newconf_ctx.lines:
+ candidates_to_add.append((newconf_ctx_keys, line))
+
+ else:
+ lines_to_add.append((newconf_ctx_keys, None))
+
+ for line in newconf_ctx.lines:
+ lines_to_add.append((newconf_ctx_keys, line))
+
+ # if we have some candidate paths commands to add, append them to lines_to_add
+ if len(candidates_to_add) > 0:
+ lines_to_add.extend(candidates_to_add)
(lines_to_add, lines_to_del) = check_for_exit_vrf(lines_to_add, lines_to_del)
(lines_to_add, lines_to_del) = ignore_delete_re_add_lines(
@@ -1523,10 +1818,12 @@ if __name__ == "__main__":
"staticd",
"vrrpd",
"ldpd",
+ "pathd",
+ "bfdd",
]:
- log.error(
- "Daemon %s is not a valid option for 'show running-config'" % args.daemon
- )
+ msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon
+ print(msg)
+ log.error(msg)
sys.exit(1)
vtysh = Vtysh(args.bindir, args.confdir, args.vty_socket, args.pathspace)