diff options
Diffstat (limited to 'tools/frr-reload.py')
| -rwxr-xr-x | tools/frr-reload.py | 296 |
1 files changed, 283 insertions, 13 deletions
diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 0de6c1c2e3..d5fa8ab6a3 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -221,6 +221,26 @@ 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 + """ + sub_strs = ["evpn mh es-id", "evpn mh es-sys-mac"] + for sub_str in sub_strs: + obj = re.match(sub_str + " (?P<esi>\S*)", line) + if obj: + line = "%s %s" % (sub_str, obj.group("esi").lower()) + break + return line + +def get_normalized_mac_ip_line(line): + if line.startswith("evpn mh es"): + return get_normalized_es_id(line) + + if not "ipv6 add" in line: + return get_normalized_ipv6_line(line) + + return line class Config(object): @@ -251,11 +271,10 @@ class Config(object): # Compress duplicate whitespaces line = " ".join(line.split()) - if ":" in line and not "ipv6 add": - qv6_line = get_normalized_ipv6_line(line) - self.lines.append(qv6_line) - else: - self.lines.append(line) + if ":" in line: + line = get_normalized_mac_ip_line(line) + + self.lines.append(line) self.load_contexts() @@ -531,6 +550,7 @@ end "dump ", "enable ", "frr ", + "fpm ", "hostname ", "ip ", "ipv6 ", @@ -607,6 +627,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: @@ -618,7 +654,7 @@ end log.debug( "LINE %-50s: popping from subcontext to ctx%-50s", line, - ctx_keys, + ctx_keys ) elif line in ["exit-vni", "exit-ldp-if"]: @@ -646,6 +682,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") @@ -708,6 +745,135 @@ 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) + else: # Continuing in an existing context, add non-commented lines to it current_context_lines.append(line) @@ -1225,6 +1391,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 @@ -1307,6 +1478,56 @@ def compare_context_objects(newconf, running): (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 @@ -1321,6 +1542,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): @@ -1330,7 +1567,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: @@ -1339,10 +1588,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( @@ -1504,10 +1770,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) @@ -1555,6 +1823,8 @@ if __name__ == "__main__": else: running.load_from_show_running(args.daemon) + + (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) lines_to_configure = [] |
