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.c164
1 files changed, 102 insertions, 62 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 87fe7f5c..8dafd181 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1464,11 +1464,9 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
struct bgp_info *new_select;
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
- struct attr attr;
struct listnode *node, *nnode;
struct peer *rsclient = rn->table->owner;
- memset (&attr, 0, sizeof (struct attr));
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new);
new_select = old_and_new.new;
@@ -1476,23 +1474,25 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP))
{
- for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient))
- {
- /* Nothing to do. */
- if (old_select && old_select == new_select)
- if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
- continue;
-
- if (old_select)
- bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
- if (new_select)
- {
- 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, afi, safi);
- }
+ if (rsclient->group)
+ for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient))
+ {
+ /* Nothing to do. */
+ if (old_select && old_select == new_select)
+ if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
+ continue;
+
+ if (old_select)
+ bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
+ if (new_select)
+ {
+ 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,
+ afi, safi);
+ }
}
else
{
@@ -1509,8 +1509,6 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
- bgp_attr_extra_free (&attr);
-
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
}
@@ -1593,9 +1591,11 @@ static void
bgp_processq_del (struct work_queue *wq, void *data)
{
struct bgp_process_queue *pq = data;
+ struct bgp_table *table = pq->rn->table;
- bgp_unlock(pq->bgp);
+ bgp_unlock (pq->bgp);
bgp_unlock_node (pq->rn);
+ bgp_table_unlock (table);
XFREE (MTYPE_BGP_PROCESS_QUEUE, pq);
}
@@ -1641,10 +1641,12 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
sizeof (struct bgp_process_queue));
if (!pqnode)
return;
-
- pqnode->rn = bgp_lock_node (rn); /* unlocked by bgp_processq_del */
+
+ /* all unlocked in bgp_processq_del */
+ bgp_table_lock (rn->table);
+ pqnode->rn = bgp_lock_node (rn);
pqnode->bgp = bgp;
- bgp_lock(bgp);
+ bgp_lock (bgp);
pqnode->afi = afi;
pqnode->safi = safi;
@@ -1805,8 +1807,6 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
const char *reason;
char buf[SU_ADDRSTRLEN];
- //memset (new_attr, 0, sizeof (struct attr));
-
/* Do not insert announces from a rsclient into its own 'bgp_table'. */
if (peer == rsclient)
return;
@@ -1894,10 +1894,10 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen, rsclient->host);
- bgp_unlock_node (rn);
- bgp_attr_unintern (attr_new);
+ bgp_unlock_node (rn);
+ bgp_attr_unintern (attr_new);
- return;
+ return;
}
/* Withdraw/Announce before we fully processed the withdraw */
@@ -1992,13 +1992,13 @@ static void
bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
struct peer *peer, struct prefix *p, int type, int sub_type,
struct prefix_rd *prd, u_char *tag)
- {
+{
struct bgp_node *rn;
struct bgp_info *ri;
char buf[SU_ADDRSTRLEN];
if (rsclient == peer)
- return;
+ return;
rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd);
@@ -2017,8 +2017,8 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
p->prefixlen);
/* Unlock bgp_node_get() lock. */
- bgp_unlock_node (rn);
- }
+ bgp_unlock_node (rn);
+}
static int
bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
@@ -2432,7 +2432,7 @@ void
bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
{
struct bgp *bgp;
- struct attr attr;
+ struct attr attr = { 0 };
struct aspath *aspath = { 0 };
struct prefix p;
struct bgp_info binfo;
@@ -2521,9 +2521,7 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
{
struct bgp_node *rn;
struct bgp_info *ri;
- struct attr attr;
-
- memset (&attr, 0, sizeof (struct attr));
+ struct attr attr = { 0 };
if (! table)
table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
@@ -2667,10 +2665,18 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
bgp_soft_reconfig_table (peer, afi, safi, table);
}
+
+struct bgp_clear_node_queue
+{
+ struct bgp_node *rn;
+ enum bgp_clear_route_type purpose;
+};
+
static wq_item_status
bgp_clear_route_node (struct work_queue *wq, void *data)
{
- struct bgp_node *rn = data;
+ struct bgp_clear_node_queue *cnq = data;
+ struct bgp_node *rn = cnq->rn;
struct peer *peer = wq->spec.data;
struct bgp_info *ri;
afi_t afi = rn->table->afi;
@@ -2679,7 +2685,7 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
assert (rn && peer);
for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer)
+ if (ri->peer == peer || cnq->purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
/* graceful restart STALE flag set. */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
@@ -2697,9 +2703,13 @@ bgp_clear_route_node (struct work_queue *wq, void *data)
static void
bgp_clear_node_queue_del (struct work_queue *wq, void *data)
{
- struct bgp_node *rn = data;
+ struct bgp_clear_node_queue *cnq = data;
+ struct bgp_node *rn = cnq->rn;
+ struct bgp_table *table = rn->table;
bgp_unlock_node (rn);
+ bgp_table_unlock (table);
+ XFREE (MTYPE_BGP_CLEAR_NODE_QUEUE, cnq);
}
static void
@@ -2707,10 +2717,10 @@ bgp_clear_node_complete (struct work_queue *wq)
{
struct peer *peer = wq->spec.data;
- peer_unlock (peer); /* bgp_clear_node_complete */
-
/* Tickle FSM to start moving again */
BGP_EVENT_ADD (peer, Clearing_Completed);
+
+ peer_unlock (peer); /* bgp_clear_route */
}
static void
@@ -2739,7 +2749,8 @@ bgp_clear_node_queue_init (struct peer *peer)
static void
bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
- struct bgp_table *table, struct peer *rsclient)
+ struct bgp_table *table, struct peer *rsclient,
+ enum bgp_clear_route_type purpose)
{
struct bgp_node *rn;
@@ -2792,21 +2803,30 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
* problem at this time,
*/
for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer)
+ if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
- bgp_lock_node (rn); /* unlocked: bgp_clear_node_queue_del */
- work_queue_add (peer->clear_node_queue, rn);
+ struct bgp_clear_node_queue *cnq;
+
+ /* both unlocked in bgp_clear_node_queue_del */
+ bgp_table_lock (rn->table);
+ bgp_lock_node (rn);
+ cnq = XCALLOC (MTYPE_BGP_CLEAR_NODE_QUEUE,
+ sizeof (struct bgp_clear_node_queue));
+ cnq->rn = rn;
+ cnq->purpose = purpose;
+ work_queue_add (peer->clear_node_queue, cnq);
+ break;
}
for (ain = rn->adj_in; ain; ain = ain->next)
- if (ain->peer == peer)
+ if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
bgp_adj_in_remove (rn, ain);
bgp_unlock_node (rn);
break;
}
for (aout = rn->adj_out; aout; aout = aout->next)
- if (aout->peer == peer)
+ if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
bgp_adj_out_remove (rn, aout, peer, afi, safi);
bgp_unlock_node (rn);
@@ -2817,7 +2837,8 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
}
void
-bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
+bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi,
+ enum bgp_clear_route_type purpose)
{
struct bgp_node *rn;
struct bgp_table *table;
@@ -2841,19 +2862,31 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
*/
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);
- else
- for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
- rn = bgp_route_next (rn))
- if ((table = rn->info) != NULL)
- bgp_clear_route_table (peer, afi, safi, table, NULL);
- for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient))
+ switch (purpose)
{
- if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
- bgp_clear_route_table (peer, afi, safi, NULL, rsclient);
+ case BGP_CLEAR_ROUTE_NORMAL:
+ if (safi != SAFI_MPLS_VPN)
+ bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose);
+ else
+ for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
+ rn = bgp_route_next (rn))
+ if ((table = rn->info) != NULL)
+ bgp_clear_route_table (peer, afi, safi, table, NULL, purpose);
+
+ for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient))
+ if (CHECK_FLAG(rsclient->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT))
+ bgp_clear_route_table (peer, afi, safi, NULL, rsclient, purpose);
+ break;
+
+ case BGP_CLEAR_ROUTE_MY_RSCLIENT:
+ bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose);
+ break;
+
+ default:
+ assert (0);
+ break;
}
/* If no routes were cleared, nothing was added to workqueue, the
@@ -2887,7 +2920,7 @@ bgp_clear_route_all (struct peer *peer)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- bgp_clear_route (peer, afi, safi);
+ bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL);
}
void
@@ -12276,3 +12309,10 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
}
+
+void
+bgp_route_finish (void)
+{
+ bgp_table_unlock (bgp_distance_table);
+ bgp_distance_table = NULL;
+}