[bgpd] Add 'show ... neighbor .... prefix-counts' command

2006-09-03 Paul Jakma <paul.jakma@sun.com>

	* bgp_route.c: Add 'show ... bgp ... <neighbour> prefix-count'
	  commands, to provide detailed counts of prefixes for a peer.
	  Informative, and should help pin down to pfxcnt drift
	  problems.
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index b27132c..cb07c58 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,3 +1,10 @@
+2006-09-03 Paul Jakma <paul.jakma@sun.com>
+
+	* bgp_route.c: Add 'show ... bgp ... <neighbour> prefix-count'
+	  commands, to provide detailed counts of prefixes for a peer.
+	  Informative, and should help pin down to pfxcnt drift
+	  problems.
+
 2006-08-27 Paul Jakma <paul.jakma@sun.com>
 
 	* bgp_advertise.c: (bgp_sync_delete) fix mtype in XFREE.
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 5623cad..40534a1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -8386,6 +8386,219 @@
   return peer;
 }
 
+enum bgp_pcounts
+{
+  PCOUNT_ADJ_IN = 0,
+  PCOUNT_DAMPED,
+  PCOUNT_REMOVED,
+  PCOUNT_HISTORY,
+  PCOUNT_STALE,
+  PCOUNT_VALID,
+  PCOUNT_ALL,
+  PCOUNT_COUNTED,
+  PCOUNT_PFCNT, /* the figure we display to users */
+  PCOUNT_MAX,
+};
+
+static const char *pcount_strs[] =
+{
+  [PCOUNT_ADJ_IN]  = "Adj-in",
+  [PCOUNT_DAMPED]  = "Damped",
+  [PCOUNT_REMOVED] = "Removed",
+  [PCOUNT_HISTORY] = "History",
+  [PCOUNT_STALE]   = "Stale",
+  [PCOUNT_VALID]   = "Valid",
+  [PCOUNT_ALL]     = "All RIB",
+  [PCOUNT_COUNTED] = "PfxCt counted",
+  [PCOUNT_PFCNT]   = "Useable",
+  [PCOUNT_MAX]     = NULL,
+};
+
+static int
+bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi)
+{
+  struct bgp_node *rn;
+  struct bgp_info *ri;
+  unsigned int pcounts[PCOUNT_MAX], i;
+  
+  if (!peer || !peer->bgp || !peer->afc[afi][safi]
+      || !peer->bgp->rib[afi][safi])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  memset (&pcounts, 0, sizeof(pcounts));
+  
+  for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
+       rn = bgp_route_next (rn))
+    {
+      struct bgp_adj_in *ain;
+      
+      for (ain = rn->adj_in; ain; ain = ain->next)
+        if (ain->peer == peer)
+          pcounts[PCOUNT_ADJ_IN]++;
+
+#define PFCNT_EXCLUDED (BGP_INFO_DAMPED|BGP_INFO_HISTORY|BGP_INFO_REMOVED|BGP_INFO_STALE)
+      for (ri = rn->info; ri; ri = ri->next)
+        {
+          char buf[SU_ADDRSTRLEN];
+          
+          if (ri->peer != peer)
+            continue;
+          
+          pcounts[PCOUNT_ALL]++;
+          
+          if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED))
+            pcounts[PCOUNT_DAMPED]++;
+          if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+            pcounts[PCOUNT_HISTORY]++;
+          if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED))
+            pcounts[PCOUNT_REMOVED]++;
+          if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+            pcounts[PCOUNT_STALE]++;
+          if (CHECK_FLAG (ri->flags, BGP_INFO_VALID))
+            pcounts[PCOUNT_VALID]++;
+          if (!CHECK_FLAG (ri->flags, PFCNT_EXCLUDED))
+            pcounts[PCOUNT_PFCNT]++;
+          
+          if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
+            {
+              pcounts[PCOUNT_COUNTED]++;
+              if (CHECK_FLAG (ri->flags, PFCNT_EXCLUDED))
+                plog_warn (peer->log,
+                           "%s [pcount] %s/%d is counted but flags 0x%x",
+                           peer->host,
+                           inet_ntop(rn->p.family, &rn->p.u.prefix,
+                                     buf, SU_ADDRSTRLEN),
+                           rn->p.prefixlen,
+                           ri->flags);
+            }
+          else
+            {
+              if (!CHECK_FLAG (ri->flags, PFCNT_EXCLUDED))
+                plog_warn (peer->log,
+                           "%s [pcount] %s/%d not counted but flags 0x%x",
+                           peer->host,
+                           inet_ntop(rn->p.family, &rn->p.u.prefix,
+                                     buf, SU_ADDRSTRLEN),
+                           rn->p.prefixlen,
+                           ri->flags);
+            }
+        }
+    }
+#undef PFCNT_EXCLUDED
+
+  vty_out (vty, "Prefix counts for %s, %s%s", 
+           peer->host, afi_safi_print (afi, safi), VTY_NEWLINE);
+  vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE);
+  vty_out (vty, "%sCounts from RIB table walk:%s%s", 
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+  for (i = 0; i < PCOUNT_MAX; i++)
+      vty_out (vty, "%20s: %-10d%s", pcount_strs[i], pcounts[i], VTY_NEWLINE);
+
+  if (pcounts[PCOUNT_PFCNT] != peer->pcount[afi][safi])
+    {
+      vty_out (vty, "%s [pcount] PfxCt drift!%s",
+               peer->host, VTY_NEWLINE);
+      vty_out (vty, "Please report this bug, with the above command output%s",
+              VTY_NEWLINE);
+    }
+               
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_bgp_neighbor_prefix_counts,
+       show_ip_bgp_neighbor_prefix_counts_cmd,
+       "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display detailed prefix count information\n")
+{
+  struct peer *peer;
+
+  peer = peer_lookup_in_view (vty, NULL, argv[0]);  
+  if (! peer) 
+    return CMD_WARNING;
+ 
+  return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_ipv6_neighbor_prefix_counts,
+       show_bgp_ipv6_neighbor_prefix_counts_cmd,
+       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display detailed prefix count information\n")
+{
+  struct peer *peer;
+
+  peer = peer_lookup_in_view (vty, NULL, argv[0]);  
+  if (! peer) 
+    return CMD_WARNING;
+ 
+  return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts,
+       show_ip_bgp_ipv4_neighbor_prefix_counts_cmd,
+       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display detailed prefix count information\n")
+{
+  struct peer *peer;
+
+  peer = peer_lookup_in_view (vty, NULL, argv[1]);
+  if (! peer)
+    return CMD_WARNING;
+
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST);
+
+  return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts,
+       show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd,
+       "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display detailed prefix count information\n")
+{
+  struct peer *peer;
+
+  peer = peer_lookup_in_view (vty, NULL, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+  
+  return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN);
+}
+
+
 static void
 show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
 		int in)
@@ -10666,7 +10879,13 @@
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
 
+  /* prefix count */
+  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
 #ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd);
+
   /* New config IPv6 BGP commands.  */
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);