From 2134a5fe519f178a1b47010f28a987fb3b6fd70a Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 10 Nov 2021 17:22:24 -0800 Subject: [PATCH] frr-reload: fix bgp nbr remote-as Remove neighbor <> remote-as <> config line, if the neighbor is part of the peer-group and peer-group contains remote-as config. Neighbors which are part of the peer-group cannot override remote-as. Fix: Frr-reload needs to remote 'neighbor <> remote-as <>' from lines_to_add if its already part of peer-group and peer-group has remote-as config. Testing Done: Before: Config snippet: neighbor PEERS peer-group neighbor PEERS remote-as external neighbor PEERS timers 3 9 neighbor 10.2.1.1 remote-as external neighbor 10.2.1.1 peer-group PEERS neighbor 10.2.1.1 timers 3 9 neighbor 10.2.1.2 remote-as external neighbor 10.2.1.2 peer-group PEERS Frr-reload failure: line 179: Failure to communicate[13] to bgpd, line: neighbor 10.2.1.1 remote-as external % Peer-group member cannot override remote-as of peer-group line 179: Failure to communicate[13] to bgpd, line: neighbor 10.2.1.2 remote-as external % Peer-group member cannot override remote-as of peer-group After: frr-reload apply the config successfully. Signed-off-by: Chirag Shah --- tools/frr-reload.py | 101 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index acd7a240b3..7868c3d41d 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -762,12 +762,96 @@ def check_for_exit_vrf(lines_to_add, lines_to_del): return (lines_to_add, lines_to_del) +def bgp_delete_nbr_remote_as_line(lines_to_add): + # Handle deletion of neighbor remote-as line from + # lines_to_add if the nbr is configured with peer-group and + # peer-group has remote-as config present. + # 'neighbor remote-as change on peer is not allowed + # if the peer is part of peer-group and peer-group has + # remote-as config. + + pg_dict = dict() + # Find all peer-group commands; create dict of each peer-group + # to store assoicated neighbor as value + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + # {'router bgp 65001': {'PG': [], 'PG1': []}, + # 'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}} + if ctx_keys[0] not in pg_dict: + pg_dict[ctx_keys[0]] = dict() + # find 'neighbor peer-group' + re_pg = re.match("neighbor (\S+) peer-group$", line) + if re_pg and re_pg.group(1) not in pg_dict[ctx_keys[0]]: + pg_dict[ctx_keys[0]][re_pg.group(1)] = { + "nbr": list(), + "remoteas": False, + } + found_pg_cmd = True + + # Find peer-group with remote-as command, also search neighbor + # associated to peer-group and store into peer-group dict + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + if ctx_keys[0] in pg_dict: + for pg_key in pg_dict[ctx_keys[0]]: + # Find 'neighbor remote-as' + pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key + re_pg_rmtas = re.search(pg_rmtas, line) + if re_pg_rmtas: + pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True + + # Find 'neighbor [interface] peer-group ' + nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + re_nbr_pg = re.search(nb_pg, line) + if ( + re_nbr_pg + and re_nbr_pg.group(1) not in pg_dict[ctx_keys[0]][pg_key] + ): + pg_dict[ctx_keys[0]][pg_key]["nbr"].append(re_nbr_pg.group(1)) + + # Find any neighbor remote-as config line check if the nbr + # is in the peer group's list of nbrs. Remove 'neighbor remote-as <>' + # from lines_to_add. + lines_to_del_from_add = [] + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + nbr_rmtas = "neighbor (\S+) remote-as.*" + re_nbr_rmtas = re.search(nbr_rmtas, line) + if re_nbr_rmtas and ctx_keys[0] in pg_dict: + for pg in pg_dict[ctx_keys[0]]: + if pg_dict[ctx_keys[0]][pg]["remoteas"] == True: + for nbr in pg_dict[ctx_keys[0]][pg]["nbr"]: + if re_nbr_rmtas.group(1) in nbr: + lines_to_del_from_add.append((ctx_keys, line)) + + for ctx_keys, line in lines_to_del_from_add: + lines_to_add.remove((ctx_keys, line)) + + +""" +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. - """ + + bgp_delete_nbr_remote_as_line(lines_to_add) + del_dict = dict() # Stores the lines to move to the end of the pending list. lines_to_del_to_del = [] @@ -860,14 +944,15 @@ def delete_move_lines(lines_to_add, lines_to_del): re_pg = re.match("neighbor (\S+) peer-group$", line) if re_pg and re_pg.group(1) not in del_dict[ctx_keys[0]]: del_dict[ctx_keys[0]][re_pg.group(1)] = list() + found_pg_del_cmd = True + + if found_pg_del_cmd == False: + return (lines_to_add, lines_to_del) for (ctx_keys, line) in lines_to_del_to_app: lines_to_del.remove((ctx_keys, line)) lines_to_del.append((ctx_keys, line)) - 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']}} for (ctx_keys, line) in lines_to_del: -- 2.39.5