OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bgp_update_queue.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_queue.h"
6 
7 #include <boost/tuple/tuple.hpp>
8 
9 using boost::tie;
10 
11 //
12 // Initialize the UpdateQueue and add the tail marker to the FIFO.
13 //
14 UpdateQueue::UpdateQueue(const RibOut *ribout, int queue_id)
15  : queue_id_(queue_id),
16  encoding_is_xmpp_(ribout->IsEncodingXmpp()),
17  tstamp_(0),
18  marker_count_(0) {
19  queue_.push_back(tail_marker_);
20 }
21 
22 //
23 // Destroy the UpdateQueue after removing the tail marker from the FIFO.
24 //
26  queue_.erase(queue_.iterator_to(tail_marker_));
27  assert(queue_.empty());
28  assert(attr_set_.empty());
29 }
30 
31 //
32 // Enqueue the specified RouteUpdate to the UpdateQueue. Updates both the
33 // FIFO and the set container.
34 //
35 // Return true if the UpdateQueue had no RouteUpdates after the tail marker.
36 //
38  rt_update->set_tstamp(++tstamp_);
39 
40  // Insert at the end of the FIFO. Remember if the FIFO previously had
41  // no RouteUpdates after the tail marker.
42  UpdateEntry *tail_upentry = &(queue_.back());
43  bool need_tail_dequeue = (tail_upentry == &tail_marker_);
44  queue_.push_back(*rt_update);
45 
46  // Go through the UpdateInfo list and insert each element into the set
47  // container for the UpdateQueue. Also set up the back pointer to the
48  // RouteUpdate.
49  UpdateInfoSList &uinfo_slist = rt_update->Updates();
50  for (UpdateInfoSList::List::iterator iter = uinfo_slist->begin();
51  iter != uinfo_slist->end(); ++iter) {
52  iter->update = rt_update;
53  UpdatesByAttr::iterator set_iter;
54  bool result;
55  tie(set_iter, result) = attr_set_.insert(*iter);
56  assert(result);
57  }
58  return need_tail_dequeue;
59 }
60 
61 //
62 // Dequeue the specified RouteUpdate from the UpdateQueue. All UpdateInfo
63 // elements for the RouteUpdate are removed from the set container.
64 //
66  queue_.erase(queue_.iterator_to(*rt_update));
67  UpdateInfoSList &uinfo_slist = rt_update->Updates();
68  for (UpdateInfoSList::List::iterator iter = uinfo_slist->begin();
69  iter != uinfo_slist->end(); ++iter) {
70  attr_set_.erase(attr_set_.iterator_to(*iter));
71  }
72 }
73 
74 //
75 // Return the next RouteUpdate after the given UpdateEntry on the UpdateQueue.
76 // Traverses the FIFO and skips over MARKERs and other element types to find
77 // the next RouteUpdate.
78 //
79 // Return NULL if there's no such RouteUpdate on the FIFO.
80 //
82  UpdatesByOrder::iterator iter = queue_.iterator_to(*current_upentry);
83  while (++iter != queue_.end()) {
84  UpdateEntry *upentry = iter.operator->();
85  if (upentry->IsUpdate()) {
86  return static_cast<RouteUpdate *>(upentry);
87  }
88  }
89  return NULL;
90 }
91 
92 //
93 // Return the next UpdateEntry on the UpdateQueue after the one specified.
94 // Traverses the FIFO and returns the next UpdateEntry, irrespective of the
95 // type.
96 //
97 // Return NULL if there's no such UpdateEntry on the FIFO.
98 //
100  UpdatesByOrder::iterator iter = queue_.iterator_to(*current_upentry);
101  if (++iter == queue_.end()) {
102  return NULL;
103  }
104  return iter.operator->();
105 }
106 
107 //
108 // Dequeue the specified UpdateInfo from the set container.
109 //
110 void UpdateQueue::AttrDequeue(UpdateInfo *current_uinfo) {
111  attr_set_.erase(attr_set_.iterator_to(*current_uinfo));
112 }
113 
114 //
115 // Return the next UpdateInfo after the one provided. This traverses the set
116 // container and returns the next one if it has the same BgpAttr. Note that
117 // we must not consider the label in order to ensure optimal packing.
118 //
119 // Returns NULL if there are no more updates with the same BgpAttr. This is
120 // relaxed if the RibOut encoding is XMPP since it's possible to pack items
121 // with different BgpAttrs in the same message given that each item is self
122 // contained.
123 //
124 // Also return NULL if the next UpdateInfo is for the same RouteUpdate. This
125 // can happen in corner cases where the label (or the set for ecmp nexthops
126 // in case of an XMPP ribout) for a route changes between Join operations for
127 // 2 different sets of IPeerUpdates. Returning such an UpdateInfo results in
128 // data corruption.
129 //
131  UpdatesByAttr::iterator iter = attr_set_.iterator_to(*current_uinfo);
132  ++iter;
133  if (iter == attr_set_.end()) {
134  return NULL;
135  }
136  UpdateInfo *next_uinfo = iter.operator->();
137  if (next_uinfo->update == current_uinfo->update) {
138  return NULL;
139  }
140  if (encoding_is_xmpp_) {
141  const RibOutAttr &next_roattr = next_uinfo->roattr;
142  const RibOutAttr &current_roattr = current_uinfo->roattr;
143  if (next_roattr.IsReachable() == current_roattr.IsReachable()) {
144  return next_uinfo;
145  } else {
146  return NULL;
147  }
148  }
149  if (next_uinfo->roattr.attr() == current_uinfo->roattr.attr()) {
150  return next_uinfo;
151  }
152  return NULL;
153 }
154 
155 //
156 // Add the provided UpdateMarker after a specific RouteUpdate. Also update
157 // the MarkerList so that all peers in the provided UpdateMarker now point
158 // to it.
159 //
161  assert(!marker->members.empty());
162  marker_count_++;
163  queue_.insert(++queue_.iterator_to(*rt_update), *marker);
164 
165  for (size_t i = marker->members.find_first();
166  i != BitSet::npos; i = marker->members.find_next(i)) {
167  assert(markers_[i]);
168  markers_[i] = marker;
169  }
170 }
171 
172 //
173 // Move the provided UpdateMarker so that it's after the RouteUpdate. Since
174 // the entire UpdateMarker itself is being moved, there's no need to update
175 // the MarkerList.
176 //
177 // If the UpdateMarker is the tail marker, skip over all markers after the
178 // RouteUpdate till we hit the next RouteUpdate or the end of the queue.
179 // This is needed for the case where some peers get blocked after sending
180 // the last RouteUpdate in the queue. In that scenario, the marker for the
181 // blocked peers is inserted after the RouteUpdate and we then try to move
182 // the tail marker after the RouteUpdate.
183 //
185  queue_.erase(queue_.iterator_to(*marker));
186 
187  UpdatesByOrder::iterator iter = queue_.iterator_to(*rt_update);
188  if (marker == &tail_marker_) {
189  for (iter++; iter != queue_.end() && iter->IsMarker(); iter++) {
190  }
191  queue_.insert(iter, *marker);
192  } else {
193  queue_.insert(++iter, *marker);
194  }
195 }
196 
197 //
198 // Split the specified UpdateMarker based on the RibPeerSet. A new marker is
199 // created for the peers in the RibPeerSet and is inserted immediately before
200 // the existing marker. The bits corresponding to the RibPeerSet being split
201 // are reset in the existing marker.
202 //
203 // The MarkerList is updated so that all the peers in in the RibPeerSet point
204 // to the new marker.
205 //
206 void UpdateQueue::MarkerSplit(UpdateMarker *marker, const RibPeerSet &msplit) {
207  assert(!msplit.empty());
208  UpdateMarker *split_marker = new UpdateMarker();
209  split_marker->members = msplit;
210 
211  marker->members.Reset(msplit);
212  assert(!marker->members.empty());
213  UpdatesByOrder::iterator mpos = queue_.iterator_to(*marker);
214  queue_.insert(mpos, *split_marker);
215  marker_count_++;
216 
217  for (size_t i = msplit.find_first();
218  i != BitSet::npos; i = msplit.find_next(i)) {
219  assert(markers_[i]);
220  markers_[i] = split_marker;
221  }
222 }
223 
224 //
225 // Merge the peers corresponding to the RibPeerSet from the src UpdateMarker
226 // to the dst. The bits corresponding to the RibPeerSet being merged into the
227 // dst are reset in the src marker. If the src UpdateMarker has no more peers,
228 // as a result, it is removed from the FIFO and destroyed.
229 //
231  UpdateMarker *src_marker, const RibPeerSet &bitset) {
232  assert(!bitset.empty());
233 
234  // Set the bits in dst and update the MarkerList. Be sure to set the dst
235  // before we reset the src since bitset maybe a reference to src->members.
236  dst_marker->members.Set(bitset);
237  for (size_t i = bitset.find_first();
238  i != BitSet::npos; i = bitset.find_next(i)) {
239  assert(markers_[i]);
240  markers_[i] = dst_marker;
241  }
242 
243  // Reset the bits in the src and get rid of it in case it's now empty.
244  src_marker->members.Reset(bitset);
245  if (src_marker->members.empty()) {
246  queue_.erase(queue_.iterator_to(*src_marker));
247  assert(src_marker != &tail_marker_);
248  delete src_marker;
249  marker_count_--;
250  }
251 }
252 
253 //
254 // Return the UpdateMarker for the peer specified by the bit position.
255 //
257  assert(markers_[bit]);
258  return markers_[bit];
259 }
260 
261 //
262 // Join a new peer, as represented by it's bit index, to the UpdateQueue.
263 // Since it's a new peer, it starts out at the tail marker. Also add the
264 // peer's bit index and the tail marker pair to the MarkerList, growing
265 // the MarkerList if necessary.
266 //
267 // Return true if the tail marker is not the last entry in the queue. The
268 // caller should trigger a tail dequeue for the RibOut if so to take care
269 // of the possibility that all peers in the tail marker are blocked. Note
270 // that a tail dequeue may already be pending in the BgpUpdateSender, but
271 // an extra one is harmless.
272 //
273 bool UpdateQueue::Join(int bit) {
274  UpdateMarker *marker = &tail_marker_;
275  marker->members.set(bit);
276  if (markers_.size() < (size_t)(bit + 1))
277  markers_.resize(bit + 1, NULL);
278  assert(!markers_[bit]);
279  markers_[bit] = marker;
280  return (&tail_marker_ != &queue_.back());
281 }
282 
283 //
284 // Leave a peer, as represented by it's bit index, from the UpdateQueue.
285 // Find the current marker for the peer and clear the peer bit's entry in
286 // the MarkerList. Don't bother shrinking the MarkerList - the entry can
287 // be reused by a subsequent Join.
288 // Reset the peer's bit in the marker and get rid of the marker itself if
289 // it's now empty.
290 //
291 void UpdateQueue::Leave(int bit) {
292  UpdateMarker *marker = markers_[bit];
293  markers_[bit] = NULL;
294  assert(marker);
295  marker->members.reset(bit);
296  if (marker != &tail_marker_ && marker->members.empty()) {
297  queue_.erase(queue_.iterator_to(*marker));
298  delete marker;
299  }
300 }
301 
303  for (size_t idx = 0; idx < markers_.size(); ++idx) {
304  UpdateMarker *marker = markers_[idx];
305  if (!marker)
306  continue;
307  CHECK_INVARIANT(marker->members.test(idx));
308  }
309  return true;
310 }
311 
312 //
313 // Return true if the UpdateQueue is empty. It's considered empty if there
314 // are as no UpdateInfo elements in the set container. We don't look at the
315 // FIFO since that may still have the tail marker on it.
316 //
317 bool UpdateQueue::empty() const {
318  return attr_set_.empty();
319 }
320 
321 size_t UpdateQueue::size() const {
322  return attr_set_.size();
323 }
324 
326  return marker_count_;
327 }
UpdatesByOrder queue_
UpdateQueue(const RibOut *ribout, int queue_id)
RouteUpdate * NextUpdate(UpdateEntry *upentry)
RibOutAttr roattr
Definition: bgp_update.h:100
const BgpAttr * attr() const
Definition: bgp_ribout.h:97
bool test(size_t pos) const
Definition: bitset.cc:146
BitSet & reset(size_t pos)
Definition: bitset.cc:136
void Reset(const BitSet &rhs)
Definition: bitset.cc:470
UpdateEntry * NextEntry(UpdateEntry *upentry)
void MarkerMerge(UpdateMarker *dst_marker, UpdateMarker *src_marker, const RibPeerSet &bitset)
RibPeerSet members
Definition: bgp_update.h:55
void AddMarker(UpdateMarker *marker, RouteUpdate *rt_update)
bool empty() const
Definition: bitset.cc:165
bool Enqueue(RouteUpdate *rt_update)
#define CHECK_INVARIANT(Cond)
Definition: util.h:29
void Leave(int bit)
bool Join(int bit)
size_t marker_count_
void Dequeue(RouteUpdate *rt_update)
UpdateMarker * GetMarker(int bit)
static const size_t npos
Definition: bitset.h:19
bool CheckInvariants() const
bool IsUpdate()
Definition: bgp_update.h:37
RouteUpdate * update
Definition: bgp_update.h:106
bool IsReachable() const
Definition: bgp_ribout.h:94
void Set(const BitSet &rhs)
Definition: bitset.cc:462
void AttrDequeue(UpdateInfo *current_uinfo)
size_t marker_count() const
BitSet & set(size_t pos)
Definition: bitset.cc:125
size_t size() const
size_t find_first() const
Definition: bitset.cc:242
void MoveMarker(UpdateMarker *marker, RouteUpdate *rt_update)
bool empty() const
size_t find_next(size_t pos) const
Definition: bitset.cc:255
MarkerList markers_
UpdatesByAttr attr_set_
void set_tstamp(uint64_t tstamp)
Definition: bgp_update.h:233
UpdateMarker tail_marker_
UpdateInfo * AttrNext(UpdateInfo *current_uinfo)
uint64_t tstamp_
void MarkerSplit(UpdateMarker *marker, const RibPeerSet &msplit)
UpdateInfoSList & Updates()
Definition: bgp_update.h:214