OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
path_resolver.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_ROUTING_INSTANCE_PATH_RESOLVER_H_
6 #define SRC_BGP_ROUTING_INSTANCE_PATH_RESOLVER_H_
7 
8 #include <boost/scoped_ptr.hpp>
9 #include <tbb/mutex.h>
10 #include <tbb/spin_rw_mutex.h>
11 
12 #include <map>
13 #include <set>
14 #include <string>
15 #include <vector>
16 #include <utility>
17 
18 #include "base/lifetime.h"
19 #include "base/util.h"
20 #include "base/address.h"
22 #include "db/db_entry.h"
23 #include "db/db_table.h"
24 
25 class BgpAttr;
26 class BgpPath;
27 class BgpRoute;
28 class BgpServer;
29 class BgpTable;
30 class DBEntryBase;
31 class DBTablePartBase;
32 class DeleteActor;
33 class IPeer;
35 class ResolverNexthop;
36 class ResolverPath;
37 class ResolverRouteState;
38 class RoutingInstance;
39 class ShowPathResolver;
40 class TaskTrigger;
41 
42 //
43 // This represents an instance of the resolver per BgpTable. A BgpTable that
44 // with BgpPaths that need resolution will have an instance of PathResolver.
45 //
46 // The [Start|Update|Stop]PathResolution APIs are invoked by PathResolution
47 // clients explicitly as required. They have to be invoked in context of the
48 // db::DBTable Task.
49 //
50 // The listener_id is used by ResolverPath to set ResolverRouteState on the
51 // BgpRoute for the BgpPaths in question. The PathResolver doesn't actually
52 // listen to notifications for routes in the BgpTable.
53 //
54 // The nexthop map keeps track of all ResolverNexthop for this instance. In
55 // addition, a given ResolverNexthop may be on the register/unregister list
56 // and the update list. Entries are added to the map and the lists from the
57 // db::DBTable Task. A mutex is used to serialize updates to the map and the
58 // lists. Note that there's no no concurrent access when entries are removed
59 // from the map and the lists, since the remove operations happen from Tasks
60 // that are mutually exclusive.
61 //
62 // The register/unregister list is processed in the context of bgp::Config
63 // Task. ResolverNexthops are added to this list when we need to add/remove
64 // or unregister them to/from the BgpConditionListener. This is done since
65 // the BgpConditionListener expects these operations to be made in context
66 // of bgp::Config Task.
67 //
68 // When a ResolverNexthop is removed the BgpConditionListener, it is added
69 // to the delete list. This is required because remove call is asynchronous.
70 // When BgpConditionListener invokes the remove request done callback, the
71 // ResolverNexthop is added to the register/unregister list again. It gets
72 // erased from the delete list and unregistered from BgpConditionListener
73 // after the list is processed again.
74 //
75 // The update list is processed in the context of bgp::ResolverNexthop Task.
76 // When an entry on this list is processed all it's dependent ResolverPaths
77 // are queued for re-evaluation in the PathResolverPartition.
78 //
79 // Concurrency Notes:
80 //
81 // Resolution APIs are invoked from db::DBTable Task.
82 // Updates to ResolverNexthop (via Match method) happen from db::DBTable Task.
83 // ResolverNexthop register/unregister list is processed in bgp::Config Task.
84 // ResolverNexthop update is processed in bgp::ResolverNexthop Task.
85 // ResolverPath update is processed in bgp::ResolverPath Task.
86 //
87 // bgp::Config is mutually exclusive with bgp::ResolverPath
88 // bgp::Config is mutually exclusive with bgp::ResolverNexthop
89 // db::DBTable is mutually exclusive with bgp::ResolverPath
90 // db::DBTable is mutually exclusive with bgp::ResolverNexthop
91 // bgp::ResolverPath is mutually exclusive with bgp::ResolverNexthop
92 //
93 class PathResolver {
94 public:
95  explicit PathResolver(BgpTable *table);
96  ~PathResolver();
97 
98  void StartPathResolution(BgpRoute *route, const BgpPath *path,
99  BgpTable *nh_table = NULL);
100  void StopPathResolution(int part_id, const BgpPath *path);
101 
104 
105  BgpTable *table() { return table_; }
106  Address::Family family() const;
109  bool IsDeleted() const;
110  void ManagedDelete();
111  bool MayDelete() const;
112  void RetryDelete();
115 
116  void FillShowInfo(ShowPathResolver *spr, bool summary) const;
117  static bool RoutePrefixMatch(const BgpRoute *route,
118  const IpAddress &address);
119 
120 private:
121  friend class PathResolverPartition;
122  friend class ResolverNexthop;
123  template <typename U> friend class PathResolverTest;
124 
125  class DeleteActor;
126  typedef std::pair<IpAddress, BgpTable *> ResolverNexthopKey;
127  typedef std::map<ResolverNexthopKey, ResolverNexthop *> ResolverNexthopMap;
128  typedef std::set<ResolverNexthop *> ResolverNexthopList;
129 
130  PathResolverPartition *GetPartition(int part_id);
131  PathResolverPartition *GetPartition(int part_id) const;
132 
134  void RemoveResolverNexthop(ResolverNexthop *rnexthop);
135  void UpdateResolverNexthop(ResolverNexthop *rnexthop);
137 
142 
143  bool RouteListener(DBTablePartBase *root, DBEntryBase *entry);
144 
145  size_t GetResolverNexthopMapSize() const;
146  size_t GetResolverNexthopDeleteListSize() const;
147 
150  size_t GetResolverNexthopRegUnregListSize() const;
151 
154  size_t GetResolverNexthopUpdateListSize() const;
155 
160  size_t GetResolverPathUpdateListSize() const;
161 
165  mutable tbb::mutex mutex_;
168  boost::scoped_ptr<TaskTrigger> nexthop_reg_unreg_trigger_;
170  boost::scoped_ptr<TaskTrigger> nexthop_update_trigger_;
172  std::vector<PathResolverPartition *> partitions_;
173 
174  boost::scoped_ptr<DeleteActor> deleter_;
176 
178 };
179 
180 //
181 // This represents one partition in the PathResolver. It keeps tracks of all
182 // the ResolverPaths for BgpRoutes in the partition. It has a map of BgpPath
183 // to ResolverPath.
184 //
185 // The update list contains ResolverPaths whose resolved BgpPath list need to
186 // be updated. Entries are added to the list as described in the comments for
187 // ResolverPath class. The list is processed in context of bgp::ResolverPath
188 // Task with the partition index as the Task instance id. This allows all the
189 // PathResolverPartitions to work concurrently.
190 
191 // Mutual exclusion of db::DBTable and bgp::ResolverPath Tasks ensures that
192 // it's safe to add/delete/update resolved BgpPaths from the bgp::ResolverPath
193 // Task. It also ensures that it's safe to access the BgpPaths of the nexthop
194 // BgpRoute from the bgp::ResolverPath Task. The only exception is where the
195 // BgpRoute itself is being modified by another bgp::ResolverPath Task. This
196 // is handled by using a read-write mutex in the ResolverRouteState.
197 //
199 public:
202 
203  void StartPathResolution(BgpRoute *route, const BgpPath *path,
204  BgpTable *nh_table);
205  void StopPathResolution(const BgpPath *path);
206 
207  void TriggerPathResolution(ResolverPath *rpath);
208  void DeferPathResolution(ResolverPath *rpath);
209 
210  int part_id() const { return part_id_; }
212  return resolver_->listener_id();
213  }
214  PathResolver *resolver() const { return resolver_; }
215  BgpTable *table() const { return resolver_->table(); }
217 
218 private:
219  friend class PathResolver;
220 
221  typedef std::map<const BgpPath *, ResolverPath *> PathToResolverPathMap;
222  typedef std::set<ResolverPath *> ResolverPathList;
223 
224  ResolverPath *CreateResolverPath(const BgpPath *path, BgpRoute *route,
225  ResolverNexthop *rnexthop);
226  ResolverPath *FindResolverPath(const BgpPath *path);
229 
234  size_t GetResolverPathUpdateListSize() const;
235 
236  int part_id_;
240  boost::scoped_ptr<TaskTrigger> rpath_update_trigger_;
241 
243 };
244 
245 //
246 // This is used to take a reference on a BgpRoute with at least one BgpPath
247 // that is being resolved by the PathResolver. Each ResolverPath for the
248 // BgpRoute in question has an intrusive pointer to the ResolverRouteState.
249 //
250 // The refcount doesn't need to be atomic because it's updated/accessed from
251 // exactly one DBPartition or PathResolverPartition.
252 //
253 // The rw_mutex is used to prevent a PathResolverPartition from modifying the
254 // associated BgpRoute while another PathResolverPartition is accessing the
255 // BgpRoute. This can happen when there's more than 1 levels of resolution in
256 // use i.e. a BgpRoute with resolved paths is itself being used to resolve a
257 // nexthop. Note that the two PathResolverPartitions could be in the same or
258 // different PathResolvers.
259 //
260 class ResolverRouteState : public DBState {
261 public:
262  ResolverRouteState(PathResolver *resolver, BgpRoute *route);
263  virtual ~ResolverRouteState();
264  tbb::spin_rw_mutex &rw_mutex() { return rw_mutex_; }
265 
266 private:
267  friend void intrusive_ptr_add_ref(ResolverRouteState *state);
268  friend void intrusive_ptr_release(ResolverRouteState *state);
269 
272  tbb::spin_rw_mutex rw_mutex_;
273  uint32_t refcount_;
274 };
275 
277  state->refcount_++;
278 }
279 
281  assert(state->refcount_ != 0);
282  if (--state->refcount_ == 0)
283  delete state;
284 }
285 
286 typedef boost::intrusive_ptr<ResolverRouteState> ResolverRouteStatePtr;
287 
288 //
289 // This represents a BgpPath for which resolution has been requested. It's
290 // inserted into a map keyed by BgpPath pointer in a PathResolverPartition.
291 //
292 // If the client requests an update the ResolverPath is inserted into an
293 // update list in the PathResolverPartition. Similarly, if there's a change
294 // in the underlying BgpRoute for the ResolverNexthop, all of the impacted
295 // ResolverPaths are added to the update list in the PathResolverPartition.
296 // The latter happens when the ResolverNexthop update list in PathResolver
297 // is processed.
298 //
299 // A ResolverPath keeps a list of resolved BgpPaths it has added. A resolved
300 // path is added for each ecmp eligible BgpPath of the BgpRoute that tracks
301 // the nexthop of ResolverPath. The nexthop is represented by ResolverNexthop.
302 //
303 // The resolved paths of the ResolverPath are reconciled when the update list
304 // in the PathResolverPartition is processed. New resolved paths may get added,
305 // existing resolved paths may get updated and stale resolved paths could get
306 // deleted.
307 //
308 // The attributes of a resolved BgpPath are a combination of the attributes
309 // of the original BgpPath and the BgpPath of the nexthop being tracked. As a
310 // general rule, forwarding information (e.g. nexthop address, label, tunnel
311 // encapsulation) is obtained from tracking BgpPath while routing information
312 // (e.g. communities, as path, local pref) is obtained from original BgpPath.
313 //
315 public:
318  ~ResolverPath();
319 
320  bool UpdateResolvedPaths();
321 
323  BgpRoute *route() const { return route_; }
324  const ResolverNexthop *rnexthop() const { return rnexthop_; }
325  void clear_path() { path_ = NULL; }
326  size_t resolved_path_count() const { return resolved_path_list_.size(); }
327 
328 private:
329  typedef std::set<BgpPath *> ResolvedPathList;
330 
331  void AddResolvedPath(ResolvedPathList::const_iterator it);
332  void DeleteResolvedPath(ResolvedPathList::const_iterator it);
333  BgpPath *LocateResolvedPath(const IPeer *peer, uint32_t path_id,
334  const BgpAttr *attr, uint32_t label, bool is_replicated = false);
335 
337  const BgpPath *path_;
342 
344 };
345 
346 //
347 // This represents a nexthop IP address to be resolved using the specified
348 // BgpTable. This need not be the BgpTable associated with the PathResolver.
349 // Each ResolverNexthop is inserted into a map keyed by ResolverNexthopKey
350 // in the PathResolver.
351 //
352 // A ResolverNexthop is created when resolution is requested for the first
353 // BgpPath with the associated IP address. At creation, the ResolverNexthop
354 // is added to the PathResolver's registration/unregistration list so that
355 // the ConditionMatch can be added to the BgpConditionListener. This list
356 // gets processed in the context of the bgp::Config Task.
357 //
358 // A ResolverNexthop maintains a vector of ResolverPathList, one entry per
359 // partition. Each ResolverPathList is a set of ResolverPaths that use the
360 // ResolverNexthop in question. When there's a change to the BgpRoute for
361 // the IP address being tracked, the ResolverNexthop is added to the update
362 // list in the PathResolver. The PathResolver processes the entries in this
363 // list in the context of the bgp::ResolverNexthop Task. The action is to
364 // trigger re-evaluation of all ResolverPaths that use the ResolverNexthop.
365 //
366 // When the last ResolverPath in a partition using a ResolverNexthop gets
367 // removed, the ResolverNexthop is added to the registration/unregistration
368 // in the PathResolver. The list is processed in the bgp::Config Task. If
369 // the ResolverNexthop is empty i.e. not being used by any ResolverPaths,
370 // the ConditionMatch is removed from the BgpConditionListener and is also
371 // erased from the map in the PathResolver. When the remove done callback
372 // gets invoked from BgpConditionListener, the ResolverNexthop is added to
373 // the register/unregistration list again. It's finally unregistered when
374 // the list is processed again.
375 //
376 // The registered flag keeps track of whether the ResolverNexthop has been
377 // registered with the BgpConditionListener. It's needed to handle corner
378 // cases where a ResolverNexthop gets added to registration/unregistration
379 // list but all ResolverPaths using it get removed before the ResolverNexthop
380 // has been registered.
381 //
382 // A set of pointers to all BgpRoutes that match IpAddress is maintained in a
383 // set so that the PathResolverPartition can access their BgpPaths. A reference
384 // to each BgpRoute in the set is kept by setting ConditionMatchState for the
385 // route. This set is sorted in descending order based on the prefix length so
386 // that longest matching route is always positioned at the beginning of the set.
387 // All operations to the set are protected by a mutex.
388 //
389 // A delete reference to BgpTable is maintained to ensure that the BgpTable
390 // does not get destroyed while there are ResolverNexthops tracking it.
391 //
393 public:
395  virtual ~ResolverNexthop();
396 
397  virtual std::string ToString() const;
398  virtual bool Match(BgpServer *server, BgpTable *table, BgpRoute *route,
399  bool deleted);
400  void AddResolverPath(int part_id, ResolverPath *rpath);
401  void RemoveResolverPath(int part_id, ResolverPath *rpath);
403 
404  void TriggerAllResolverPaths() const;
405 
406  void ManagedDelete() { }
407 
408  IpAddress address() const { return address_; }
409  BgpTable *table() const { return table_; }
410  bool InsertRoute(BgpRoute *route);
411  bool RemoveRoute(BgpRoute *route);
412  const BgpRoute *GetRoute() const;
413  BgpRoute *GetRoute();
414  bool empty() const;
415  bool registered() const { return registered_; }
416  void set_registered() { registered_ = true; }
417 
418 protected:
420  bool operator()(const BgpRoute *lhs, const BgpRoute *rhs) const;
421  };
422  typedef std::set<BgpRoute *, ResolverRouteCompare> ResolverRouteSet;
423 
425 
426 private:
427  typedef std::set<ResolverPath *> ResolverPathList;
428 
433  mutable tbb::mutex routes_mutex_;
434  std::vector<ResolverPathList> rpath_lists_;
436 
438 };
439 
440 #endif // SRC_BGP_ROUTING_INSTANCE_PATH_RESOLVER_H_
ResolverNexthop * LocateResolverNexthop(IpAddress address, BgpTable *table)
bool RouteListener(DBTablePartBase *root, DBEntryBase *entry)
void PauseResolverPathUpdateProcessing()
int intrusive_ptr_add_ref(const AsPath *cpath)
Definition: bgp_aspath.h:147
bool MayDelete() const
boost::scoped_ptr< DeleteActor > deleter_
PathResolver * resolver_
const ResolverNexthop * rnexthop() const
BgpTable * table()
void FillShowInfo(ShowPathResolver *spr, bool summary) const
void ResumeResolverPathUpdateProcessing()
ResolverNexthopList nexthop_update_list_
bool nexthop_longest_match_
LifetimeRef< PathResolver > table_delete_ref_
void clear_path()
ResolverPath * CreateResolverPath(const BgpPath *path, BgpRoute *route, ResolverNexthop *rnexthop)
std::set< BgpRoute *, ResolverRouteCompare > ResolverRouteSet
void DisableResolverPathUpdateProcessing()
virtual bool Match(BgpServer *server, BgpTable *table, BgpRoute *route, bool deleted)
bool ProcessResolverNexthopRegUnregList()
tbb::mutex mutex_
std::map< const BgpPath *, ResolverPath * > PathToResolverPathMap
tbb::mutex routes_mutex_
ResolvedPathList resolved_path_list_
LifetimeRef< ResolverNexthop > table_delete_ref_
DISALLOW_COPY_AND_ASSIGN(ResolverPath)
void TriggerPathResolution(ResolverPath *rpath)
Family
Definition: address.h:24
ResolverRouteSet routes_
boost::asio::ip::address IpAddress
Definition: address.h:13
PathResolver(BgpTable *table)
size_t GetResolverPathUpdateListSize() const
DBTablePartBase * table_partition()
virtual ~ResolverNexthop()
int ListenerId
Definition: db_table.h:62
PathResolverPartition(int part_id, PathResolver *resolver)
ResolverNexthop * rnexthop_
void StartPathResolution(BgpRoute *route, const BgpPath *path, BgpTable *nh_table=NULL)
const BgpRoute * GetRoute() const
ResolverNexthopList nexthop_reg_unreg_list_
tbb::spin_rw_mutex rw_mutex_
BgpTable * table() const
Definition: ipeer.h:186
PathToResolverPathMap rpath_map_
void DeferPathResolution(ResolverPath *rpath)
friend void intrusive_ptr_add_ref(ResolverRouteState *state)
void DisableResolverNexthopUpdateProcessing()
bool ProcessResolverNexthopUpdateList()
PathResolver * resolver_
void RetryDelete()
ResolverPath * RemoveResolverPath(const BgpPath *path)
std::map< ResolverNexthopKey, ResolverNexthop * > ResolverNexthopMap
ResolverNexthop(PathResolver *resolver, IpAddress address, BgpTable *table)
bool empty() const
BgpTable * table() const
void EnableResolverNexthopUpdateProcessing()
size_t resolved_path_count() const
void StopPathResolution(const BgpPath *path)
void RegisterUnregisterResolverNexthop(ResolverNexthop *rnexthop)
size_t GetResolverNexthopDeleteListSize() const
ResolverRouteState * LocateResolverRouteState(BgpRoute *route)
size_t GetResolverNexthopUpdateListSize() const
bool ProcessResolverPathUpdateList()
DBTableBase::ListenerId listener_id_
BgpRoute * route_
boost::intrusive_ptr< ResolverRouteState > ResolverRouteStatePtr
friend void intrusive_ptr_release(ResolverRouteState *state)
Address::Family family() const
BgpPath * LocateResolvedPath(const IPeer *peer, uint32_t path_id, const BgpAttr *attr, uint32_t label, bool is_replicated=false)
void UpdateResolverNexthop(ResolverNexthop *rnexthop)
size_t GetResolverPathUpdateListSize() const
PathResolver * resolver_
BgpRoute * route() const
DBTableBase::ListenerId listener_id() const
void RemoveResolverNexthop(ResolverNexthop *rnexthop)
boost::scoped_ptr< TaskTrigger > nexthop_reg_unreg_trigger_
void EnableResolverPathUpdateProcessing()
std::pair< IpAddress, BgpTable * > ResolverNexthopKey
void DisableResolverNexthopRegUnregProcessing()
ResolverRouteStatePtr state_
friend class PathResolverTest
void RemoveResolverPath(int part_id, ResolverPath *rpath)
DISALLOW_COPY_AND_ASSIGN(PathResolverPartition)
void UnregisterResolverNexthopDone(BgpTable *table, ConditionMatch *match)
bool InsertRoute(BgpRoute *route)
void TriggerAllResolverPaths() const
ResolverRouteState * GetResolverRouteState()
std::set< ResolverPath * > ResolverPathList
std::set< ResolverPath * > ResolverPathList
BgpTable * table_
bool ProcessResolverNexthopRegUnreg(ResolverNexthop *rnexthop)
virtual std::string ToString() const
void DisableResolverPathUpdateProcessing()
void DeleteResolvedPath(ResolvedPathList::const_iterator it)
ResolverPath(PathResolverPartition *partition, const BgpPath *path, BgpRoute *route, ResolverNexthop *rnexthop)
ResolverNexthopMap nexthop_map_
void StartPathResolution(BgpRoute *route, const BgpPath *path, BgpTable *nh_table)
bool operator()(const BgpRoute *lhs, const BgpRoute *rhs) const
BgpTable * table_
boost::scoped_ptr< TaskTrigger > rpath_update_trigger_
std::vector< PathResolverPartition * > partitions_
void ResumeResolverPathUpdateProcessing()
void StopPathResolution(int part_id, const BgpPath *path)
bool registered() const
IpAddress address() const
void set_nexthop_longest_match(bool flag)
const BgpPath * path_
void intrusive_ptr_release(const AsPath *cpath)
Definition: bgp_aspath.h:155
void AddResolverPath(int part_id, ResolverPath *rpath)
void EnableResolverNexthopRegUnregProcessing()
static bool RoutePrefixMatch(const BgpRoute *route, const IpAddress &address)
size_t GetResolverNexthopRegUnregListSize() const
void PauseResolverPathUpdateProcessing()
ResolverPathList rpath_update_list_
IpAddress address_
ResolverNexthopList nexthop_delete_list_
std::vector< ResolverPathList > rpath_lists_
std::set< ResolverNexthop * > ResolverNexthopList
PathResolverPartition * GetPartition(int part_id)
boost::scoped_ptr< TaskTrigger > nexthop_update_trigger_
tbb::spin_rw_mutex & rw_mutex()
PathResolver * resolver() const
ResolverRouteState(PathResolver *resolver, BgpRoute *route)
DISALLOW_COPY_AND_ASSIGN(ResolverNexthop)
PathResolverPartition * partition_
DBTableBase::ListenerId listener_id() const
bool IsDeleted() const
void ManagedDelete()
BgpConditionListener * get_condition_listener(Address::Family family)
bool nexthop_longest_match() const
ResolverRouteState * FindResolverRouteState(BgpRoute *route)
std::set< BgpPath * > ResolvedPathList
void AddResolvedPath(ResolvedPathList::const_iterator it)
void EnableResolverPathUpdateProcessing()
ResolverPath * FindResolverPath(const BgpPath *path)
PathResolverPartition * partition() const
bool RemoveRoute(BgpRoute *route)
size_t GetResolverNexthopMapSize() const
DISALLOW_COPY_AND_ASSIGN(PathResolver)
bool UpdateResolvedPaths()
virtual ~ResolverRouteState()