bgpd: Add clear command to force a bestpath recalculation and re-advertisement of a prefix

Add these commands to bgp:

clear ip bgp prefix A.B.C.D/M
clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M

These two commands forces a bestpath calculation to happen again if
necessary to re-advertise the prefix.

Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 17b87f4..48645cf 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1602,7 +1602,8 @@
   new_select = old_and_new.new;
 
   /* Nothing to do. */
-  if (old_select && old_select == new_select)
+  if (old_select && old_select == new_select 
+      && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR))
     {
       if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
         {
@@ -1616,6 +1617,9 @@
         }
     }
 
+  /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */
+  UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR);
+
   if (old_select)
     bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
   if (new_select)
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 3b4e6cf..8e963ae 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -65,6 +65,7 @@
 
   u_char flags;
 #define BGP_NODE_PROCESS_SCHEDULED	(1 << 0)
+#define BGP_NODE_USER_CLEAR             (1 << 1)
 };
 
 /*
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 4c1de16..406ecb1 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4680,6 +4680,87 @@
   return CMD_SUCCESS;
 }
 
+/* Recalculate bestpath and re-advertise a prefix */
+static int
+bgp_clear_prefix (struct vty *vty, char *view_name, const char *ip_str,
+                  afi_t afi, safi_t safi, struct prefix_rd *prd)
+{
+  int ret;
+  struct prefix match;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_table *rib;
+
+  /* BGP structure lookup. */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+        {
+          vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+        {
+          vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  /* Check IP address argument. */
+  ret = str2prefix (ip_str, &match);
+  if (! ret)
+    {
+      vty_out (vty, "%% address is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  match.family = afi2family (afi);
+  rib = bgp->rib[afi][safi];
+
+  if (safi == SAFI_MPLS_VPN)
+    {
+      for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))
+        {
+          if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+            continue;
+
+          if ((table = rn->info) != NULL)
+            {
+              if ((rm = bgp_node_match (table, &match)) != NULL)
+                {
+                  if (rm->p.prefixlen == match.prefixlen)
+                    {
+                      SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR);
+                      bgp_process (bgp, rm, afi, safi);
+                    }
+                  bgp_unlock_node (rm);
+                }
+            }
+        }
+    }
+  else
+    {
+      if ((rn = bgp_node_match (rib, &match)) != NULL)
+        {
+          if (rn->p.prefixlen == match.prefixlen)
+            {
+              SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR);
+              bgp_process (bgp, rn, afi, safi);
+            }
+          bgp_unlock_node (rn);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
 static int
 bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,
                enum clear_sort sort, enum bgp_clear_type stype, 
@@ -4842,6 +4923,27 @@
        "Address family\n"
        "Clear all external peers\n")
 
+DEFUN (clear_ip_bgp_prefix,
+       clear_ip_bgp_prefix_cmd,
+       "clear ip bgp prefix A.B.C.D/M",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear bestpath and re-advertise\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return bgp_clear_prefix (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL);
+}
+
+ALIAS (clear_ip_bgp_prefix,
+       clear_bgp_prefix_cmd,
+       "clear bgp prefix A.B.C.D/M",
+       CLEAR_STR
+       BGP_STR
+       "Clear bestpath and re-advertise\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+
 DEFUN (clear_ip_bgp_as,
        clear_ip_bgp_as_cmd,
        "clear ip bgp " CMD_AS_RANGE,
@@ -5072,6 +5174,22 @@
        "Clear all peers\n"
        "Soft reconfig outbound update\n")
 
+DEFUN (clear_bgp_ipv6_safi_prefix,
+       clear_bgp_ipv6_safi_prefix_cmd,
+       "clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M",
+       CLEAR_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Clear bestpath and re-advertise\n"
+       "IPv6 prefix <network>/<length>,  e.g.,  3ffe::/16\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL);
+  else
+    return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL);
+}
+
 DEFUN (clear_ip_bgp_peer_soft_out,
        clear_ip_bgp_peer_soft_out_cmd,
        "clear ip bgp A.B.C.D soft out",
@@ -10909,6 +11027,10 @@
   install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd);
   install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd);
 
+  /* clear ip bgp prefix  */
+  install_element (ENABLE_NODE, &clear_ip_bgp_prefix_cmd);
+  install_element (ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd);
+
   /* "clear ip bgp neighbor soft out" */
   install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd);