OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bgp_update_queue.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #ifndef SRC_BGP_BGP_UPDATE_QUEUE_H_
6 #define SRC_BGP_BGP_UPDATE_QUEUE_H_
7 
8 #include <list>
9 #include <set>
10 #include <vector>
11 
12 #include "bgp/bgp_update.h"
13 
14 //
15 // Comparator used to order UpdateInfos in the UpdateQueue set container.
16 // Looks at the BgpAttr, Timestamp and the associated RouteUpdate but not
17 // the Label, in order to achieve optimal packing of BGP updates. Ignore
18 // the BgpAttr in case of XMPP since each item is self contained - there's
19 // no notion of common attributes for all items in an update message.
20 //
21 // Compare the UpdateInfo pointers themselves as the final tie-breaker to
22 // handle the case where there are 2 UpdateInfos with the same BgpAttr in
23 // the same RouteUpdate. This can happen if the label (or the set for ecmp
24 // nexthops in case of an XMPP ribout) for a route changes between the Join
25 // operations for 2 different sets of IPeerUpdates.
26 //
28  bool operator()(const UpdateInfo &lhs, const UpdateInfo &rhs) const {
29  if (lhs.roattr.is_xmpp()) {
30  if (lhs.roattr.IsReachable() < rhs.roattr.IsReachable()) {
31  return true;
32  }
33  if (lhs.roattr.IsReachable() > rhs.roattr.IsReachable()) {
34  return false;
35  }
36  } else {
37  if (lhs.roattr.attr() < rhs.roattr.attr()) {
38  return true;
39  }
40  if (lhs.roattr.attr() > rhs.roattr.attr()) {
41  return false;
42  }
43  }
44  if (lhs.update->tstamp() < rhs.update->tstamp()) {
45  return true;
46  }
47  if (lhs.update->tstamp() > rhs.update->tstamp()) {
48  return false;
49  }
50  if (lhs.update < rhs.update) {
51  return true;
52  }
53  if (lhs.update > rhs.update) {
54  return false;
55  }
56  return (&lhs < &rhs);
57  }
58 };
59 
60 //
61 // This class implements an update queue for a RibOut. A RibUpdateMonitor
62 // contains a vector of pointers to UpdateQueue. The UpdateQueue instances
63 // are created and the corresponding pointers added to the vector from the
64 // RibOutUpdates constructor. The following relationships are relevant:
65 //
66 // RibOut -> RibOutUpdates (1:N)
67 // RibOutUpdates -> RibUpdateMonitor (1:1)
68 // RibUpdateMonitor -> UpdateQueue (1:N)
69 //
70 // Each UpdateQueue has an id which indicates whether it's a BULK queue or
71 // an UPDATE queue. A BULK queue is used for route refresh and also when
72 // a new peer comes up.
73 //
74 // An UpdateQueue contains an intrusive doubly linked list of UpdateEntry
75 // base elements, which could be either be UpdateMarker or RouteUpdate.
76 // This list is maintained in temporal order i.e. it's a FIFO.
77 //
78 // An UpdateQueue also has a intrusive set of UpdateInfo elements. These
79 // are ordered by attribute, timestamp and the corresponding prefix. This
80 // container is used when building updates since it allows us to traverse
81 // prefixes grouped by attributes. The relationship between a RouteUpdate
82 // and UpdateInfo is described elsewhere.
83 //
84 // An UpdateQueue also maintains a mapping from a peer's bit position to
85 // it's UpdateMarker. Note that it's possible for multiple peers to point
86 // to the same marker.
87 //
88 // A special UpdateMarker called the tail marker is used as an easy way to
89 // keep track of whether the list is empty. The tail marker is always the
90 // last marker in the list. Another way to think about this is that all
91 // the RouteUpdates after the tail marker have not been seen by any peer.
92 // This property is maintained by making sure that when the update marker
93 // for a peer (or set of peers) reaches the tail marker, it's merged into
94 // the tail marker.
95 //
96 class UpdateQueue {
97 public:
98  // Typedefs for the intrusive list.
99  typedef boost::intrusive::member_hook<
100  UpdateEntry,
101  boost::intrusive::list_member_hook<>,
104 
105  typedef boost::intrusive::list<UpdateEntry, UpdateEntryNode> UpdatesByOrder;
106 
107  // Typedefs for the intrusive set.
108  typedef boost::intrusive::member_hook<UpdateInfo,
109  boost::intrusive::set_member_hook<>,
112 
113  typedef boost::intrusive::set<UpdateInfo, UpdateSetNode,
114  boost::intrusive::compare<UpdateByAttrCmp>
116 
117  typedef std::vector<UpdateMarker *> MarkerList;
118 
119  UpdateQueue(const RibOut *ribout, int queue_id);
120  ~UpdateQueue();
121 
122  bool Enqueue(RouteUpdate *rt_update);
123  void Dequeue(RouteUpdate *rt_update);
124 
126  UpdateEntry *NextEntry(UpdateEntry *upentry);
127 
128  void AttrDequeue(UpdateInfo *current_uinfo);
129  UpdateInfo *AttrNext(UpdateInfo *current_uinfo);
130 
131  void AddMarker(UpdateMarker *marker, RouteUpdate *rt_update);
132  void MoveMarker(UpdateMarker *marker, RouteUpdate *rt_update);
133  void MarkerSplit(UpdateMarker *marker, const RibPeerSet &msplit);
134  void MarkerMerge(UpdateMarker *dst_marker, UpdateMarker *src_marker,
135  const RibPeerSet &bitset);
136  UpdateMarker *GetMarker(int bit);
137 
138  bool Join(int bit);
139  void Leave(int bit);
140 
141  bool CheckInvariants() const;
142 
144 
145  bool empty() const;
146  size_t size() const;
147  size_t marker_count() const;
148 
149 private:
150  friend class BgpExportTest;
151  friend class RibOutUpdatesTest;
152 
155  uint64_t tstamp_;
161 
163 };
164 
165 #endif // SRC_BGP_BGP_UPDATE_QUEUE_H_
friend class BgpExportTest
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
boost::intrusive::set_member_hook update_node
Definition: bgp_update.h:97
boost::intrusive::list< UpdateEntry, UpdateEntryNode > UpdatesByOrder
UpdateEntry * NextEntry(UpdateEntry *upentry)
void MarkerMerge(UpdateMarker *dst_marker, UpdateMarker *src_marker, const RibPeerSet &bitset)
void AddMarker(UpdateMarker *marker, RouteUpdate *rt_update)
UpdateMarker * tail_marker()
bool Enqueue(RouteUpdate *rt_update)
friend class RibOutUpdatesTest
void Leave(int bit)
bool Join(int bit)
size_t marker_count_
void Dequeue(RouteUpdate *rt_update)
UpdateMarker * GetMarker(int bit)
boost::intrusive::set< UpdateInfo, UpdateSetNode, boost::intrusive::compare< UpdateByAttrCmp > > UpdatesByAttr
bool operator()(const UpdateInfo &lhs, const UpdateInfo &rhs) const
bool CheckInvariants() const
uint64_t tstamp() const
Definition: bgp_update.h:232
std::vector< UpdateMarker * > MarkerList
RouteUpdate * update
Definition: bgp_update.h:106
bool IsReachable() const
Definition: bgp_ribout.h:94
void AttrDequeue(UpdateInfo *current_uinfo)
size_t marker_count() const
size_t size() const
void MoveMarker(UpdateMarker *marker, RouteUpdate *rt_update)
bool is_xmpp() const
Definition: bgp_ribout.h:123
bool empty() const
boost::intrusive::list_member_hook list_node
Definition: bgp_update.h:40
MarkerList markers_
UpdatesByAttr attr_set_
boost::intrusive::member_hook< UpdateEntry, boost::intrusive::list_member_hook<>,&UpdateEntry::list_node > UpdateEntryNode
UpdateMarker tail_marker_
boost::intrusive::member_hook< UpdateInfo, boost::intrusive::set_member_hook<>,&UpdateInfo::update_node > UpdateSetNode
UpdateInfo * AttrNext(UpdateInfo *current_uinfo)
DISALLOW_COPY_AND_ASSIGN(UpdateQueue)
uint64_t tstamp_
void MarkerSplit(UpdateMarker *marker, const RibPeerSet &msplit)