diff options
Diffstat (limited to 'tools/frr-reload.py')
| -rwxr-xr-x | tools/frr-reload.py | 357 |
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) |
