OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
agent_route_walker.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 #include <assert.h>
5 #include <cmn/agent_cmn.h>
6 #include <route/route.h>
7 #include <vnc_cfg_types.h>
8 #include <agent_types.h>
9 #include <cmn/agent_db.h>
11 #include <oper/vrf.h>
12 #include <oper/agent_route.h>
13 #include <sandesh/sandesh.h>
14 #include <sandesh/sandesh_types.h>
15 #include <sandesh/sandesh_trace.h>
16 #include <sandesh/common/vns_constants.h>
17 
18 using namespace std;
19 
21  AGENT_DBWALK_TRACE_BUF, 1000));
22 
24 }
25 
26 static void
28  RouteWalkerDBState *state) {
29  for (uint8_t table_type = Agent::ROUTE_TABLE_START;
30  table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
31  it->second[table_type] = DBTable::DBTableWalkRef();
32  }
33 }
34 
36  walk_ref_list_(), marked_for_deletion_(false) {
38  boost::bind(&AgentRouteWalkerManager::VrfNotify, this,
39  _1, _2));
40 }
41 
43  //Since walker ref list is going off, mark all walkers to have NULL
44  //managers.
45  //TODO
46 }
47 
49  assert(std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker)
50  != walk_ref_list_.end());
51  walker->ReleaseVrfWalkReference();
52 }
53 
54 void
56  VrfEntry *vrf) {
58  state->walker_ref_map_.begin();
59  it != state->walker_ref_map_.end(); it++) {
61  }
62 }
63 
64 //Handles VRF addition and deletion.
65 //Releases all vrf walker reference and route table walker references.
67  DBEntryBase *e) {
68  VrfEntry *vrf = static_cast<VrfEntry *>(e);
69  RouteWalkerDBState *state =
70  static_cast<RouteWalkerDBState *>(vrf->GetState(partition->parent(),
72  if (vrf->IsDeleted()) {
73  if (!state)
74  return;
75  RemoveWalkReferencesInVrf(state, vrf);
76  vrf->ClearState(partition->parent(), vrf_listener_id_);
77  delete state;
78  return;
79  }
80 
81  if (!state) {
82  CreateState(vrf);
83  }
84 }
85 
88  vrf->SetState(vrf->get_table(), vrf_listener_id_, state);
89  return state;
90 }
91 
93  walk_ref_list_.erase(std::find(walk_ref_list_.begin(), walk_ref_list_.end(),
94  walker));
95 }
96 
98  marked_for_deletion_ = true;
99  TryUnregister();
100 }
101 
103  if (walk_ref_list_.size() != 0)
104  return;
106 }
107 
109 (AgentRouteWalkerPtr walker) const {
110  assert (std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker) !=
111  walk_ref_list_.end());
112 }
113 
116  return;
117  walk_ref_list_.insert(walker);
118  walker->set_mgr(this);
119 }
120 
121 AgentRouteWalker::AgentRouteWalker(const std::string &name,
122  Agent *agent) : agent_(agent), name_(name),
123  route_walk_count_(), walk_done_cb_(), route_walk_done_for_vrf_cb_(),
124  mgr_(NULL), deregister_done_(false) {
127  boost::bind(&AgentRouteWalker::VrfWalkNotify,
128  this, _1, _2),
130  this, _2));
132  boost::bind(&AgentRouteWalker::Deregister, this,
133  _1, _2),
135  this));
136  refcount_ = 0;
137 }
138 
140  assert(vrf_walk_ref_.get() == NULL);
141  assert(delete_walk_ref_.get() == NULL);
142 }
143 
146  RouteWalkerDBState *state =
147  static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
148  mgr_->vrf_listener_id()));
149  if (vrf->IsDeleted())
150  return state;
151 
152  if (!state)
153  state = mgr_->CreateState(vrf);
154 
155  return state;
156 }
157 
160  RouteWalkerDBState *state,
161  AgentRouteTable *table) {
162  assert(state != NULL);
163  Agent::RouteTableType table_type = table->GetTableType();
164  AgentRouteWalkerPtr walker_ptr = AgentRouteWalkerPtr(this);
165 
166  // Search for walker and if found then check if table type has a reference
167  // allocated or not. If allocated return the same.
169  state->walker_ref_map_.find(walker_ptr);
170  DBTable::DBTableWalkRef route_table_walk_ref = DBTable::DBTableWalkRef();
171 
172  // Walker was not found in map, add it
173  if (it == state->walker_ref_map_.end()) {
174  RouteWalkerDBState::RouteWalkRef route_walk_ref;
175  std::pair<RouteWalkerDBState::AgentRouteWalkerRefMapIter, bool> ret;
176  ret = state->walker_ref_map_.insert(std::make_pair(walker_ptr, route_walk_ref));
177  if (ret.second == false) {
178  AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
179  "LocateRouteTableWalkRef walker add failed.",
180  "", "");
181  return DBTable::DBTableWalkRef();
182  }
183  it = ret.first;
184  }
185 
186  // table type had no reference allocated, so allocate it.
187  if (it->second[table_type] == DBTable::DBTableWalkRef()) {
188  it->second[table_type] = table->AllocWalker(
190  this, _1, _2),
192  this, _2, walker_ptr));
193  }
194  return it->second[table_type];
195 }
196 
197 /*
198  * Starts walk for all VRF.
199  */
202  if (vrf_walk_ref_->in_progress() == false)
205  //TODO trace
206  AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_, "StartVrfWalk",
207  "", "");
208 }
209 
212  VrfEntry *vrf = table->vrf_entry();
214  return LocateRouteTableWalkRef(vrf, state, table);
215 }
216 
218  DBTable::DBTableWalkRef &route_table_walk_ref) {
219  if (route_table_walk_ref->in_progress() == false) {
222  }
223  table->WalkAgain(route_table_walk_ref);
224 }
225 
226 /*
227  * Starts route walk for given VRF.
228  */
231  AgentRouteTable *table = NULL;
232 
233  //Start the walk for every route table
234  for (uint8_t table_type = (Agent::INVALID + 1);
235  table_type < Agent::ROUTE_TABLE_MAX;
236  table_type++) {
237  table = static_cast<AgentRouteTable *>
238  (vrf->GetRouteTable(table_type));
239  if (!table) continue;
240  DBTable::DBTableWalkRef route_table_walk_ref =
242  WalkTable(table, route_table_walk_ref);
243  }
244 }
245 
246 /*
247  * VRF entry notification handler
248  */
250  DBEntryBase *e) {
251  VrfEntry *vrf = static_cast<VrfEntry *>(e);
252 
253  // TODO - VRF deletion need not be ignored, as it may be a way to
254  // unsubscribe. Needs to be fixed with controller walks.
255  //
256  // In case of controller-peer going down. We want to send 'unsubscribe' of
257  // VRF to BGP. Assume sequence where XMPP goes down and VRF is deleted. If
258  // XMPP walk starts before VRF deletion, we unsubscribe to the VRF
259  // notification at end of walk. If we skip deleted VRF in walk, we will not
260  // send 'unsubscribe' to BGP
261  //
262  if (vrf->IsDeleted()) {
263  AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
264  "VrfWalkNotify: Vrf deleted, no route walk.",
265  (vrf != NULL) ? vrf->GetName() : "Unknown",
266  "NA");
267  return true;
268  }
269 
270  StartRouteWalk(vrf);
271  return true;
272 }
273 
275  VrfWalkDone(part);
277  Callback(NULL);
278 }
279 
281 }
282 
283 /*
284  * Route entry notification handler
285  */
287  DBEntryBase *e) {
288  return true;
289 }
290 
292 }
293 
295  AgentRouteWalkerPtr ptr) {
296  RouteWalkDone(part);
297 
298  AgentRouteTable *table = static_cast<AgentRouteTable *>(part);
301  uint32_t vrf_id = table->vrf_id();
302 
303  VrfEntry *vrf = agent_->vrf_table()->
304  FindVrfFromIdIncludingDeletedVrf(vrf_id);
305  // If there is no vrf entry for table, that signifies that
306  // routes have gone and table is empty. Since routes have gone
307  // state from vncontroller on routes have been removed and so would
308  // have happened on vrf entry as well.
309  Callback(vrf);
310 }
311 
314  walk_count_.fetch_and_decrement();
315 }
316 
318  VrfRouteWalkCountMap::iterator it = route_walk_count_.find(vrf);
319  if (it != route_walk_count_.end()) {
320  it->second.fetch_and_decrement();
321  if (it->second == AgentRouteWalker::kInvalidWalkCount)
322  route_walk_count_.erase(vrf);
323  }
324 }
325 
327  route_walk_count_[vrf].fetch_and_increment();
328 }
329 
331  if (vrf && AreAllRouteWalksDone(vrf)) {
332  //Deletes the state on VRF
334  }
335  if (AreAllWalksDone()) {
336  //To be executed in callback where surity is there
337  //that all walks are done.
338  AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
339  "All Walks are done",
340  (vrf != NULL) ? vrf->GetName() : "Unknown",
341  "NA");
342  if (walk_done_cb_.empty() == false) {
343  walk_done_cb_();
344  }
345  }
346 }
347 
350  state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
351  if (it == state->walker_ref_map_.end())
352  return true;
353 
354  for (uint8_t table_type = Agent::ROUTE_TABLE_START;
355  table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
356  if (it->second[table_type] != DBTable::DBTableWalkRef())
357  return false;
358  }
359  return true;
360 }
361 
362 /*
363  * Check if all route table walk have been reset for this VRF
364  */
367  if (!state) {
368  return;
369  }
370 
371  AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
372  "All route walks are done",
373  (vrf != NULL) ? vrf->GetName() : "Unknown",
374  "NA");
375 
376  if (route_walk_done_for_vrf_cb_.empty())
377  return;
378 
380 }
381 
384 }
385 
387  VrfRouteWalkCountMap::const_iterator it = route_walk_count_.find(vrf);
388  return (it == route_walk_count_.end());
389 }
390 
391 /* Callback set, his is called when all walks are done i.e. VRF + route */
393  walk_done_cb_ = cb;
394 }
395 
396 /*
397  * Callback is registered to notify walk complete of all route tables for
398  * a VRF.
399  */
402 }
403 
406  if (vrf_walk_ref_ != NULL) {
408  }
409  vrf_walk_ref_.reset();
410 }
411 
413  DBEntryBase *e) {
414  VrfEntry *vrf = static_cast<VrfEntry *>(e);
415  DBTable::ListenerId vrf_listener_id = mgr_->vrf_listener_id();
416  RouteWalkerDBState *state =
417  static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
418  vrf_listener_id));
419  AgentRouteWalkerPtr walker_ptr = AgentRouteWalkerPtr(this);
420 
421  if (state == NULL)
422  return true;
423 
424  if (vrf_walk_ref_.get() != NULL) {
426  state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
427  if (it != state->walker_ref_map_.end())
429  return true;
430  }
431 
432  //If walk reference is provided as NULL, its delete of walk manager and
433  //agent shutdown. So delete all walk_refs.
435  state->walker_ref_map_.begin();
436  it2 != state->walker_ref_map_.end(); it2++) {
438  }
439  vrf->ClearState(partition->parent(), vrf_listener_id);
440  delete state;
441  return true;
442 }
443 
444 void
446  const Agent *agent = walker.get()->agent();
447  if (walker.get()->vrf_walk_ref().get() != NULL) {
448  walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
449  vrf_walk_ref());
450  }
451  if (walker.get()->delete_walk_ref().get() != NULL) {
452  walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
453  delete_walk_ref());
454  }
455 
456  if (agent->oper_db()->agent_route_walk_manager()) {
457  walker.get()->mgr()->RemoveWalker(walker);
458  walker.get()->mgr()->TryUnregister();
459  }
460  walker.get()->deregister_done_ = true;
461 }
462 
464  w->refcount_.fetch_and_increment();
465 }
466 
468  if (w->refcount_.fetch_and_decrement() == 1) {
469  delete w;
470  }
471 }
int intrusive_ptr_add_ref(const AsPath *cpath)
Definition: bgp_aspath.h:147
boost::array< DBTable::DBTableWalkRef, Agent::ROUTE_TABLE_MAX > RouteWalkRef
void ValidateAgentRouteWalker(AgentRouteWalkerPtr walker) const
RouteWalkerDBState * CreateState(VrfEntry *vrf)
void VrfNotify(DBTablePartBase *partition, DBEntryBase *e)
Agent * agent() const
static void DeregisterDone(AgentRouteWalkerPtr walker)
void WalkDoneCallback(WalkDone cb)
Definition: vrf.h:86
void Callback(VrfEntry *vrf)
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
void RemoveWalker(AgentRouteWalkerPtr walker)
virtual bool VrfWalkNotify(DBTablePartBase *partition, DBEntryBase *e)
RouteWalkDoneCb route_walk_done_for_vrf_cb_
DBTableBase * get_table() const
Definition: db_entry.cc:119
Agent supports multiple route tables - Inet-unicast (IPv4/IPv6), Inet-multicast, bridge, EVPN (Type2/Type5). This base class contains common code for all types of route tables.
Definition: agent_route.h:109
bool IsDeleted() const
Definition: db_entry.h:49
void SetState(DBTableBase *tbl_base, ListenerId listener, DBState *state)
Definition: db_entry.cc:22
int ListenerId
Definition: db_table.h:62
DBTableWalkRef AllocWalker(WalkFn walk_fn, WalkCompleteFn walk_complete)
Definition: db_table.cc:613
void set_mgr(AgentRouteWalkerManager *mgr)
void VrfWalkDoneInternal(DBTableBase *part)
DBTableBase * parent()
void OnRouteTableWalkCompleteForVrf(VrfEntry *vrf)
AgentRouteWalkerManager * mgr_
const string & GetName() const
Definition: vrf.h:100
static const uint8_t ROUTE_TABLE_START
Definition: agent.h:425
AgentRouteWalker(const std::string &name, Agent *agent)
boost::shared_ptr< TraceBuffer< SandeshTrace > > SandeshTraceBufferPtr
Definition: sandesh_trace.h:18
DBTable::DBTableWalkRef delete_walk_ref_
static void RemoveWalkReferencesInRoutetable(RouteWalkerDBState::AgentRouteWalkerRefMapIter &it, RouteWalkerDBState *state)
boost::function< void(VrfEntry *)> RouteWalkDoneCb
void Unregister(ListenerId listener)
Definition: db_table.cc:186
void ReleaseWalker(DBTableWalkRef &walk)
Definition: db_table.cc:619
OperDB * oper_db() const
Definition: agent.cc:1013
bool IsRouteTableWalkCompleted(RouteWalkerDBState *state)
bool Deregister(DBTablePartBase *partition, DBEntryBase *e)
virtual bool RouteWalkNotify(DBTablePartBase *partition, DBEntryBase *e)
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
void WalkAgain(DBTableWalkRef walk)
Definition: db_table.cc:631
VrfEntry * vrf_entry() const
Definition: agent_route.cc:459
virtual void RouteWalkDone(DBTableBase *part)
void RegisterWalker(AgentRouteWalker *walker)
void WalkTable(AgentRouteTable *table, DBTable::DBTableWalkRef &route_table_walk_ref)
Definition: agent.h:358
AgentRouteWalkerManager * agent_route_walk_manager() const
Definition: operdb_init.h:91
SandeshTraceBufferPtr AgentDBwalkTraceBuf
DBTable::DBTableWalkRef LocateRouteTableWalkRef(const VrfEntry *vrf, RouteWalkerDBState *state, AgentRouteTable *table)
AgentRouteWalkerRefMap::const_iterator AgentRouteWalkerRefMapConstIter
DBTable::ListenerId vrf_listener_id() const
bool AreAllWalksDone() const
tbb::atomic< uint32_t > refcount_
void StartRouteWalk(VrfEntry *vrf)
AgentRouteWalkerRefMap::iterator AgentRouteWalkerRefMapIter
void RouteWalkDoneForVrfCallback(RouteWalkDoneCb cb)
void ClearState(DBTableBase *tbl_base, ListenerId listener)
Definition: db_entry.cc:73
DBTable::DBTableWalkRef vrf_walk_ref_
boost::intrusive_ptr< AgentRouteWalker > AgentRouteWalkerPtr
DBTable::DBTableWalkRef & vrf_walk_ref()
void RemoveWalkReferencesInVrf(RouteWalkerDBState *state, VrfEntry *vrf)
static const int kInvalidWalkCount
void DecrementRouteWalkCount(const VrfEntry *vrf)
VrfTable * vrf_table() const
Definition: agent.h:485
#define AGENT_DBWALK_TRACE_BUF
tbb::atomic< int > walk_count_
void ReleaseWalker(AgentRouteWalker *walker)
DBTable::ListenerId vrf_listener_id_
void IncrementRouteWalkCount(const VrfEntry *vrf)
AgentRouteWalkerManager(Agent *agent)
AgentRouteTable * GetRouteTable(uint8_t table_type) const
Definition: vrf.cc:285
void intrusive_ptr_release(const AsPath *cpath)
Definition: bgp_aspath.h:155
DBTable::DBTableWalkRef & delete_walk_ref()
#define AGENT_DBWALK_TRACE(obj,...)
boost::intrusive_ptr< DBTableWalk > DBTableWalkRef
Definition: db_table.h:169
RouteTableType
Definition: agent.h:415
AgentRouteWalkerRefMap walker_ref_map_
bool AreAllRouteWalksDone(const VrfEntry *vrf) const
virtual void VrfWalkDone(DBTableBase *part)
DBTable::DBTableWalkRef AllocateRouteTableReferences(AgentRouteTable *table)
VrfRouteWalkCountMap route_walk_count_
boost::function< void()> WalkDone
RouteWalkerDBState * LocateRouteWalkerDBState(VrfEntry *vrf)
virtual Agent::RouteTableType GetTableType() const =0
SandeshTraceBufferPtr SandeshTraceBufferCreate(const std::string &buf_name, size_t buf_size, bool trace_enable=true)
Definition: sandesh_trace.h:46
uint32_t vrf_id() const
Definition: agent_route.h:161
void RouteWalkDoneInternal(DBTableBase *part, AgentRouteWalkerPtr ptr)