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