summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_route.c
diff options
context:
space:
mode:
authorJeffrey C. Ollie <jeff@ocjtech.us>2007-04-09 15:36:33 -0500
committerJeffrey C. Ollie <jeff@ocjtech.us>2007-04-09 15:36:33 -0500
commit37e11172f8ed157340783b73d56595bb02d0a2d2 (patch)
tree65163a9cdb8ded9c55c94da92e8a6327bda9067c /bgpd/bgp_route.c
parent8d3e3ccfd0d0cb82b253f937339d1c6189a2bf54 (diff)
parent43cd33a44e010f818633b7f144b5a0be352b41e7 (diff)
downloadquagga-37e11172f8ed157340783b73d56595bb02d0a2d2.tar.bz2
quagga-37e11172f8ed157340783b73d56595bb02d0a2d2.tar.xz
Merge commit 'quagga_0_99_6_release' into linux-realmsquagga-0.99.6-realms.patch
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r--bgpd/bgp_route.c901
1 files changed, 779 insertions, 122 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 20276b49..8216fd4e 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -187,12 +187,87 @@ bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri)
void
bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri)
{
- /* leave info in place for now in place for now,
- * bgp_process will reap it later. */
- SET_FLAG (ri->flags, BGP_INFO_REMOVED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_REMOVED);
+ /* set of previous already took care of pcount */
UNSET_FLAG (ri->flags, BGP_INFO_VALID);
}
+/* undo the effects of a previous call to bgp_info_delete; typically
+ called when a route is deleted and then quickly re-added before the
+ deletion has been processed */
+static void
+bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri)
+{
+ bgp_info_unset_flag (rn, ri, BGP_INFO_REMOVED);
+ /* unset of previous already took care of pcount */
+ SET_FLAG (ri->flags, BGP_INFO_VALID);
+}
+
+/* Adjust pcount as required */
+static void
+bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
+{
+ assert (rn && rn->table);
+ assert (ri && ri->peer && ri->peer->bgp);
+
+ /* Ignore 'pcount' for RS-client tables */
+ if (rn->table->type != BGP_TABLE_MAIN
+ || ri->peer == ri->peer->bgp->peer_self)
+ return;
+
+ if (BGP_INFO_HOLDDOWN (ri)
+ && CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
+ {
+
+ UNSET_FLAG (ri->flags, BGP_INFO_COUNTED);
+
+ /* slight hack, but more robust against errors. */
+ if (ri->peer->pcount[rn->table->afi][rn->table->safi])
+ ri->peer->pcount[rn->table->afi][rn->table->safi]--;
+ else
+ {
+ zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s",
+ __func__, ri->peer->host);
+ zlog_backtrace (LOG_WARNING);
+ zlog_warn ("%s: Please report to Quagga bugzilla", __func__);
+ }
+ }
+ else if (!BGP_INFO_HOLDDOWN (ri)
+ && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
+ {
+ SET_FLAG (ri->flags, BGP_INFO_COUNTED);
+ ri->peer->pcount[rn->table->afi][rn->table->safi]++;
+ }
+}
+
+
+/* Set/unset bgp_info flags, adjusting any other state as needed.
+ * This is here primarily to keep prefix-count in check.
+ */
+void
+bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
+{
+ SET_FLAG (ri->flags, flag);
+
+ /* early bath if we know it's not a flag that changes useability state */
+ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
+ return;
+
+ bgp_pcount_adjust (rn, ri);
+}
+
+void
+bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
+{
+ UNSET_FLAG (ri->flags, flag);
+
+ /* early bath if we know it's not a flag that changes useability state */
+ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
+ return;
+
+ bgp_pcount_adjust (rn, ri);
+}
+
/* Get MED value. If MED value is missing and "bgp bestpath
missing-as-worst" is specified, treat it as the worst value. */
static u_int32_t
@@ -1235,15 +1310,15 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *
{
if (bgp_info_cmp (bgp, ri2, new_select))
{
- UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
new_select = ri2;
}
- SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK);
+ bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
}
}
- SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK);
- SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
}
/* Check old selected route and new selected route. */
@@ -1269,11 +1344,11 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
&& (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED)))
{
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
continue;
}
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED);
if (bgp_info_cmp (bgp, ri, new_select))
new_select = ri;
@@ -1367,11 +1442,11 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
continue;
if (old_select)
- UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
if (new_select)
{
- SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
- UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
}
bgp_process_announce_selected (rsclient, new_select, rn, &attr,
@@ -1381,11 +1456,11 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
else
{
if (old_select)
- UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
if (new_select)
{
- SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
- UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
}
bgp_process_announce_selected (rsclient, new_select, rn,
&attr, afi, safi);
@@ -1433,11 +1508,11 @@ bgp_process_main (struct work_queue *wq, void *data)
}
if (old_select)
- UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
if (new_select)
{
- SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
- UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
}
@@ -1504,7 +1579,7 @@ bgp_process_queue_init (void)
bm->process_main_queue->spec.max_retries
= bm->process_main_queue->spec.max_retries = 0;
bm->process_rsclient_queue->spec.hold
- = bm->process_main_queue->spec.hold = 500;
+ = bm->process_main_queue->spec.hold = 50;
}
void
@@ -1636,43 +1711,6 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
return 0;
}
-static void
-bgp_pcount_increment (struct bgp_node *rn, struct bgp_info *ri,
- afi_t afi, safi_t safi)
-{
- assert (ri && rn);
-
- if (!CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)
- && rn->table->type == BGP_TABLE_MAIN)
- {
- SET_FLAG (ri->flags, BGP_INFO_COUNTED);
- ri->peer->pcount[afi][safi]++;
- }
-}
-
-static void
-bgp_pcount_decrement (struct bgp_node *rn, struct bgp_info *ri,
- afi_t afi, safi_t safi)
-{
- /* Ignore 'pcount' for RS-client tables */
- if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)
- && rn->table->type == BGP_TABLE_MAIN)
- {
- UNSET_FLAG (ri->flags, BGP_INFO_COUNTED);
-
- /* slight hack, but more robust against errors. */
- if (ri->peer->pcount[afi][safi])
- ri->peer->pcount[afi][safi]--;
- else
- {
- zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s",
- __func__, ri->peer->host);
- zlog_backtrace (LOG_WARNING);
- zlog_warn ("%s: Please report to Quagga bugzilla", __func__);
- }
- }
-}
-
/* Unconditionally remove the route from the RIB, without taking
* damping into consideration (eg, because the session went down)
*/
@@ -1680,7 +1718,6 @@ static void
bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
afi_t afi, safi_t safi)
{
- bgp_pcount_decrement (rn, ri, afi, safi);
bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
@@ -1703,7 +1740,6 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0))
== BGP_DAMP_SUPPRESSED)
{
- bgp_pcount_decrement (rn, ri, afi, safi);
bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
return;
}
@@ -1800,7 +1836,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
if (attrhash_cmp (ri->attr, attr_new))
{
- UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG,
@@ -1823,7 +1859,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
p->prefixlen, rsclient->host);
/* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* Update to new attribute. */
bgp_attr_unintern (ri->attr);
@@ -1833,7 +1869,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
if (safi == SAFI_MPLS_VPN)
memcpy (ri->tag, tag, 3);
- SET_FLAG (ri->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
/* Process change. */
bgp_process (bgp, rn, afi, safi);
@@ -1863,7 +1899,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
if (safi == SAFI_MPLS_VPN)
memcpy (new->tag, tag, 3);
- SET_FLAG (new->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
/* Register new BGP information. */
bgp_info_add (rn, new);
@@ -2044,7 +2080,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Same attribute comes in. */
if (attrhash_cmp (ri->attr, attr_new))
{
- UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer_sort (peer) == BGP_PEER_EBGP
@@ -2056,8 +2092,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen);
- bgp_pcount_increment (rn, ri, afi, safi);
-
if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
{
bgp_aggregate_increment (bgp, p, ri, afi, safi);
@@ -2076,8 +2110,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
{
- UNSET_FLAG (ri->flags, BGP_INFO_STALE);
- bgp_pcount_increment (rn, ri, afi, safi);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_STALE);
bgp_process (bgp, rn, afi, safi);
}
}
@@ -2096,15 +2129,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- UNSET_FLAG (ri->flags, BGP_INFO_STALE);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_STALE);
/* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* implicit withdraw, decrement aggregate and pcount here.
* only if update is accepted, they'll increment below.
*/
- bgp_pcount_decrement (rn, ri, afi, safi);
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
/* Update bgp route dampening information. */
@@ -2146,15 +2178,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
- SET_FLAG (ri->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
else
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
+ bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
}
else
- SET_FLAG (ri->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
/* Process change. */
- bgp_pcount_increment (rn, ri, afi, safi);
bgp_aggregate_increment (bgp, p, ri, afi, safi);
bgp_process (bgp, rn, afi, safi);
@@ -2191,15 +2222,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
- SET_FLAG (new->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
else
- UNSET_FLAG (new->flags, BGP_INFO_VALID);
+ bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
}
else
- SET_FLAG (new->flags, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
/* Increment prefix */
- bgp_pcount_increment (rn, new, afi, safi);
bgp_aggregate_increment (bgp, p, new, afi, safi);
/* Register new BGP information. */
@@ -2566,13 +2596,8 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
&& peer->nsf[afi][safi]
&& ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_REMOVED))
- {
- bgp_pcount_decrement (rn, ri, afi, safi);
- SET_FLAG (ri->flags, BGP_INFO_STALE);
- }
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
+ bgp_info_set_flag (rn, ri, BGP_INFO_STALE);
else
bgp_rib_remove (rn, ri, peer, afi, safi);
break;
@@ -2607,11 +2632,10 @@ bgp_clear_node_complete (struct work_queue *wq)
{
struct peer *peer = wq->spec.data;
- UNSET_FLAG (peer->sflags, PEER_STATUS_CLEARING);
peer_unlock (peer); /* bgp_clear_node_complete */
/* Tickle FSM to start moving again */
- BGP_EVENT_ADD (peer, BGP_Start);
+ BGP_EVENT_ADD (peer, Clearing_Completed);
}
static void
@@ -2673,9 +2697,10 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
if (peer->clear_node_queue == NULL)
bgp_clear_node_queue_init (peer);
- /* bgp_fsm.c will not bring CLEARING sessions out of Idle this
- * protects against peers which flap faster than we can we clear,
- * which could lead to:
+ /* bgp_fsm.c keeps sessions in state Clearing, not transitioning to
+ * Idle until it receives a Clearing_Completed event. This protects
+ * against peers which flap faster than we can we clear, which could
+ * lead to:
*
* a) race with routes from the new session being installed before
* clear_route_node visits the node (to delete the route of that
@@ -2684,11 +2709,8 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
* on the process_main queue. Fast-flapping could cause that queue
* to grow and grow.
*/
- if (!CHECK_FLAG (peer->sflags, PEER_STATUS_CLEARING))
- {
- SET_FLAG (peer->sflags, PEER_STATUS_CLEARING);
- peer_lock (peer); /* bgp_clear_node_complete */
- }
+ if (!peer->clear_node_queue->thread)
+ peer_lock (peer); /* bgp_clear_node_complete */
if (safi != SAFI_MPLS_VPN)
bgp_clear_route_table (peer, afi, safi, NULL, NULL);
@@ -2704,11 +2726,37 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
bgp_clear_route_table (peer, afi, safi, NULL, rsclient);
}
- /* If no routes were cleared, nothing was added to workqueue, run the
- * completion function now.
+ /* If no routes were cleared, nothing was added to workqueue, the
+ * completion function won't be run by workqueue code - call it here.
+ *
+ * Additionally, there is a presumption in FSM that clearing is only
+ * needed if peer state is Established - peers in pre-Established states
+ * shouldn't have any route-update state associated with them (in or out).
+ *
+ * We still get here from FSM through bgp_stop->clear_route_all in
+ * pre-Established though, so this is a useful sanity check to ensure
+ * the assumption above holds.
+ *
+ * At some future point, this check could be move to the top of the
+ * function, and do a quick early-return when state is
+ * pre-Established, avoiding above list and table scans. Once we're
+ * sure it is safe..
*/
if (!peer->clear_node_queue->thread)
bgp_clear_node_complete (peer->clear_node_queue);
+ else
+ {
+ /* clearing queue scheduled. Normal if in Established state
+ * (and about to transition out of it), but otherwise...
+ */
+ if (peer->status != Established)
+ {
+ plog_err (peer->log, "%s [Error] State %s is not Established,"
+ " but routes were cleared - bug!",
+ peer->host, LOOKUP (bgp_status_msg, peer->status));
+ assert (peer->status == Established);
+ }
+ }
}
void
@@ -3002,9 +3050,8 @@ bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient,
/* Withdraw static BGP route from routing table. */
if (ri)
{
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, safi);
}
/* Unlock bgp_node_lookup. */
@@ -3106,7 +3153,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (ri)
{
- if (attrhash_cmp (ri->attr, attr_new))
+ if (attrhash_cmp (ri->attr, attr_new) &&
+ !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
@@ -3116,9 +3164,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
else
{
/* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* Rewrite BGP route information. */
+ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+ bgp_info_restore(rn, ri);
bgp_attr_unintern (ri->attr);
ri->attr = attr_new;
ri->uptime = time (NULL);
@@ -3213,7 +3263,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (ri)
{
- if (attrhash_cmp (ri->attr, attr_new))
+ if (attrhash_cmp (ri->attr, attr_new) &&
+ !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
@@ -3223,10 +3274,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
else
{
/* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* Rewrite BGP route information. */
- bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+ bgp_info_restore(rn, ri);
+ else
+ bgp_aggregate_decrement (bgp, p, ri, afi, safi);
bgp_attr_unintern (ri->attr);
ri->attr = attr_new;
ri->uptime = time (NULL);
@@ -3333,9 +3387,8 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
if (ri)
{
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, safi);
}
/* Unlock bgp_node_lookup. */
@@ -3382,9 +3435,8 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
if (ri)
{
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, safi);
}
/* Unlock bgp_node_lookup. */
@@ -4165,7 +4217,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
if (aggregate->summary_only)
{
ri->suppress++;
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
@@ -4368,7 +4420,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
if (aggregate->summary_only)
{
ri->suppress++;
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
/* as-set aggregate route generate origin, as path,
@@ -4468,7 +4520,7 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
if (ri->suppress == 0)
{
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
}
@@ -4494,9 +4546,8 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,
/* Withdraw static BGP route from routing table. */
if (ri)
{
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, safi);
}
/* Unlock bgp_node_lookup. */
@@ -5010,7 +5061,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (bi)
{
- if (attrhash_cmp (bi->attr, new_attr))
+ if (attrhash_cmp (bi->attr, new_attr) &&
+ !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
{
bgp_attr_unintern (new_attr);
aspath_unintern (attr.aspath);
@@ -5020,10 +5072,13 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
else
{
/* The attribute is changed. */
- SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED);
+ bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED);
/* Rewrite BGP route information. */
- bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
+ if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
+ bgp_info_restore(bn, bi);
+ else
+ bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
bgp_attr_unintern (bi->attr);
bi->attr = new_attr;
bi->uptime = time (NULL);
@@ -5081,9 +5136,8 @@ bgp_redistribute_delete (struct prefix *p, u_char type)
if (ri)
{
bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, SAFI_UNICAST);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, SAFI_UNICAST);
}
bgp_unlock_node (rn);
}
@@ -5110,9 +5164,8 @@ bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type)
if (ri)
{
bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, SAFI_UNICAST);
bgp_info_delete (rn, ri);
+ bgp_process (bgp, rn, afi, SAFI_UNICAST);
}
}
}
@@ -8495,6 +8548,598 @@ peer_lookup_in_view (struct vty *vty, const char *view_name,
return peer;
}
+
+enum bgp_stats
+{
+ BGP_STATS_MAXBITLEN = 0,
+ BGP_STATS_RIB,
+ BGP_STATS_PREFIXES,
+ BGP_STATS_TOTPLEN,
+ BGP_STATS_UNAGGREGATEABLE,
+ BGP_STATS_MAX_AGGREGATEABLE,
+ BGP_STATS_AGGREGATES,
+ BGP_STATS_SPACE,
+ BGP_STATS_ASPATH_COUNT,
+ BGP_STATS_ASPATH_MAXHOPS,
+ BGP_STATS_ASPATH_TOTHOPS,
+ BGP_STATS_ASPATH_MAXSIZE,
+ BGP_STATS_ASPATH_TOTSIZE,
+ BGP_STATS_ASN_HIGHEST,
+ BGP_STATS_MAX,
+};
+
+static const char *table_stats_strs[] =
+{
+ [BGP_STATS_PREFIXES] = "Total Prefixes",
+ [BGP_STATS_TOTPLEN] = "Average prefix length",
+ [BGP_STATS_RIB] = "Total Advertisements",
+ [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes",
+ [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes",
+ [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements",
+ [BGP_STATS_SPACE] = "Address space advertised",
+ [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths",
+ [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)",
+ [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)",
+ [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)",
+ [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)",
+ [BGP_STATS_ASN_HIGHEST] = "Highest public ASN",
+ [BGP_STATS_MAX] = NULL,
+};
+
+struct bgp_table_stats
+{
+ struct bgp_table *table;
+ unsigned long long counts[BGP_STATS_MAX];
+};
+
+#if 0
+#define TALLY_SIGFIG 100000
+static unsigned long
+ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval)
+{
+ unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG);
+ unsigned long res = (newtot * TALLY_SIGFIG) / count;
+ unsigned long ret = newtot / count;
+
+ if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2))
+ return ret + 1;
+ else
+ return ret;
+}
+#endif
+
+static int
+bgp_table_stats_walker (struct thread *t)
+{
+ struct bgp_node *rn;
+ struct bgp_node *top;
+ struct bgp_table_stats *ts = THREAD_ARG (t);
+ unsigned int space = 0;
+
+ if (!(top = bgp_table_top (ts->table)))
+ return 0;
+
+ switch (top->p.family)
+ {
+ case AF_INET:
+ space = IPV4_MAX_BITLEN;
+ break;
+ case AF_INET6:
+ space = IPV6_MAX_BITLEN;
+ break;
+ }
+
+ ts->counts[BGP_STATS_MAXBITLEN] = space;
+
+ for (rn = top; rn; rn = bgp_route_next (rn))
+ {
+ struct bgp_info *ri;
+ struct bgp_node *prn = rn->parent;
+ unsigned int rinum = 0;
+
+ if (rn == top)
+ continue;
+
+ if (!rn->info)
+ continue;
+
+ ts->counts[BGP_STATS_PREFIXES]++;
+ ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen;
+
+#if 0
+ ts->counts[BGP_STATS_AVGPLEN]
+ = ravg_tally (ts->counts[BGP_STATS_PREFIXES],
+ ts->counts[BGP_STATS_AVGPLEN],
+ rn->p.prefixlen);
+#endif
+
+ /* check if the prefix is included by any other announcements */
+ while (prn && !prn->info)
+ prn = prn->parent;
+
+ if (prn == NULL || prn == top)
+ {
+ ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
+ /* announced address space */
+ if (space)
+ ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen);
+ }
+ else if (prn->info)
+ ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
+
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ rinum++;
+ ts->counts[BGP_STATS_RIB]++;
+
+ if (ri->attr &&
+ (CHECK_FLAG (ri->attr->flag,
+ ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))))
+ ts->counts[BGP_STATS_AGGREGATES]++;
+
+ /* as-path stats */
+ if (ri->attr && ri->attr->aspath)
+ {
+ unsigned int hops = aspath_count_hops (ri->attr->aspath);
+ unsigned int size = aspath_size (ri->attr->aspath);
+ as_t highest = aspath_highest (ri->attr->aspath);
+
+ ts->counts[BGP_STATS_ASPATH_COUNT]++;
+
+ if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS])
+ ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops;
+
+ if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE])
+ ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size;
+
+ ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops;
+ ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size;
+#if 0
+ ts->counts[BGP_STATS_ASPATH_AVGHOPS]
+ = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT],
+ ts->counts[BGP_STATS_ASPATH_AVGHOPS],
+ hops);
+ ts->counts[BGP_STATS_ASPATH_AVGSIZE]
+ = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT],
+ ts->counts[BGP_STATS_ASPATH_AVGSIZE],
+ size);
+#endif
+ if (highest > ts->counts[BGP_STATS_ASN_HIGHEST])
+ ts->counts[BGP_STATS_ASN_HIGHEST] = highest;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_table_stats ts;
+ unsigned int i;
+
+ if (!bgp->rib[afi][safi])
+ {
+ vty_out (vty, "%% No RIB exist for the AFI/SAFI%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset (&ts, 0, sizeof (ts));
+ ts.table = bgp->rib[afi][safi];
+ thread_execute (bm->master, bgp_table_stats_walker, &ts, 0);
+
+ vty_out (vty, "BGP %s RIB statistics%s%s",
+ afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE);
+
+ for (i = 0; i < BGP_STATS_MAX; i++)
+ {
+ if (!table_stats_strs[i])
+ continue;
+
+ switch (i)
+ {
+#if 0
+ case BGP_STATS_ASPATH_AVGHOPS:
+ case BGP_STATS_ASPATH_AVGSIZE:
+ case BGP_STATS_AVGPLEN:
+ vty_out (vty, "%-30s: ", table_stats_strs[i]);
+ vty_out (vty, "%12.2f",
+ (float)ts.counts[i] / (float)TALLY_SIGFIG);
+ break;
+#endif
+ case BGP_STATS_ASPATH_TOTHOPS:
+ case BGP_STATS_ASPATH_TOTSIZE:
+ vty_out (vty, "%-30s: ", table_stats_strs[i]);
+ vty_out (vty, "%12.2f",
+ ts.counts[i] ?
+ (float)ts.counts[i] /
+ (float)ts.counts[BGP_STATS_ASPATH_COUNT]
+ : 0);
+ break;
+ case BGP_STATS_TOTPLEN:
+ vty_out (vty, "%-30s: ", table_stats_strs[i]);
+ vty_out (vty, "%12.2f",
+ ts.counts[i] ?
+ (float)ts.counts[i] /
+ (float)ts.counts[BGP_STATS_PREFIXES]
+ : 0);
+ break;
+ case BGP_STATS_SPACE:
+ vty_out (vty, "%-30s: ", table_stats_strs[i]);
+ vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE);
+ if (ts.counts[BGP_STATS_MAXBITLEN] < 9)
+ break;
+ vty_out (vty, "%30s: ", "\% announced ");
+ vty_out (vty, "%12.2f%s",
+ 100 * (float)ts.counts[BGP_STATS_SPACE] /
+ (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]),
+ VTY_NEWLINE);
+ vty_out (vty, "%30s: ", "/8 equivalent ");
+ vty_out (vty, "%12.2f%s",
+ (float)ts.counts[BGP_STATS_SPACE] /
+ (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)),
+ VTY_NEWLINE);
+ if (ts.counts[BGP_STATS_MAXBITLEN] < 25)
+ break;
+ vty_out (vty, "%30s: ", "/24 equivalent ");
+ vty_out (vty, "%12.2f",
+ (float)ts.counts[BGP_STATS_SPACE] /
+ (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24)));
+ break;
+ default:
+ vty_out (vty, "%-30s: ", table_stats_strs[i]);
+ vty_out (vty, "%12llu", ts.counts[i]);
+ }
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+bgp_table_stats_vty (struct vty *vty, const char *name,
+ const char *afi_str, const char *safi_str)
+{
+ struct bgp *bgp;
+ afi_t afi;
+ safi_t safi;
+
+ if (name)
+ bgp = bgp_lookup_by_name (name);
+ else
+ bgp = bgp_get_default ();
+
+ if (!bgp)
+ {
+ vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (strncmp (afi_str, "ipv", 3) == 0)
+ {
+ if (strncmp (afi_str, "ipv4", 4) == 0)
+ afi = AFI_IP;
+ else if (strncmp (afi_str, "ipv6", 4) == 0)
+ afi = AFI_IP6;
+ else
+ {
+ vty_out (vty, "%% Invalid address family %s%s",
+ afi_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (strncmp (safi_str, "m", 1) == 0)
+ safi = SAFI_MULTICAST;
+ else if (strncmp (safi_str, "u", 1) == 0)
+ safi = SAFI_UNICAST;
+ else if (strncmp (safi_str, "vpnv4", 5) == 0)
+ safi = BGP_SAFI_VPNV4;
+ else if (strncmp (safi_str, "vpnv6", 6) == 0)
+ safi = BGP_SAFI_VPNV6;
+ else
+ {
+ vty_out (vty, "%% Invalid subsequent address family %s%s",
+ safi_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ vty_out (vty, "%% Invalid address family %s%s",
+ afi_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6)
+ || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4))
+ {
+ vty_out (vty, "%% Invalid subsequent address family %s for %s%s",
+ afi_str, safi_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_table_stats (vty, bgp, afi, safi);
+}
+
+DEFUN (show_bgp_statistics,
+ show_bgp_statistics_cmd,
+ "show bgp (ipv4|ipv6) (unicast|multicast) statistics",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "BGP RIB advertisement statistics\n")
+{
+ return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]);
+}
+
+ALIAS (show_bgp_statistics,
+ show_bgp_statistics_vpnv4_cmd,
+ "show bgp (ipv4) (vpnv4) statistics",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "BGP RIB advertisement statistics\n")
+
+DEFUN (show_bgp_statistics_view,
+ show_bgp_statistics_view_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "Address family\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "BGP RIB advertisement statistics\n")
+{
+ return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]);
+}
+
+ALIAS (show_bgp_statistics_view,
+ show_bgp_statistics_view_vpnv4_cmd,
+ "show bgp view WORD (ipv4) (vpnv4) statistics",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "BGP RIB advertisement statistics\n")
+
+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,
+};
+
+struct peer_pcounts
+{
+ unsigned int count[PCOUNT_MAX];
+ const struct peer *peer;
+ const struct bgp_table *table;
+};
+
+static int
+bgp_peer_count_walker (struct thread *t)
+{
+ struct bgp_node *rn;
+ struct peer_pcounts *pc = THREAD_ARG (t);
+ const struct peer *peer = pc->peer;
+
+ for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn))
+ {
+ struct bgp_adj_in *ain;
+ struct bgp_info *ri;
+
+ for (ain = rn->adj_in; ain; ain = ain->next)
+ if (ain->peer == peer)
+ pc->count[PCOUNT_ADJ_IN]++;
+
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ char buf[SU_ADDRSTRLEN];
+
+ if (ri->peer != peer)
+ continue;
+
+ pc->count[PCOUNT_ALL]++;
+
+ if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED))
+ pc->count[PCOUNT_DAMPED]++;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+ pc->count[PCOUNT_HISTORY]++;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED))
+ pc->count[PCOUNT_REMOVED]++;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ pc->count[PCOUNT_STALE]++;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_VALID))
+ pc->count[PCOUNT_VALID]++;
+ if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
+ pc->count[PCOUNT_PFCNT]++;
+
+ if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
+ {
+ pc->count[PCOUNT_COUNTED]++;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
+ 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, BGP_INFO_UNUSEABLE))
+ 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);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_pcounts pcounts = { .peer = peer };
+ unsigned int 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));
+ pcounts.peer = peer;
+ pcounts.table = peer->bgp->rib[afi][safi];
+
+ /* in-place call via thread subsystem so as to record execution time
+ * stats for the thread-walk (i.e. ensure this can't be blamed on
+ * on just vty_read()).
+ */
+ thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0);
+
+ 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.count[i], VTY_NEWLINE);
+
+ if (pcounts.count[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,
@@ -10776,7 +11421,13 @@ bgp_route_init ()
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);
@@ -10946,7 +11597,13 @@ bgp_route_init ()
install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd);
install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd);
install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd);
-
+
+ /* Statistics */
+ install_element (ENABLE_NODE, &show_bgp_statistics_cmd);
+ install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd);
+ install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd);
+ install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd);
+
/* old command */
install_element (VIEW_NODE, &show_ipv6_bgp_cmd);
install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd);