]> git.puffer.fish Git - matthieu/frr.git/commitdiff
tools: fix peer-group deletion in frr-reload
authorChirag Shah <chirag@nvidia.com>
Sun, 16 May 2021 02:41:43 +0000 (19:41 -0700)
committerChirag Shah <chirag@nvidia.com>
Mon, 24 May 2021 23:06:24 +0000 (16:06 -0700)
All of peers and respective configs are wiped out when
pee-group is removed.

In an attempt to remove peer-group and its associated peers
configs via frr-reload fails if the peer-group is removed first.

To pass the peer-group config removal via frr-reload following
steps are taken:
Find the bgp context to which peer-group belongs.
Find the peer-group associated peer(s) and store them in a list.
Remove the peers config lines from the pending list.
Move the peer-group deletion line to end of the pending list so
any remaining peer-group associated config can be removed successfully.

The above steps take 3 iterations over the pending list and scales
linearly.

Ticket:2656351
Reviewed By:CCR-11575
Testing Done:

Broken:

config:
router bgp 5544
 neighbor PG1 peer-group
 neighbor PG1 remote-as external
 neighbor swp10 interface peer-group PG1
 neighbor swp10 timers 3 9

failed frr-reload log:
2021-05-17 22:02:42,608  INFO: Executed "router bgp 5544  no neighbor
PG1 peer-group"
2021-05-17 22:02:42,708  INFO: Failed to execute router bgp 5544  no
neighbor PG1 remote-as external
2021-05-17 22:02:42,808  INFO: Failed to execute router bgp 5544  no
neighbor PG1 remote-as
2021-05-17 22:02:42,906  INFO: Failed to execute router bgp 5544  no
neighbor PG1
2021-05-17 22:02:43,007  INFO: Failed to execute router bgp 5544  no
neighbor
2021-05-17 22:02:43,106  INFO: Failed to execute router bgp 5544  no
2021-05-17 22:02:43,106 ERROR: "router bgp 5544 --  no" we failed to
remove this command
2021-05-17 22:02:43,107 ERROR: % Create the peer-group or interface
first

With fix:
2021-05-17 22:05:27,687  INFO: Executed "router bgp 5544  no neighbor
PG1 remote-as external"
2021-05-17 22:05:27,791  INFO: Executed "router bgp 5544  no neighbor
PG1 peer-group"

Signed-off-by: Chirag Shah <chirag@nvidia.com>
tools/frr-reload.py

index c28a971525aeaf76185db21e8b7c21a7b3f971bd..448ab79ead8ee937993ff734e46665e5710b3805 100755 (executable)
@@ -1095,6 +1095,175 @@ 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):
+
+    del_dict = dict()
+    # Stores the lines to move to the end of the pending list.
+    lines_to_del_to_del = []
+    # Stores the lines to move to end of the pending list.
+    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.
+
+    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"
+
+    """
+
+    for (ctx_keys, line) in lines_to_del:
+        if (
+            ctx_keys[0].startswith("router bgp")
+            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:
+
+             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
+
+            """
+            # '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': []}}
+            """
+            if ctx_keys[0] not in del_dict:
+                del_dict[ctx_keys[0]] = dict()
+            # find 'no neighbor <pg_name> peer-group'
+            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()
+
+    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:
+        if (
+            ctx_keys[0].startswith("router bgp")
+            and line
+            and line.startswith("neighbor ")
+        ):
+            if ctx_keys[0] in del_dict:
+                for pg_key in del_dict[ctx_keys[0]]:
+                    # 'neighbor <peer> [interface] peer-group <pg_name>'
+                    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 del_dict[ctx_keys[0]][pg_key]
+                    ):
+                        del_dict[ctx_keys[0]][pg_key].append(re_nbr_pg.group(1))
+
+    lines_to_del_to_app = []
+    for (ctx_keys, line) in lines_to_del:
+        if (
+            ctx_keys[0].startswith("router bgp")
+            and line
+            and line.startswith("neighbor ")
+        ):
+            if ctx_keys[0] in del_dict:
+                for pg in del_dict[ctx_keys[0]]:
+                    for nbr in del_dict[ctx_keys[0]][pg]:
+                        nb_exp = "neighbor %s .*" % nbr
+                        re_nb = re.search(nb_exp, line)
+                        # add peer configs to delete list.
+                        if re_nb and line not in lines_to_del_to_del:
+                            lines_to_del_to_del.append((ctx_keys, line))
+
+                    pg_exp = "neighbor %s peer-group$" % pg
+                    re_pg = re.match(pg_exp, line)
+                    if re_pg:
+                        lines_to_del_to_app.append((ctx_keys, line))
+
+    for (ctx_keys, line) in lines_to_del_to_del:
+        lines_to_del.remove((ctx_keys, line))
+
+    for (ctx_keys, line) in lines_to_del_to_app:
+        lines_to_del.remove((ctx_keys, line))
+        lines_to_del.append((ctx_keys, line))
+
+    return (lines_to_add, lines_to_del)
+
+
 def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
 
     # Quite possibly the most confusing (while accurate) variable names in history
@@ -1724,6 +1893,7 @@ def compare_context_objects(newconf, running):
     (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(
         lines_to_add, lines_to_del
     )
+    (lines_to_add, lines_to_del) = delete_move_lines(lines_to_add, lines_to_del)
     (lines_to_add, lines_to_del) = ignore_unconfigurable_lines(
         lines_to_add, lines_to_del
     )