LCOV - code coverage report
Current view: top level - bgp - bgp_update_monitor.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 294 300 98.0 %
Date: 2026-11-09 02:10:49 Functions: 27 27 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "bgp/bgp_update_monitor.h"
       7             : 
       8             : #include "base/task_annotations.h"
       9             : #include "bgp/bgp_ribout_updates.h"
      10             : #include "bgp/bgp_table.h"
      11             : #include "bgp/bgp_update_queue.h"
      12             : 
      13     2162486 : RouteUpdatePtr::RouteUpdatePtr(RouteUpdate *rt_update) : rt_update_(rt_update) {
      14     2162486 : }
      15             : 
      16     5237208 : RouteUpdatePtr::~RouteUpdatePtr() {
      17     5237208 : }
      18             : 
      19      136016 : RibUpdateMonitor::RibUpdateMonitor(RibOut *ribout, QueueVec *queue_vec)
      20      136016 :     : ribout_(ribout), queue_vec_(queue_vec) {
      21      136016 : }
      22             : 
      23             : //
      24             : // Helper routine for GetRouteStateAndDequeue to handle a RouteUpdate. Do
      25             : // nothing if it's a duplicate.
      26             : //
      27             : // Return a pointer to the DBState and update duplicate as appropriate.
      28             : //
      29        1855 : DBState *RibUpdateMonitor::GetRouteUpdateAndDequeue(DBEntryBase *db_entry,
      30             :         RouteUpdate *rt_update, UpdateCmp cmp, bool *duplicate) {
      31        1855 :     CHECK_CONCURRENCY("db::DBTable");
      32             : 
      33             :     // Compare desired state with current update. If the desired state
      34             :     // is a NOP just return without modifying the queue.
      35        1855 :     if (rt_update->queue_id() == RibOutUpdates::QUPDATE) {
      36        1760 :         *duplicate = cmp(rt_update);
      37        1759 :         if (*duplicate) {
      38         290 :             return NULL;
      39             :         }
      40             :     }
      41             : 
      42             :     // Set the state on the DBEntryBase and remove the RouteUpdate from
      43             :     // the queue. Change the queue to QUPDATE since that's where we will
      44             :     // re-enqueue the RouteUpdate, if we do it.
      45        1564 :     db_entry->SetState(ribout_->table(), ribout_->listener_id(), rt_update);
      46        1565 :     UpdateQueue *queue = queue_vec_->at(rt_update->queue_id());
      47        1565 :     queue->Dequeue(rt_update);
      48        1565 :     rt_update->set_queue_id(RibOutUpdates::QUPDATE);
      49        1565 :     return rt_update;
      50             : }
      51             : 
      52             : //
      53             : // Helper routine for GetRouteStateAndDequeue to handle a UpdateList.
      54             : //
      55             : // Since an update operation overrides any join/refresh state, get rid of
      56             : // RouteUpdates that are not for QUPDATE.
      57             : //
      58             : // Note that we should NOT check for duplicate state in QUPDATE and bail.
      59             : // Doing so could result in a failure to remove pending RouteUpdates from
      60             : // QBULK which are no longer required.
      61             : //
      62             : // Return a pointer to the RouteUpdate for QUPDATE if it exists, else
      63             : // Return a pointer to new RouteState if the UpdateList has history, else
      64             : // Return NULL.
      65             : //
      66          60 : DBState *RibUpdateMonitor::GetUpdateListAndDequeue(DBEntryBase *db_entry,
      67             :         UpdateList *uplist) {
      68          60 :     CHECK_CONCURRENCY("db::DBTable");
      69             : 
      70             :     DBState *dbstate;
      71          60 :     RouteUpdate *rt_update = uplist->FindUpdate(RibOutUpdates::QUPDATE);
      72          60 :     if (rt_update) {
      73             :         // There's a RouteUpdate for QUPDATE. Remove it from the UpdateList
      74             :         // and move the history to it.  The entry will be reused as if that
      75             :         // was the DBState instead of the UpdateList.
      76          30 :         uplist->RemoveUpdate(rt_update);
      77          30 :         queue_vec_->at(rt_update->queue_id())->Dequeue(rt_update);
      78          30 :         uplist->MoveHistory(rt_update);
      79          30 :         dbstate = rt_update;
      80          30 :     } else if (!uplist->History()->empty()) {
      81             :         // There's no RouteUpdate for QUPDATE, but the history is not empty.
      82             :         // Move the history to a new RouteState.
      83          20 :         RouteState *rstate = new RouteState();
      84          20 :         uplist->MoveHistory(rstate);
      85          20 :         dbstate = rstate;
      86             :     } else {
      87             :         // There's no RouteUpdate for QUPDATE and the history is empty. We
      88             :         // can simply pretend that there was no DBState after we get rid
      89             :         // of the UpdateList.
      90          10 :         dbstate = NULL;
      91             :     }
      92             : 
      93             :     // Get rid of all other RouteUpdates and the UpdateList itself.  Note
      94             :     // that the RouteUpdate for QUPDATE, if any, has already been removed
      95             :     // from the UpdateList at this point.
      96          60 :     UpdateList::List *list = uplist->GetList();
      97          60 :     for (UpdateList::List::iterator iter = list->begin();
      98         120 :          iter != list->end(); iter++) {
      99          60 :         RouteUpdate *temp_rt_update = *iter;
     100          60 :         queue_vec_->at(temp_rt_update->queue_id())->Dequeue(temp_rt_update);
     101          60 :         delete temp_rt_update;
     102             :     }
     103             : 
     104             :     // Update the DBState and return it.
     105          60 :     if (dbstate) {
     106          50 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), dbstate);
     107             :     } else {
     108          10 :         db_entry->ClearState(ribout_->table(), ribout_->listener_id());
     109             :     }
     110          60 :     return dbstate;
     111             : }
     112             : 
     113             : //
     114             : // Get the DBState for the DBEntryBase and dequeue it from an UpdateQueue
     115             : // if required.  The DBState could be a RouteState, a RouteUpdate or an
     116             : // UpdateList.  If it's a RouteState, it won't be on an UpdateQueue.  If
     117             : // it's a RouteUpdate or an UpdateList, see if it's a duplicate i.e. the
     118             : // desired state is the same as the currently advertised state.
     119             : //
     120             : // This routine is used by the export module to obtain exclusive access to
     121             : // the RouteUpdate or UpdateList. The access is exclusive by definition if
     122             : // there's no DBState or it's a RouteState.
     123             : //
     124             : // Return a pointer to the DBState and update duplicate as appropriate.
     125             : //
     126     1472774 : DBState *RibUpdateMonitor::GetDBStateAndDequeue(DBEntryBase *db_entry,
     127             :         UpdateCmp cmp, bool *duplicate) {
     128     1472774 :     CHECK_CONCURRENCY("db::DBTable");
     129             : 
     130     1472758 :     *duplicate = false;
     131             : 
     132             :     // Don't need to bother going through the monitor if there's no DBState.
     133             :     DBState *dbstate =
     134     1472758 :         db_entry->GetState(ribout_->table(), ribout_->listener_id());
     135     1473959 :     if (dbstate == NULL) {
     136      926152 :         return dbstate;
     137             :     }
     138             : 
     139             :     // Go through the monitor and handle the DBState as appropriate.  Note
     140             :     // that we still need to check for the DBState being NULL as things may
     141             :     // have changed after the check made above.
     142             :     while (true) {
     143             :         // Get the DBState; bail if there's no existing state.
     144             :         DBState *dbstate =
     145      547807 :             db_entry->GetState(ribout_->table(), ribout_->listener_id());
     146      547809 :         if (dbstate == NULL) {
     147           0 :             return dbstate;
     148             :         }
     149             : 
     150             :         // Return if it's a RouteState.
     151      547809 :         RouteState *rstate = dynamic_cast<RouteState *>(dbstate);
     152      547809 :         if (rstate != NULL) {
     153      545886 :             return rstate;
     154             :         }
     155             : 
     156             :         // Handle the case where it's a RouteUpdate.
     157        1923 :         RouteUpdate *rt_update = dynamic_cast<RouteUpdate *>(dbstate);
     158        1923 :         if (rt_update != NULL) {
     159        3710 :             return GetRouteUpdateAndDequeue(db_entry, rt_update, cmp,
     160        1855 :                     duplicate);
     161             :         }
     162             : 
     163             :         // Handle the case where it's a UpdateList.
     164          68 :         UpdateList *uplist = dynamic_cast<UpdateList *>(dbstate);
     165             :         DBState *db_state;
     166          68 :         assert(uplist);
     167          68 :         db_state = GetUpdateListAndDequeue(db_entry, uplist);
     168          60 :         delete uplist;
     169          60 :         return db_state;
     170             :     }
     171             : 
     172             :     assert(false);
     173             :     return NULL;
     174             : }
     175             : 
     176             : //
     177             : // Helper routine for GetPeerSetCurrentAndScheduled to handle a RouteState.
     178             : // Go through all the AdvertiseInfo to build the bitset.
     179             : //
     180      456564 : static void RouteStateCurrent(const RouteState *rstate,
     181             :         RibPeerSet *mcurrent) {
     182      456564 :     CHECK_CONCURRENCY("db::DBTable");
     183             : 
     184      455940 :     const AdvertiseSList &adv_slist = rstate->Advertised();
     185      455919 :     for (AdvertiseSList::List::const_iterator iter = adv_slist->begin();
     186     2063330 :          iter != adv_slist->end(); ++iter) {
     187     1152364 :         mcurrent->Set(iter->bitset);
     188             :     }
     189      455295 : }
     190             : 
     191             : //
     192             : // Helper routine for GetPeerSetCurrentAndScheduled to handle a RouteUpdate.
     193             : // Go through all the AdvertiseInfo and UpdateInfo to build the bitset.
     194             : //
     195             : // Do not consider the UpdateInfos if the given queue_id does not match the
     196             : // one in the RouteUpdate.  Note that QCOUNT is considered to be a wildcard.
     197             : //
     198      156117 : static void RouteUpdateCurrentAndScheduled(const RouteUpdate *rt_update,
     199             :         int queue_id, RibPeerSet *mcurrent, RibPeerSet *mscheduled) {
     200      156117 :     CHECK_CONCURRENCY("db::DBTable");
     201             : 
     202      156008 :     const AdvertiseSList &adv_slist = rt_update->History();
     203      156007 :     for (AdvertiseSList::List::const_iterator iter = adv_slist->begin();
     204      671982 :          iter != adv_slist->end(); ++iter) {
     205      360222 :         mcurrent->Set(iter->bitset);
     206             :     }
     207             : 
     208      155834 :     if (queue_id != RibOutUpdates::QCOUNT && queue_id != rt_update->queue_id())
     209       11578 :         return;
     210             : 
     211      144256 :     const UpdateInfoSList &uinfo_slist = rt_update->Updates();
     212      144410 :     for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
     213      579723 :          iter != uinfo_slist->end(); ++iter) {
     214      290990 :         mscheduled->Set(iter->target);
     215             :     }
     216             : }
     217             : 
     218             : //
     219             : // Helper routine for GetPeerSetCurrentAndScheduled to handle a UpdateList.
     220             : // Go through all AdvertiseInfo in the UpdateList and then each RouteUpdate
     221             : // in the UpdateList to build the bitset.
     222             : //
     223         140 : static void UpdateListCurrentAndScheduled(const UpdateList *uplist,
     224             :         int queue_id, RibPeerSet *mcurrent, RibPeerSet *mscheduled) {
     225         140 :     CHECK_CONCURRENCY("db::DBTable");
     226             : 
     227         140 :     const AdvertiseSList &adv_slist = uplist->History();
     228         140 :     for (AdvertiseSList::List::const_iterator iter = adv_slist->begin();
     229         650 :          iter != adv_slist->end(); ++iter) {
     230         370 :         mcurrent->Set(iter->bitset);
     231             :     }
     232             : 
     233         140 :     const UpdateList::List *list = uplist->GetList();
     234         140 :     for (UpdateList::List::const_iterator iter = list->begin();
     235         415 :          iter != list->end(); ++iter) {
     236         275 :         RouteUpdateCurrentAndScheduled(*iter, queue_id, mcurrent, mscheduled);
     237             :     }
     238         140 : }
     239             : 
     240             : //
     241             : // Build the RibPeerSet of peers that are currently advertising the given
     242             : // DBEntryBase or are scheduled to advertise it. The mcurrent parameter is
     243             : // filled with the contents of the advertised bitmask (history) while the
     244             : // mscheduled parameter is filled with the bitmask of updates in the queue.
     245             : //
     246             : // Return false if there's no associated DBState or if it's a RouteState
     247             : // i.e. there's no pending state to be advertised.
     248             : //
     249      863811 : bool RibUpdateMonitor::GetPeerSetCurrentAndScheduled(DBEntryBase *db_entry,
     250             :         int queue_id, RibPeerSet *mcurrent, RibPeerSet *mscheduled) {
     251      863811 :     CHECK_CONCURRENCY("db::DBTable");
     252             : 
     253             :     // Don't need to bother going through the monitor if there's no DBState.
     254             :     DBState *dbstate =
     255      863706 :         db_entry->GetState(ribout_->table(), ribout_->listener_id());
     256      864830 :     if (dbstate == NULL) {
     257      252260 :         return false;
     258             :     }
     259             : 
     260             :     // Go through the monitor and handle the DBState as appropriate.  Note
     261             :     // that we still need to check for the DBState being NULL as things may
     262             :     // have changed after the check made above.
     263             :     while (true) {
     264             :         // Get the DBState; bail if there's no existing state.
     265      612517 :         DBState *dbstate = db_entry->GetState(ribout_->table(),
     266      612570 :                                          ribout_->listener_id());
     267      612586 :         if (dbstate == NULL) {
     268           0 :             return false;
     269             :         }
     270             : 
     271             :         // Handle the case where it's a RouteState.
     272      612586 :         RouteState *rstate = dynamic_cast<RouteState *>(dbstate);
     273      612586 :         if (rstate != NULL) {
     274      456580 :             RouteStateCurrent(rstate, mcurrent);
     275      455703 :             return false;
     276             :         }
     277             : 
     278             :         // Handle the case where it's a RouteUpdate.
     279      156006 :         RouteUpdate *rt_update = dynamic_cast<RouteUpdate *>(dbstate);
     280      156006 :         if (rt_update != NULL) {
     281      155869 :             RouteUpdateCurrentAndScheduled(rt_update, queue_id,
     282             :                     mcurrent, mscheduled);
     283      155692 :             break;
     284             :         }
     285             : 
     286             :         // Handle the case where it's a UpdateList.
     287         137 :         UpdateList *uplist = dynamic_cast<UpdateList *>(dbstate);
     288         137 :         if (uplist != NULL) {
     289         140 :             UpdateListCurrentAndScheduled(uplist, queue_id,
     290             :                     mcurrent, mscheduled);
     291         140 :             break;
     292             :         }
     293             : 
     294             :         // Unknown DBState.
     295           0 :         assert(false);
     296             :     }
     297             : 
     298      155832 :     return true;
     299             : }
     300             : 
     301             : //
     302             : // Helper routine for MergeUpdate to handle case where the current DBState
     303             : // is a RouteState.
     304             : //
     305             : // Move the previous history from the RouteState to the RouteUpdate and
     306             : // enqueue it.
     307             : //
     308             : // Return true if the BgpUpdateSender needs to trigger a tail dequeue for
     309             : // the (RibOut, QueueId).
     310             : //
     311       53122 : bool RibUpdateMonitor::RouteStateMergeUpdate(DBEntryBase *db_entry,
     312             :         RouteUpdate *rt_update, RouteState *rstate) {
     313       53122 :     CHECK_CONCURRENCY("db::DBTable");
     314             : 
     315       53104 :     rstate->MoveHistory(rt_update);
     316       53104 :     delete rstate;
     317       53109 :     return EnqueueUpdate(db_entry, rt_update);
     318             : }
     319             : 
     320             : //
     321             : // Helper routine for MergeUpdate to handle case where the current DBState
     322             : // is a RouteUpdate.
     323             : //
     324             : // If the new RouteUpdate is for the same queue as the current RouteUpdate,
     325             : // dequeue the current, merge in the UpdateInfo from the new and enqueue it
     326             : // again. Otherwise, build an UpdateList containing both RouteUpdates and
     327             : // enqueue the new RouteUpdate.
     328             : //
     329             : // Return true if the BgpUpdateSender needs to trigger a tail dequeue for
     330             : // the (RibOut, QueueId).
     331             : //
     332          47 : bool RibUpdateMonitor::RouteUpdateMergeUpdate(DBEntryBase *db_entry,
     333             :         RouteUpdate *rt_update, RouteUpdate *current_rt_update) {
     334          47 :     CHECK_CONCURRENCY("db::DBTable");
     335             : 
     336          47 :     if (current_rt_update->queue_id() == rt_update->queue_id()) {
     337          37 :         UpdateQueue *queue = queue_vec_->at(current_rt_update->queue_id());
     338          37 :         queue->Dequeue(current_rt_update);
     339          37 :         current_rt_update->MergeUpdateInfo(rt_update->Updates());
     340          37 :         assert(rt_update->Updates()->empty());
     341          37 :         delete rt_update;
     342          37 :         return EnqueueUpdate(db_entry, current_rt_update);
     343             :     } else {
     344          10 :         UpdateList *uplist = current_rt_update->MakeUpdateList();
     345          10 :         uplist->AddUpdate(rt_update);
     346          10 :         return EnqueueUpdate(db_entry, rt_update, uplist);
     347             :     }
     348             : }
     349             : 
     350             : //
     351             : // Helper routine for MergeUpdate to handle case where the current DBState
     352             : // is a UpdateList.
     353             : //
     354             : // Figure out if the UpdateList already has a RouteUpdate for this queue.
     355             : // If so, dequeue the existing RouteUpdate, merge the UpdateInfo from the
     356             : // new one and enqueue the existing RouteUpdate again. Otherwise, add the
     357             : // new RouteUpdate to the UpdateList and enqueue the RouteUpdate.
     358             : //
     359             : // Return true if the BgpUpdateSender needs to trigger a tail dequeue for
     360             : // the (RibOut, QueueId).
     361             : //
     362          25 : bool RibUpdateMonitor::UpdateListMergeUpdate(DBEntryBase *db_entry,
     363             :         RouteUpdate *rt_update, UpdateList *uplist) {
     364          25 :     CHECK_CONCURRENCY("db::DBTable");
     365             : 
     366          25 :     RouteUpdate *current_rt_update = uplist->FindUpdate(rt_update->queue_id());
     367          25 :     if (current_rt_update) {
     368          20 :         UpdateQueue *queue = queue_vec_->at(current_rt_update->queue_id());
     369          20 :         queue->Dequeue(current_rt_update);
     370          20 :         current_rt_update->MergeUpdateInfo(rt_update->Updates());
     371          20 :         assert(rt_update->Updates()->empty());
     372          20 :         delete rt_update;
     373          20 :         return EnqueueUpdate(db_entry, current_rt_update, uplist);
     374             :     } else {
     375           5 :         uplist->AddUpdate(rt_update);
     376           5 :         return EnqueueUpdate(db_entry, rt_update, uplist);
     377             :     }
     378             : }
     379             : 
     380             : //
     381             : // Take the desired state as represented by the RouteUpdate and merge it with
     382             : // any previously advertised state for the DBEntryBase. Note that the previous
     383             : // state could be for a different queue and/or other peers in the RibOut.
     384             : //
     385             : // Return true if the BgpUpdateSender needs to trigger a tail dequeue for
     386             : // the (RibOut, QueueId).
     387             : //
     388       79396 : bool RibUpdateMonitor::MergeUpdate(DBEntryBase *db_entry,
     389             :         RouteUpdate *rt_update) {
     390       79396 :     CHECK_CONCURRENCY("db::DBTable");
     391             : 
     392             :     // Go through the monitor and handle the DBState as necessary. Need
     393             :     // to use the monitor even if there's no DBState in order to protect
     394             :     // against race conditions which could result in an incorrect return
     395             :     // value.
     396             :     while (true) {
     397             :         DBState *dbstate =
     398       79405 :             db_entry->GetState(ribout_->table(), ribout_->listener_id());
     399             : 
     400             :         // Handle the case where there's no DBState.  Simply add the new
     401             :         // RouteUpdate to the queue.
     402       79426 :         if (dbstate == NULL) {
     403       26230 :             return EnqueueUpdate(db_entry, rt_update);
     404             :         }
     405             : 
     406             :         // Handle the case where it's a RouteState.
     407       53196 :         RouteState *rstate = dynamic_cast<RouteState *>(dbstate);
     408       53196 :         if (rstate != NULL) {
     409       53123 :             return RouteStateMergeUpdate(db_entry, rt_update, rstate);
     410             :         }
     411             : 
     412             :         // Handle the case where it's a RouteUpdate.
     413          73 :         RouteUpdate *current_rt_update = dynamic_cast<RouteUpdate *>(dbstate);
     414          73 :         if (current_rt_update != NULL) {
     415          47 :             return RouteUpdateMergeUpdate(db_entry, rt_update,
     416          47 :                     current_rt_update);
     417             :         }
     418             : 
     419             :         // Handle the case where it's a UpdateList.
     420          26 :         UpdateList *uplist = dynamic_cast<UpdateList *>(dbstate);
     421          26 :         if (uplist != NULL) {
     422          25 :             return UpdateListMergeUpdate(db_entry, rt_update, uplist);
     423             :         }
     424             : 
     425             :         // Unknown DBState.
     426           1 :         assert(false);
     427             :     }
     428             : 
     429             :     assert(false);
     430             :     return false;
     431             : }
     432             : 
     433             : //
     434             : // Traipse through all the AdvertiseInfo elements in the list and clear the
     435             : // RibPeerSet. If the RibPeerSet in an element becomes empty, remove it from
     436             : // the list container and get rid of the element.
     437             : //
     438      261203 : void RibUpdateMonitor::AdvertiseSListClearBits(AdvertiseSList &adv_slist,
     439             :         const RibPeerSet &clear) {
     440      261203 :     CHECK_CONCURRENCY("db::DBTable");
     441             : 
     442      261199 :     for (AdvertiseSList::List::iterator iter = adv_slist->begin();
     443     1172287 :          iter != adv_slist->end(); ) {
     444      324967 :         iter->bitset.Reset(clear);
     445      324870 :         if (iter->bitset.empty()) {
     446      548337 :             iter = adv_slist->erase_and_dispose(iter, AdvertiseInfoDisposer());
     447             :         } else {
     448      142162 :             iter++;
     449             :         }
     450             :     }
     451      261043 : }
     452             : 
     453             : //
     454             : // Traipse through all the UpdateInfo elements in the list and clear the
     455             : // RibPeerSet. If the RibPeerSet in an element becomes empty, remove it
     456             : // from the set and list containers and get rid of the element.
     457             : //
     458       61102 : void RibUpdateMonitor::UpdateInfoSListClearBits(UpdateInfoSList &uinfo_slist,
     459             :         const RibPeerSet &clear) {
     460       61102 :     CHECK_CONCURRENCY("db::DBTable");
     461             : 
     462       61087 :     for (UpdateInfoSList::List::iterator iter = uinfo_slist->begin();
     463      245721 :          iter != uinfo_slist->end(); ) {
     464       61723 :         iter->target.Reset(clear);
     465       61714 :         if (iter->target.empty()) {
     466       60394 :             RouteUpdate *rt_update = iter->update;
     467       60394 :             UpdateQueue *queue = queue_vec_->at(rt_update->queue_id());
     468      120816 :             queue->AttrDequeue(iter.operator->());
     469      181357 :             iter = uinfo_slist->erase_and_dispose(iter, UpdateInfoDisposer());
     470             :         } else {
     471        1322 :             iter++;
     472             :         }
     473             :     }
     474       61099 : }
     475             : 
     476             : //
     477             : // Helper routine for ClearPeerSetCurrentAndScheduled to handle case where
     478             : // the current DBState is a RouteState.
     479             : //
     480             : // Clean up the AdvertiseInfos corresponding to the peers in RibPeerSet.
     481             : //
     482      200408 : void RibUpdateMonitor::RouteStateClearPeerSet(DBEntryBase *db_entry,
     483             :         RouteState *rstate, const RibPeerSet &mleave) {
     484      200408 :     CHECK_CONCURRENCY("db::DBTable");
     485             : 
     486             :     // Clear the bits for each element in the AdvertiseSList.
     487      200224 :     AdvertiseSListClearBits(rstate->Advertised(), mleave);
     488             : 
     489             :     // Get rid of the RouteState itself if it's empty.
     490      200254 :     if (rstate->Advertised()->empty()) {
     491      104507 :         db_entry->ClearState(ribout_->table(), ribout_->listener_id());
     492      104585 :         delete rstate;
     493             :     }
     494      200237 : }
     495             : 
     496             : //
     497             : // Helper routine for ClearPeerSetCurrentAndScheduled to handle case where
     498             : // the current DBState is a RouteUpdate.
     499             : //
     500             : // Clean up the UpdateInfos corresponding to the peers in RibPeerSet.
     501             : //
     502             : // Return true if rt_update has to be deleted, false otherwise
     503             : //
     504       61042 : bool RibUpdateMonitor::RouteUpdateClearPeerSet(DBEntryBase *db_entry,
     505             :             RouteUpdate *rt_update, const RibPeerSet &mleave) {
     506       61042 :     CHECK_CONCURRENCY("db::DBTable");
     507             : 
     508             :     // Clear the bits for each element in the AdvertiseSList.
     509       60937 :     AdvertiseSListClearBits(rt_update->History(), mleave);
     510             : 
     511             :     // Clear the bits for each element in the UpdateInfoSList.
     512       60949 :     UpdateInfoSListClearBits(rt_update->Updates(), mleave);
     513             : 
     514             :     // Update the DBstate for the DBentry as appropriate.
     515       60990 :     if (!rt_update->Updates()->empty()) {
     516             :         // There are more scheduled updates, do nothing.
     517        1182 :         return false;
     518             :     }
     519             : 
     520       59796 :     if (!rt_update->History()->empty()) {
     521             :         // No more scheduled updates but there are current updates. Dequeue
     522             :         // the RouteUpdate, move the history to a new RouteState and get rid
     523             :         // of the RouteUpdate.
     524       14724 :         DequeueUpdate(rt_update);
     525       14727 :         RouteState *rstate = new RouteState;
     526       14727 :         rt_update->MoveHistory(rstate);
     527       14725 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), rstate);
     528             :     } else {
     529             :         // No more scheduled or current updates.  Dequeue the RouteUpdate,
     530             :         // clear the state on the DBEntry and get rid of the RouteUpdate.
     531       45063 :         DequeueUpdate(rt_update);
     532       45047 :         db_entry->ClearState(ribout_->table(), ribout_->listener_id());
     533             :     }
     534             : 
     535       59855 :     return true;
     536             : }
     537             : 
     538             : //
     539             : // Helper routine for ClearPeerSetCurrentAndScheduled to handle case where
     540             : // the current DBState is a UpdateList.
     541             : //
     542             : // Return true if uplist has to be deleted, false otherwise
     543             : //
     544          80 : bool RibUpdateMonitor::UpdateListClearPeerSet(DBEntryBase *db_entry,
     545             :         UpdateList *uplist, const RibPeerSet &mleave) {
     546          80 :     CHECK_CONCURRENCY("db::DBTable");
     547             : 
     548          80 :     UpdateList::List *list = uplist->GetList();
     549             : 
     550             :     // Clear the bits for each element in the AdvertiseSList.
     551          80 :     AdvertiseSListClearBits(uplist->History(), mleave);
     552             : 
     553             :     // Clear the bits for each element in the UpdateInfoSList for each
     554             :     // RouteUpdate. If a RouteUpdate becomes empty as a result, get rid
     555             :     // of it.
     556          80 :     for (UpdateList::List::iterator iter = list->begin();
     557         240 :          iter != list->end(); ) {
     558         160 :         RouteUpdate *rt_update = *iter++;
     559         160 :         UpdateInfoSListClearBits(rt_update->Updates(), mleave);
     560         160 :         if (rt_update->Updates()->empty()) {
     561          80 :             uplist->RemoveUpdate(rt_update);
     562          80 :             DequeueUpdate(rt_update);
     563          80 :             delete rt_update;
     564             :         }
     565             :     }
     566             : 
     567             :     // Update the DBstate for the DBentry as appropriate.
     568          80 :     if (list->size() > 1) {
     569             :         // There's multiple RouteUpdates on the UpdateList, do nothing.
     570          30 :         return false;
     571          50 :     } else if (list->size() == 1) {
     572             :         // There's exactly 1 RouteUpdate on the UpdateList. Downgrade
     573             :         // the UpdateList to a RouteUpdate and get rid of UpdateList.
     574             :         // Note that the history will be moved to the RouteUpdate as
     575             :         // part of the downgrade.
     576          20 :         RouteUpdate *rt_update = uplist->MakeRouteUpdate();
     577          20 :         assert(rt_update);
     578          20 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), rt_update);
     579          30 :     } else if (!uplist->History()->empty()) {
     580             :         // There's no RouteUpdates on the UpdateList, but the history
     581             :         // is not empty.  Move the history to a new RouteState and get
     582             :         // rid of the UpdateList.
     583          20 :         RouteState *rstate = new RouteState;
     584          20 :         uplist->MoveHistory(rstate);
     585          20 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), rstate);
     586             :     } else {
     587             :         // There's no RouteUpdates on the UpdateList and the history is
     588             :         // empty. Clear state on the DBEntry and get rid of UpdateList.
     589          10 :         db_entry->ClearState(ribout_->table(), ribout_->listener_id());
     590             :     }
     591             : 
     592          50 :     return true;
     593             : }
     594             : 
     595             : //
     596             : // Cancel all scheduled updates and clean up AdvertiseInfo corresponding
     597             : // to any current updates for the peers in the RibPeerSet.
     598             : //
     599      261101 : void RibUpdateMonitor::ClearPeerSetCurrentAndScheduled(DBEntryBase *db_entry,
     600             :         const RibPeerSet &mleave) {
     601      261101 :     CHECK_CONCURRENCY("db::DBTable");
     602             : 
     603             :     // Don't need to bother going through the monitor if there's no DBState.
     604             :     DBState *dbstate =
     605      261194 :         db_entry->GetState(ribout_->table(), ribout_->listener_id());
     606      261513 :     if (dbstate == NULL) {
     607           0 :         return;
     608             :     }
     609             : 
     610             :     // Go through the monitor and handle the DBState as appropriate.  Note
     611             :     // that we still need to check for the DBState being NULL as things may
     612             :     // have changed after the check made above.
     613             :     while (true) {
     614             :         DBState *dbstate =
     615      261513 :             db_entry->GetState(ribout_->table(), ribout_->listener_id());
     616             : 
     617             :         // Handle the case where there's no DBState.
     618      261529 :         if (dbstate == NULL) {
     619           0 :             return;
     620             :         }
     621             : 
     622             :         // Handle the case where it's a RouteState.
     623      261529 :         RouteState *rstate = dynamic_cast<RouteState *>(dbstate);
     624      261529 :         if (rstate != NULL) {
     625      200407 :             RouteStateClearPeerSet(db_entry, rstate, mleave);
     626      200223 :             return;
     627             :         }
     628             : 
     629             :         // Handle the case where it's a RouteUpdate.
     630       61122 :         RouteUpdate *rt_update = dynamic_cast<RouteUpdate *>(dbstate);
     631       61122 :         if (rt_update != NULL) {
     632             :             bool delete_rt_update =
     633       61042 :                 RouteUpdateClearPeerSet(db_entry, rt_update, mleave);
     634       61036 :             if (delete_rt_update) {
     635       59854 :                 delete rt_update;
     636             :             }
     637       61032 :             return;
     638             :         }
     639             : 
     640             :         // Handle the case where it's a UpdateList.
     641          80 :         UpdateList *uplist = dynamic_cast<UpdateList *>(dbstate);
     642             :         bool delete_uplist;
     643             : 
     644          80 :         assert(uplist);
     645          80 :         delete_uplist = UpdateListClearPeerSet(db_entry, uplist, mleave);
     646          80 :         if (delete_uplist) {
     647          50 :             delete uplist;
     648             :         }
     649          80 :         return;
     650             :     }
     651             : 
     652             :     assert(false);
     653             : }
     654             : 
     655             : //
     656             : // Enqueue the specified RouteUpdate to the UpdateQueue and set the listener
     657             : // state for the for the DBEntry to point to the RouteUpdate.
     658             : // Set the listener state to the UpdateList if it is non-NULL, else set it to
     659             : // the RouteUpdate.
     660             : //
     661             : // Return true if the BgpUpdateSender needs to trigger a tail dequeue for
     662             : // the (RibOut, QueueId).
     663             : //
     664      979458 : bool RibUpdateMonitor::EnqueueUpdate(DBEntryBase *db_entry,
     665             :         RouteUpdate *rt_update, UpdateList *uplist) {
     666      979458 :     CHECK_CONCURRENCY("db::DBTable");
     667             : 
     668      979505 :     UpdateQueue *queue = queue_vec_->at(rt_update->queue_id());
     669      979497 :     if (uplist) {
     670          35 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), uplist);
     671             :     } else {
     672      979462 :         db_entry->SetState(ribout_->table(), ribout_->listener_id(), rt_update);
     673             :     }
     674      979960 :     return queue->Enqueue(rt_update);
     675             : }
     676             : 
     677             : //
     678             : // Dequeue the specified RouteUpdate from it's UpdateQueue.
     679             : //
     680      978020 : void RibUpdateMonitor::DequeueUpdate(RouteUpdate *rt_update) {
     681      978020 :     CHECK_CONCURRENCY("db::DBTable", "bgp::SendUpdate");
     682             : 
     683      978029 :     UpdateQueue *queue = queue_vec_->at(rt_update->queue_id());
     684      978021 :     queue->Dequeue(rt_update);
     685      978121 : }
     686             : 
     687             : //
     688             : // Get the next RouteUpdate after the provided UpdateEntry and return
     689             : // the RouteUpdatePtr encapsulator for it.
     690             : //
     691             : // If the next RouteUpdate is NULL, move the tail marker to be after
     692             : // the UpdateEntry.  The tail marker move must be done must be done
     693             : // atomically with returning a NULL RouteUpdatePtr. This ensures that
     694             : // Enqueue can correctly detect the need to trigger a tail dequeue.
     695             : //
     696     1234283 : RouteUpdatePtr RibUpdateMonitor::GetNextUpdate(int queue_id,
     697             :         UpdateEntry *upentry) {
     698     1234283 :     CHECK_CONCURRENCY("bgp::SendUpdate");
     699             : 
     700     1234202 :     UpdateQueue *queue = queue_vec_->at(queue_id);
     701     1234209 :     RouteUpdate *next_rt_update = queue->NextUpdate(upentry);
     702     1234248 :     RouteUpdatePtr update(next_rt_update);
     703     1234408 :     if (!next_rt_update && upentry->IsUpdate()) {
     704      604650 :         RouteUpdate *rt_update = static_cast<RouteUpdate *>(upentry);
     705      604650 :         queue->MoveMarker(queue->tail_marker(), rt_update);
     706             :     }
     707     1234383 :     return update;
     708           0 : }
     709             : 
     710             : //
     711             : // Get the next UpdateEntry after the one provided and return it via
     712             : // the output parameter.
     713             : //
     714             : // Return the RouteUpdatePtr encapsulator for the next UpdateEntry
     715             : // if it's a RouteUpdate.  If it's not, return an encapsulator for
     716             : // a NULL RouteUpdate.
     717             : //
     718         507 : RouteUpdatePtr RibUpdateMonitor::GetNextEntry(int queue_id,
     719             :         UpdateEntry *upentry, UpdateEntry **next_upentry_p) {
     720         507 :     CHECK_CONCURRENCY("bgp::SendUpdate");
     721             : 
     722         507 :     UpdateQueue *queue = queue_vec_->at(queue_id);
     723         507 :     UpdateEntry *next_upentry = *next_upentry_p = queue->NextEntry(upentry);
     724         507 :     if (next_upentry != NULL && next_upentry->IsUpdate()) {
     725         419 :         RouteUpdate *rt_update = static_cast<RouteUpdate *>(next_upentry);
     726         419 :         RouteUpdatePtr update(rt_update);
     727         419 :         return update;
     728         419 :     }
     729          88 :     return RouteUpdatePtr();
     730             : }
     731             : 
     732             : //
     733             : // Get the next UpdateInfo after the one provided and return it via
     734             : // the output parameter.
     735             : //
     736             : // Return the RouteUpdatePtr encapsulator for the RouteUpdate that
     737             : // corresponds to the next UpdateInfo. If there's no next UpdateInfo
     738             : // return an encapsulator for a NULL RouteUpdate.
     739             : //
     740      927953 : RouteUpdatePtr RibUpdateMonitor::GetAttrNext(int queue_id,
     741             :         UpdateInfo *current_uinfo, UpdateInfo **next_uinfo_p) {
     742      927953 :     CHECK_CONCURRENCY("bgp::SendUpdate");
     743             : 
     744      927813 :     UpdateQueue *queue = queue_vec_->at(queue_id);
     745      927802 :     UpdateInfo *next_uinfo = queue->AttrNext(current_uinfo);
     746      927958 :     RouteUpdate *rt_update = NULL;
     747      927958 :     if (next_uinfo) {
     748      315513 :         rt_update = next_uinfo->update;
     749             :     }
     750      927958 :     RouteUpdatePtr update(rt_update);
     751      927965 :     *next_uinfo_p = next_uinfo;
     752      927965 :     return update;
     753             : }
     754             : 
     755             : //
     756             : // Set the listener state for the DBEntryBase to be the DBState.
     757             : //
     758      584115 : void RibUpdateMonitor::SetEntryState(DBEntryBase *db_entry, DBState *dbstate) {
     759      584115 :     CHECK_CONCURRENCY("bgp::SendUpdate");
     760             : 
     761      584149 :     db_entry->SetState(ribout_->table(), ribout_->listener_id(), dbstate);
     762      584262 : }
     763             : 
     764             : //
     765             : // Clear the listener state for the DBEntryBase.
     766             : //
     767      333976 : void RibUpdateMonitor::ClearEntryState(DBEntryBase *db_entry) {
     768      333976 :     CHECK_CONCURRENCY("bgp::SendUpdate");
     769             : 
     770      333984 :     db_entry->ClearState(ribout_->table(), ribout_->listener_id());
     771      334150 : }

Generated by: LCOV version 1.14