summaryrefslogtreecommitdiff
path: root/bgpd/bgp_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r--bgpd/bgp_route.c92
1 files changed, 67 insertions, 25 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index ce44842e..c464cd04 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2490,8 +2490,6 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
{
struct bgp_node *rn = data;
struct peer *peer = wq->spec.data;
- struct bgp_adj_in *ain;
- struct bgp_adj_out *aout;
struct bgp_info *ri;
afi_t afi = rn->table->afi;
safi_t safi = rn->table->safi;
@@ -2511,20 +2509,6 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
bgp_rib_remove (rn, ri, peer, afi, safi);
break;
}
- for (ain = rn->adj_in; ain; ain = ain->next)
- if (ain->peer == peer)
- {
- bgp_adj_in_remove (rn, ain);
- bgp_unlock_node (rn);
- break;
- }
- for (aout = rn->adj_out; aout; aout = aout->next)
- if (aout->peer == peer)
- {
- bgp_adj_out_remove (rn, aout, peer, afi, safi);
- bgp_unlock_node (rn);
- break;
- }
return WQ_SUCCESS;
}
@@ -2577,6 +2561,7 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
{
struct bgp_node *rn;
+
if (! table)
table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi];
@@ -2586,11 +2571,65 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
{
+ struct bgp_info *ri;
+ struct bgp_adj_in *ain;
+ struct bgp_adj_out *aout;
+
if (rn->info == NULL)
continue;
-
- bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */
- work_queue_add (peer->clear_node_queue, rn);
+
+ /* XXX:TODO: This is suboptimal, every non-empty route_node is
+ * queued for every clearing peer, regardless of whether it is
+ * relevant to the peer at hand.
+ *
+ * Overview: There are 3 different indices which need to be
+ * scrubbed, potentially, when a peer is removed:
+ *
+ * 1 peer's routes visible via the RIB (ie accepted routes)
+ * 2 peer's routes visible by the (optional) peer's adj-in index
+ * 3 other routes visible by the peer's adj-out index
+ *
+ * 3 there is no hurry in scrubbing, once the struct peer is
+ * removed from bgp->peer, we could just GC such deleted peer's
+ * adj-outs at our leisure.
+ *
+ * 1 and 2 must be 'scrubbed' in some way, at least made
+ * invisible via RIB index before peer session is allowed to be
+ * brought back up. So one needs to know when such a 'search' is
+ * complete.
+ *
+ * Ideally:
+ *
+ * - there'd be a single global queue or a single RIB walker
+ * - rather than tracking which route_nodes still need to be
+ * examined on a peer basis, we'd track which peers still
+ * aren't cleared
+ *
+ * Given that our per-peer prefix-counts now should be reliable,
+ * this may actually be achievable. It doesn't seem to be a huge
+ * problem at this time,
+ */
+ for (ri = rn->info; ri; ri = ri->next)
+ if (ri->peer == peer)
+ {
+ bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */
+ work_queue_add (peer->clear_node_queue, rn);
+ }
+
+ for (ain = rn->adj_in; ain; ain = ain->next)
+ if (ain->peer == peer)
+ {
+ bgp_adj_in_remove (rn, ain);
+ bgp_unlock_node (rn);
+ break;
+ }
+ for (aout = rn->adj_out; aout; aout = aout->next)
+ if (aout->peer == peer)
+ {
+ bgp_adj_out_remove (rn, aout, peer, afi, safi);
+ bgp_unlock_node (rn);
+ break;
+ }
}
return;
}
@@ -2636,15 +2675,18 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
}
/* If no routes were cleared, nothing was added to workqueue, the
- * completion function won't be run by workqueue code - call it here.
+ * completion function won't be run by workqueue code - call it here.
+ * XXX: Actually, this assumption doesn't hold, see
+ * bgp_clear_route_table(), we queue all non-empty nodes.
*
* 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).
+ * really 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.
+ * We still can get here in pre-Established though, through
+ * peer_delete -> bgp_fsm_change_status, 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