OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bgp_update.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "bgp/bgp_update.h"
6 
7 #include "bgp/bgp_route.h"
8 #include "bgp/bgp_table.h"
9 
10 //
11 // Find the UpdateInfo element with matching RibOutAttr.
12 //
14  const RibOutAttr &roattr) const {
15  for (List::const_iterator iter = list_.begin();
16  iter != list_.end(); ++iter) {
17  if (iter->roattr == roattr) return iter.operator->();
18  }
19  return NULL;
20 }
21 
22 RouteUpdate::RouteUpdate(BgpRoute *route, int queue_id)
24  route_(route),
25  queue_id_(queue_id),
26  flags_(0) {
27 }
28 
31  ClearHistory();
32 }
33 
34 //
35 // Set the given UpdateInfoSList in the RouteUpdate to the given value.
36 //
37 // Note that the back pointers from the individual UpdateInfo elements
38 // to the RouteUpdate will be set up when the RouteUpdate gets enqueued
39 // to an UpdateQueue.
40 //
42  assert(updates_->empty());
43  updates_.swap(uinfo_slist);
44 }
45 
46 //
47 // Get rid of all the UpdateInfo elements in the RouteUpdate. Each element
48 // is also deleted.
49 //
51  updates_->clear_and_dispose(UpdateInfoDisposer());
52 }
53 
54 //
55 // Remove the UpdateInfo element from the UpdateInfoSList and delete the
56 // element.
57 //
58 // Return true if the UpdateInfoSList is now empty.
59 //
61  updates_->erase_and_dispose(updates_->iterator_to(*uinfo),
63  return updates_->empty();
64 }
65 
66 //
67 // Find the UpdateInfo element with matching RibOutAttr.
68 //
70  for (UpdateInfoSList::List::iterator iter = updates_->begin();
71  iter != updates_->end(); ++iter) {
72  if (iter->roattr == roattr) return iter.operator->();
73  }
74  return NULL;
75 }
76 
77 //
78 // Find the UpdateInfo element with matching RibOutAttr, full of const
79 // goodness so it can be used by CompareUpdateInfo.
80 //
81 const UpdateInfo *RouteUpdate::FindUpdateInfo(const RibOutAttr &roattr) const {
82  for (UpdateInfoSList::List::const_iterator iter = updates_->begin();
83  iter != updates_->end(); ++iter) {
84  if (iter->roattr == roattr) return iter.operator->();
85  }
86  return NULL;
87 }
88 
89 //
90 // Reset the given RibPeerSet from the target of all UpdateInfo elements. Get
91 // rid of any elements whose target becomes empty.
92 //
94  for (UpdateInfoSList::List::iterator iter = updates_->begin();
95  iter != updates_->end(); ) {
96  iter->target.Reset(peerset);
97  if (iter->target.empty()) {
98  iter = updates_->erase_and_dispose(iter, UpdateInfoDisposer());
99  } else {
100  ++iter;
101  }
102  }
103 }
104 
105 //
106 // Compare this RouteUpdate with the UpdateInfo elements in the given list.
107 // The UpdateInfos and AdvertiseInfos in the RouteUpdate represent the old
108 // state and the UpdateInfoSList represents the new state.
109 //
110 // Uses brute force since the UpdateInfo and AdvertiseInfo lists typically
111 // contain just a single element.
112 //
113 // Return true if the information in the RouteUpdate is logically the same
114 // as that in the UpdateInfoSList.
115 //
116 bool RouteUpdate::CompareUpdateInfo(const UpdateInfoSList &uinfo_slist) const {
117  // Handle the special case where the given UpdateInfoSList is empty.
118  //
119  // If we already have withdraws scheduled to all peers to which the
120  // route was sent earlier, and there are no other scheduled updates,
121  // we can safely consider the RouteUpdate to have the same state as
122  // an empty UpdateInfoSList.
123  RibOutAttr roattr_null;
124  if (uinfo_slist->empty() &&
125  updates_->size() == 1 && updates_->begin()->roattr == roattr_null) {
126  RibPeerSet withdraw_peerset = updates_->begin()->target;
127  for (AdvertiseSList::List::const_iterator iter = history_->begin();
128  iter != history_->end(); ++iter) {
129  if (!withdraw_peerset.Contains(iter->bitset))
130  return false;
131  }
132  return true;
133  }
134 
135  // All the peers that we sent the route to previously must be covered
136  // by the UpdateInfos in the given UpdateInfoSList. If this is not the
137  // case, we would need to schedule withdraws to the peers that are not
138  // covered.
139  RibPeerSet old_peerset, new_peerset;
140  for (AdvertiseSList::List::const_iterator iter = history_->begin();
141  iter != history_->end(); ++iter) {
142  old_peerset.Set(iter->bitset);
143  }
144  for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
145  iter != uinfo_slist->end(); ++iter) {
146  new_peerset.Set(iter->target);
147  }
148  if (!new_peerset.Contains(old_peerset))
149  return false;
150 
151  // Compare the peerset for each UpdateInfo in the UpdateInfoSList to
152  // the peerset for the corresponding UpdateInfo and AdvertiseInfo in
153  // in the RouteUpdate i.e. the ones for the same RibOutAttr. Each
154  // peer in the new UpdateInfo must either be in the old UpdateInfo or
155  // AdvertiseInfo.
156  for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
157  iter != uinfo_slist->end(); ++iter) {
158  RibPeerSet attr_peerset;
159  const UpdateInfo *uinfo = FindUpdateInfo(iter->roattr);
160  if (uinfo)
161  attr_peerset.Set(uinfo->target);
162  const AdvertiseInfo *ainfo = FindHistory(iter->roattr);
163  if (ainfo)
164  attr_peerset.Set(ainfo->bitset);
165  if (iter->target != attr_peerset)
166  return false;
167  }
168 
169  // Compare the peerset for each UpdateInfo in the RouteUpdate to the
170  // corresponding UpdateInfo in the given UpdateInfoSList. The peerset
171  // from the old UpdateInfo needs to be a subset of the peerset from
172  // the new UpdateInfo. It need not be equal since we may already have
173  // sent the old state to some peers and moved them to the history.
174  for (UpdateInfoSList::List::const_iterator iter = updates_->begin();
175  iter != updates_->end(); ++iter) {
176  const UpdateInfo *uinfo = uinfo_slist.FindUpdateInfo(iter->roattr);
177  if (!uinfo || !uinfo->target.Contains(iter->target))
178  return false;
179  }
180 
181  return true;
182 }
183 
184 //
185 // Merge the list of UpdateInfo elements into the RouteUpdate. If we find
186 // an UpdateInfo with the same RibOutAttr, we modify it's target in place.
187 // Otherwise, we reset the target bits in any existing UpdateInfos in the
188 // RouteUpdate and move the UpdateInfo from the list into the RouteUpdate.
189 //
191  for (UpdateInfoSList::List::iterator iter = uinfo_slist->begin();
192  iter != uinfo_slist->end(); ) {
193  UpdateInfo *uinfo = FindUpdateInfo(iter->roattr);
194  if (uinfo) {
195  uinfo->target |= iter->target;
196  iter = uinfo_slist->erase_and_dispose(iter, UpdateInfoDisposer());
197  } else {
198  UpdateInfo &temp_uinfo = *iter;
199  ResetUpdateInfo(temp_uinfo.target);
200  iter = uinfo_slist->erase(iter);
201  updates_->push_front(temp_uinfo);
202  }
203  }
204 }
205 
206 //
207 // The AdvertiseSList in the history contains state that has been sent to
208 // a set of peers, and the given UpdateInfoSList represents state that we
209 // intend to send to a possibly different set of peers.
210 //
211 // If there are peers in any AdvertiseInfo in the history for which there
212 // is no state in the UpdateInfoSList, create an UpdateInfo with negative
213 // state to withdraw what we sent out previously. This UpdateInfo has null
214 // RibOutAttr and a RibPeerSet of all peers from which we need to withdraw
215 // the route.
216 //
218  RibPeerSet peerset;
219 
220  // Build the bitset of peers to which we previously advertised something.
221  for (AdvertiseSList::List::const_iterator iter = history_->begin();
222  iter != history_->end(); ++iter) {
223  peerset.Set(iter->bitset);
224  }
225 
226  // Remove the peers to which we are going to send updated state.
227  for (UpdateInfoSList::List::const_iterator iter = uinfo_slist->begin();
228  iter != uinfo_slist->end(); ++iter) {
229  peerset.Reset(iter->target);
230  }
231 
232  // Push an UpdateInfo for a withdraw if the bitset is non-empty.
233  if (!peerset.empty()) {
234  UpdateInfo *uinfo = new UpdateInfo(peerset);
235  uinfo_slist->push_front(*uinfo);
236  }
237 }
238 
239 //
240 // If any UpdateInfo element in the UpdateInfoSList describes state that's
241 // already in one of the AdvertiseInfos in the history, trim that state to
242 // avoid sending duplicate information.
243 //
244 // The RibPeerSet in the UpdateInfo need not be exactly the same as that in
245 // the AdevrtiseInfo. If the RibOutAttrs match, we can trim the RibPeerSet
246 // in the UpdateInfo.
247 //
249  for (AdvertiseSList::List::const_iterator iter = history_->begin();
250  iter != history_->end(); ++iter) {
251  const AdvertiseInfo *ainfo = iter.operator->();
252 
253  for (UpdateInfoSList::List::iterator iter = uinfo_slist->begin();
254  iter != uinfo_slist->end(); ++iter) {
255  // Keep going if the attributes are different.
256  if (iter->roattr != ainfo->roattr)
257  continue;
258 
259  // Found one with matching attributes. Reset the target bits in
260  // the UpdateInfo. Get rid of the UpdateInfo if the target is now
261  // empty.
262  iter->target.Reset(ainfo->bitset);
263  if (iter->target.empty()) {
264  uinfo_slist->erase_and_dispose(iter, UpdateInfoDisposer());
265  }
266 
267  // Since a given UpdateInfoSList can have at most one UpdateInfo
268  // with any given attributes, there's no point in looking at any
269  // more UpdateInfos.
270  break;
271  }
272  }
273 }
274 
275 //
276 // Set the given AdvertiseSList in the RouteUpdate to the given value.
277 //
278 // Should be used only for testing.
279 //
281  assert(history_->empty());
282  history_.swap(history);
283 }
284 
285 //
286 // Get rid of all the AdvertiseInfo elements in the RouteUpdate. Each element
287 // is also deleted.
288 //
290  history_->clear_and_dispose(AdvertiseInfoDisposer());
291 }
292 
293 //
294 // Move history from RouteUpdate to RouteState.
295 //
297  AdvertiseSList adv_slist;
298  SwapHistory(adv_slist);
299  rstate->SwapHistory(adv_slist);
300 }
301 
302 //
303 // Find the history element with matching RibOutAttr.
304 //
305 const AdvertiseInfo *RouteUpdate::FindHistory(const RibOutAttr &roattr) const {
306  for (AdvertiseSList::List::const_iterator iter = history_->begin();
307  iter != history_->end(); ++iter) {
308  if (iter->roattr == roattr) return iter.operator->();
309  }
310  return NULL;
311 }
312 
313 //
314 // Update the history information for the RouteUpdate to include the given
315 // RibOutAttr and the RibPeerSet. This may entail an update to an existing
316 // AdvertiseInfo or the creation of a new one, as well as possible deletion
317 // of an existing one.
318 //
319 void RouteUpdate::UpdateHistory(RibOut *ribout, const RibOutAttr *roattr,
320  const RibPeerSet &bits) {
321  // The history information may reside in the RouteUpdate itself or in
322  // the associated UpdateList if the RouteUpdate in on an UpdateList.
323  AdvertiseSList &adv_slist =
324  (OnUpdateList() ? GetUpdateList(ribout)->History() : history_);
325 
326  // Traipse through all the AdvertiseInfo elements in the history. We
327  // obviously need to find one with a matching RibOutAttr if it exists
328  // and update it's RibPeerSet. Additionally, we also want to reset
329  // the RibPeerSet in all other elements since we may have previously
330  // advertised different attributes to some of the peers in the set.
331  AdvertiseInfo *ainfo = NULL;
332  for (AdvertiseSList::List::iterator iter = adv_slist->begin();
333  iter != adv_slist->end(); ) {
334  // Remember if we find the matching element, and move on to the
335  // next one.
336  if (iter->roattr == *roattr) {
337  assert(ainfo == NULL);
338  ainfo = iter.operator->();
339  ++iter;
340  continue;
341  }
342 
343  // TBD: optimize to reuse an element with the same RibPeerSet but
344  // different attributes.
345 
346  // Reset the bits in the current element. If the RibPeerSet in the
347  // element becomes empty, get rid of it.
348  iter->bitset.Reset(bits);
349  if (iter->bitset.empty()) {
350  AdvertiseSList::List::iterator prev_iter = iter++;
351  adv_slist->erase_and_dispose(prev_iter, AdvertiseInfoDisposer());
352  } else {
353  ++iter;
354  }
355  }
356 
357  // Update an existing element if we found one or create a new one with
358  // the appropriate state.
359  if (roattr->IsReachable()) {
360  if (ainfo == NULL) {
361  ainfo = new AdvertiseInfo(roattr);
362  adv_slist->push_front(*ainfo);
363  }
364  ainfo->bitset |= bits;
365  } else {
366  assert(ainfo == NULL);
367  }
368 }
369 
370 //
371 // Return true if this RouteUpdate has been advertised to anyone. We simply
372 // go through all the AdvertiseInfo elements in the history and check if we
373 // have at least one that's reachable.
374 //
376  for (AdvertiseSList::List::const_iterator iter = history_->begin();
377  iter != history_->end(); ++iter) {
378  if (iter->roattr.IsReachable()) {
379  return true;
380  }
381  }
382  return false;
383 }
384 
385 //
386 // Upgrade this RouteUpdate to an UpdateList. Creates a new UpdateList and
387 // adds the RouteUpdate to it. Also moves the history from the RouteUpdate
388 // to the UpdateList.
389 //
390 // Returns the new UpdateList.
391 //
393  UpdateList *uplist = new UpdateList;
394  AdvertiseSList history;
395  SwapHistory(history);
396  uplist->SwapHistory(history);
397  uplist->AddUpdate(this);
398  return uplist;
399 }
400 
401 //
402 // Return the UpdateList that contains this RouteUpdate. Assumes that the
403 // RouteUpdate is on an UpdateList.
404 //
407  DBState *dbstate = route_->GetState(ribout->table(), ribout->listener_id());
408  UpdateList *uplist = dynamic_cast<UpdateList *>(dbstate);
409  assert(uplist);
410  return uplist;
411 }
412 
413 //
414 // Set the given AdvertiseSList in the UpdateList to the given value.
415 //
416 // Should be used only for testing.
417 //
419  assert(history_->empty());
420  history_.swap(history);
421 }
422 
423 //
424 // Move history from UpdateList to RouteState.
425 //
427  AdvertiseSList adv_slist;
428  SwapHistory(adv_slist);
429  rstate->SwapHistory(adv_slist);
430 }
431 
432 //
433 // Move history from UpdateList to RouteUpdate.
434 //
436  AdvertiseSList adv_slist;
437  SwapHistory(adv_slist);
438  rt_update->SwapHistory(adv_slist);
439 }
440 
441 //
442 // Find the history element with matching RibOutAttr.
443 //
444 const AdvertiseInfo *UpdateList::FindHistory(const RibOutAttr &roattr) const {
445  for (AdvertiseSList::List::const_iterator iter = history_->begin();
446  iter != history_->end(); ++iter) {
447  if (iter->roattr == roattr) return iter.operator->();
448  }
449  return NULL;
450 }
451 
452 //
453 // Add a RouteUpdate to this UpdateList. Sets up the association between
454 // the RouteUpdate and the UpdateList.
455 //
456 // Assumes that RouteUpdate has no history i.e. AdvertiseSList is empty.
457 //
459  list_.push_back(rt_update);
460  rt_update->set_update_list();
461 }
462 
463 //
464 // Remove a RouteUpdate from this UpdateList. Takes care of removing the
465 // linkage between the UpdateList and the RouteUpdate.
466 //
468  rt_update->clear_update_list();
469  list_.remove(rt_update);
470 }
471 
472 //
473 // Find the RouteUpdate for the given queue.
474 //
476  for (List::iterator iter = list_.begin(); iter != list_.end(); ++iter) {
477  if ((*iter)->queue_id() == queue_id)
478  return *iter;
479  }
480  return NULL;
481 }
482 
483 //
484 // Downgrade this UpdateList to a RouteUpdate if there's only 1 RouteUpdate
485 // on it. Takes care of removing the linkage between the UpdateList and the
486 // last RouteUpdate and moves history from the UpdateList to the RouteUpdate.
487 //
488 // Note that the caller is responsible for deleting the UpdateList.
489 //
490 // Returns the last/only RouteUpdate if successful, NULL otherwise.
491 //
493  assert(list_.size() != 0);
494 
495  if (list_.size() > 1)
496  return NULL;
497 
498  RouteUpdate *rt_update = list_.front();
499  rt_update->clear_update_list();
500  MoveHistory(rt_update);
501  return rt_update;
502 }
UpdateInfoSList updates_
Definition: bgp_update.h:248
BgpTable * table()
Definition: bgp_ribout.h:304
RouteUpdate(BgpRoute *route, int queue_id)
Definition: bgp_update.cc:22
RouteUpdate * MakeRouteUpdate()
Definition: bgp_update.cc:492
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
void SetHistory(AdvertiseSList &history)
Definition: bgp_update.cc:418
AdvertiseSList history_
Definition: bgp_update.h:247
void SetUpdateInfo(UpdateInfoSList &uinfo_slist)
Definition: bgp_update.cc:41
void Reset(const BitSet &rhs)
Definition: bitset.cc:470
void AddUpdate(RouteUpdate *rt_update)
Definition: bgp_update.cc:458
BgpRoute * route_
Definition: bgp_update.h:244
void clear_update_list()
Definition: bgp_update.h:225
bool OnUpdateList()
Definition: bgp_update.h:220
bool RemoveUpdateInfo(UpdateInfo *uinfo)
Definition: bgp_update.cc:60
bool Contains(const BitSet &rhs) const
Definition: bitset.cc:536
bool CompareUpdateInfo(const UpdateInfoSList &uinfo_slist) const
Definition: bgp_update.cc:116
void ClearHistory()
Definition: bgp_update.cc:289
bool empty() const
Definition: bitset.cc:165
RibPeerSet target
Definition: bgp_update.h:103
void swap(UpdateInfoSList &uinfo_slist)
Definition: bgp_update.h:154
void MoveHistory(RouteState *rstate)
Definition: bgp_update.cc:296
const AdvertiseInfo * FindHistory(const RibOutAttr &roattr) const
Definition: bgp_update.cc:305
UpdateInfo * FindUpdateInfo(const RibOutAttr &roattr)
Definition: bgp_update.cc:69
RibPeerSet bitset
Definition: bgp_ribout.h:172
List list_
Definition: bgp_update.h:295
void BuildNegativeUpdateInfo(UpdateInfoSList &uinfo_slist) const
Definition: bgp_update.cc:217
void SetHistory(AdvertiseSList &history)
Definition: bgp_update.cc:280
bool IsReachable() const
Definition: bgp_ribout.h:94
void ClearUpdateInfo()
Definition: bgp_update.cc:50
void ResetUpdateInfo(const RibPeerSet &peerset)
Definition: bgp_update.cc:93
void Set(const BitSet &rhs)
Definition: bitset.cc:462
AdvertiseSList & History()
Definition: bgp_update.h:274
void MoveHistory(RouteState *rstate)
Definition: bgp_update.cc:426
RouteUpdate * FindUpdate(int queue_id)
Definition: bgp_update.cc:475
bool FlagIsSet(Flag flag) const
Definition: bgp_update.h:240
void UpdateHistory(RibOut *ribout, const RibOutAttr *roattr, const RibPeerSet &bits)
Definition: bgp_update.cc:319
void SwapHistory(AdvertiseSList &history)
Definition: bgp_update.h:205
void TrimRedundantUpdateInfo(UpdateInfoSList &uinfo_slist) const
Definition: bgp_update.cc:248
bool IsAdvertised() const
Definition: bgp_update.cc:375
const UpdateInfo * FindUpdateInfo(const RibOutAttr &roattr) const
Definition: bgp_update.cc:13
void set_update_list()
Definition: bgp_update.h:224
void RemoveUpdate(RouteUpdate *rt_update)
Definition: bgp_update.cc:467
void SwapHistory(AdvertiseSList &history)
Definition: bgp_ribout.h:236
UpdateList * GetUpdateList(RibOut *ribout)
Definition: bgp_update.cc:405
DBTableBase::ListenerId listener_id() const
Definition: bgp_ribout.h:313
AdvertiseSList history_
Definition: bgp_update.h:294
void SwapHistory(AdvertiseSList &history)
Definition: bgp_update.h:278
UpdateList * MakeUpdateList()
Definition: bgp_update.cc:392
const AdvertiseInfo * FindHistory(const RibOutAttr &roattr) const
Definition: bgp_update.cc:444
void swap(AdvertiseSList &adv_slist)
Definition: bgp_ribout.h:208
RibOutAttr roattr
Definition: bgp_ribout.h:173
void MergeUpdateInfo(UpdateInfoSList &uinfo_slist)
Definition: bgp_update.cc:190