diff options
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r-- | bgpd/bgp_route.c | 164 |
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; +} |