Line data Source code
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>
10 : #include <oper/agent_route_walker.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 :
20 : SandeshTraceBufferPtr AgentDBwalkTraceBuf(SandeshTraceBufferCreate(
21 : AGENT_DBWALK_TRACE_BUF, 1000));
22 :
23 48 : RouteWalkerDBState::RouteWalkerDBState() : walker_ref_map_() {
24 48 : }
25 :
26 : static void
27 85 : RemoveWalkReferencesInRoutetable(RouteWalkerDBState::AgentRouteWalkerRefMapIter &it,
28 : RouteWalkerDBState *state) {
29 85 : for (uint8_t table_type = Agent::ROUTE_TABLE_START;
30 595 : table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
31 510 : it->second[table_type] = DBTable::DBTableWalkRef();
32 : }
33 85 : }
34 :
35 3 : AgentRouteWalkerManager::AgentRouteWalkerManager(Agent *agent) : agent_(agent),
36 3 : walk_ref_list_(), marked_for_deletion_(false) {
37 3 : vrf_listener_id_ = agent->vrf_table()->Register(
38 : boost::bind(&AgentRouteWalkerManager::VrfNotify, this,
39 : _1, _2));
40 3 : }
41 :
42 6 : AgentRouteWalkerManager::~AgentRouteWalkerManager() {
43 : //Since walker ref list is going off, mark all walkers to have NULL
44 : //managers.
45 : //TODO
46 6 : }
47 :
48 134 : void AgentRouteWalkerManager::ReleaseWalker(AgentRouteWalker *walker) {
49 134 : assert(std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker)
50 : != walk_ref_list_.end());
51 134 : walker->ReleaseVrfWalkReference();
52 134 : }
53 :
54 : void
55 15 : AgentRouteWalkerManager::RemoveWalkReferencesInVrf(RouteWalkerDBState *state,
56 : VrfEntry *vrf) {
57 15 : for (RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
58 15 : state->walker_ref_map_.begin();
59 50 : it != state->walker_ref_map_.end(); it++) {
60 35 : RemoveWalkReferencesInRoutetable(it, state);
61 : }
62 15 : }
63 :
64 : //Handles VRF addition and deletion.
65 : //Releases all vrf walker reference and route table walker references.
66 304 : void AgentRouteWalkerManager::VrfNotify(DBTablePartBase *partition,
67 : DBEntryBase *e) {
68 304 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
69 : RouteWalkerDBState *state =
70 304 : static_cast<RouteWalkerDBState *>(vrf->GetState(partition->parent(),
71 : vrf_listener_id_));
72 304 : if (vrf->IsDeleted()) {
73 252 : if (!state)
74 237 : return;
75 15 : RemoveWalkReferencesInVrf(state, vrf);
76 15 : vrf->ClearState(partition->parent(), vrf_listener_id_);
77 15 : delete state;
78 15 : return;
79 : }
80 :
81 52 : if (!state) {
82 32 : CreateState(vrf);
83 : }
84 : }
85 :
86 48 : RouteWalkerDBState *AgentRouteWalkerManager::CreateState(VrfEntry *vrf) {
87 48 : RouteWalkerDBState *state = new RouteWalkerDBState();
88 48 : vrf->SetState(vrf->get_table(), vrf_listener_id_, state);
89 48 : return state;
90 : }
91 :
92 134 : void AgentRouteWalkerManager::RemoveWalker(AgentRouteWalkerPtr walker) {
93 134 : walk_ref_list_.erase(std::find(walk_ref_list_.begin(), walk_ref_list_.end(),
94 : walker));
95 134 : }
96 :
97 3 : void AgentRouteWalkerManager::Shutdown() {
98 3 : marked_for_deletion_ = true;
99 3 : TryUnregister();
100 3 : }
101 :
102 137 : void AgentRouteWalkerManager::TryUnregister() {
103 137 : if (walk_ref_list_.size() != 0)
104 134 : return;
105 3 : agent_->vrf_table()->Unregister(vrf_listener_id_);
106 : }
107 :
108 112 : void AgentRouteWalkerManager::ValidateAgentRouteWalker
109 : (AgentRouteWalkerPtr walker) const {
110 112 : assert (std::find(walk_ref_list_.begin(), walk_ref_list_.end(), walker) !=
111 : walk_ref_list_.end());
112 112 : }
113 :
114 134 : void AgentRouteWalkerManager::RegisterWalker(AgentRouteWalker *walker) {
115 134 : if (marked_for_deletion_)
116 0 : return;
117 134 : walk_ref_list_.insert(walker);
118 134 : walker->set_mgr(this);
119 : }
120 :
121 134 : AgentRouteWalker::AgentRouteWalker(const std::string &name,
122 134 : Agent *agent) : agent_(agent), name_(name),
123 134 : route_walk_count_(), walk_done_cb_(), route_walk_done_for_vrf_cb_(),
124 268 : mgr_(NULL), deregister_done_(false) {
125 134 : walk_count_ = AgentRouteWalker::kInvalidWalkCount;
126 268 : vrf_walk_ref_ = agent_->vrf_table()->AllocWalker(
127 : boost::bind(&AgentRouteWalker::VrfWalkNotify,
128 : this, _1, _2),
129 : boost::bind(&AgentRouteWalker::VrfWalkDoneInternal,
130 134 : this, _2));
131 268 : delete_walk_ref_ = agent_->vrf_table()->AllocWalker(
132 : boost::bind(&AgentRouteWalker::Deregister, this,
133 : _1, _2),
134 : boost::bind(&AgentRouteWalker::DeregisterDone,
135 134 : this));
136 134 : refcount_ = 0;
137 134 : }
138 :
139 134 : AgentRouteWalker::~AgentRouteWalker() {
140 134 : assert(vrf_walk_ref_.get() == NULL);
141 134 : assert(delete_walk_ref_.get() == NULL);
142 134 : }
143 :
144 : RouteWalkerDBState *
145 630 : AgentRouteWalker::LocateRouteWalkerDBState(VrfEntry *vrf) {
146 : RouteWalkerDBState *state =
147 630 : static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
148 630 : mgr_->vrf_listener_id()));
149 630 : if (vrf->IsDeleted())
150 0 : return state;
151 :
152 630 : if (!state)
153 16 : state = mgr_->CreateState(vrf);
154 :
155 630 : return state;
156 : }
157 :
158 : DBTable::DBTableWalkRef
159 540 : AgentRouteWalker::LocateRouteTableWalkRef(const VrfEntry *vrf,
160 : RouteWalkerDBState *state,
161 : AgentRouteTable *table) {
162 540 : assert(state != NULL);
163 540 : Agent::RouteTableType table_type = table->GetTableType();
164 540 : 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.
168 : RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
169 540 : state->walker_ref_map_.find(walker_ptr);
170 540 : DBTable::DBTableWalkRef route_table_walk_ref = DBTable::DBTableWalkRef();
171 :
172 : // Walker was not found in map, add it
173 540 : if (it == state->walker_ref_map_.end()) {
174 85 : RouteWalkerDBState::RouteWalkRef route_walk_ref;
175 85 : std::pair<RouteWalkerDBState::AgentRouteWalkerRefMapIter, bool> ret;
176 85 : ret = state->walker_ref_map_.insert(std::make_pair(walker_ptr, route_walk_ref));
177 85 : if (ret.second == false) {
178 0 : AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
179 : "LocateRouteTableWalkRef walker add failed.",
180 : "", "");
181 0 : return DBTable::DBTableWalkRef();
182 : }
183 85 : it = ret.first;
184 85 : }
185 :
186 : // table type had no reference allocated, so allocate it.
187 540 : if (it->second[table_type] == DBTable::DBTableWalkRef()) {
188 1020 : it->second[table_type] = table->AllocWalker(
189 : boost::bind(&AgentRouteWalker::RouteWalkNotify,
190 : this, _1, _2),
191 1020 : boost::bind(&AgentRouteWalker::RouteWalkDoneInternal,
192 510 : this, _2, walker_ptr));
193 : }
194 540 : return it->second[table_type];
195 540 : }
196 :
197 : /*
198 : * Starts walk for all VRF.
199 : */
200 22 : void AgentRouteWalker::StartVrfWalk() {
201 22 : mgr_->ValidateAgentRouteWalker(this);
202 22 : if (vrf_walk_ref_->in_progress() == false)
203 22 : IncrementWalkCount();
204 22 : agent_->vrf_table()->WalkAgain(vrf_walk_ref_);
205 : //TODO trace
206 22 : AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_, "StartVrfWalk",
207 : "", "");
208 22 : }
209 :
210 : DBTable::DBTableWalkRef
211 540 : AgentRouteWalker::AllocateRouteTableReferences(AgentRouteTable *table) {
212 540 : VrfEntry *vrf = table->vrf_entry();
213 540 : RouteWalkerDBState *state = LocateRouteWalkerDBState(vrf);
214 540 : return LocateRouteTableWalkRef(vrf, state, table);
215 : }
216 :
217 540 : void AgentRouteWalker::WalkTable(AgentRouteTable *table,
218 : DBTable::DBTableWalkRef &route_table_walk_ref) {
219 540 : if (route_table_walk_ref->in_progress() == false) {
220 540 : IncrementWalkCount();
221 540 : IncrementRouteWalkCount(table->vrf_entry());
222 : }
223 540 : table->WalkAgain(route_table_walk_ref);
224 540 : }
225 :
226 : /*
227 : * Starts route walk for given VRF.
228 : */
229 90 : void AgentRouteWalker::StartRouteWalk(VrfEntry *vrf) {
230 90 : mgr_->ValidateAgentRouteWalker(this);
231 90 : AgentRouteTable *table = NULL;
232 :
233 : //Start the walk for every route table
234 630 : for (uint8_t table_type = (Agent::INVALID + 1);
235 630 : table_type < Agent::ROUTE_TABLE_MAX;
236 : table_type++) {
237 : table = static_cast<AgentRouteTable *>
238 540 : (vrf->GetRouteTable(table_type));
239 540 : if (!table) continue;
240 : DBTable::DBTableWalkRef route_table_walk_ref =
241 540 : AllocateRouteTableReferences(table);
242 540 : WalkTable(table, route_table_walk_ref);
243 540 : }
244 90 : }
245 :
246 : /*
247 : * VRF entry notification handler
248 : */
249 14 : bool AgentRouteWalker::VrfWalkNotify(DBTablePartBase *partition,
250 : DBEntryBase *e) {
251 14 : 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 14 : if (vrf->IsDeleted()) {
263 0 : AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
264 : "VrfWalkNotify: Vrf deleted, no route walk.",
265 : (vrf != NULL) ? vrf->GetName() : "Unknown",
266 : "NA");
267 0 : return true;
268 : }
269 :
270 14 : StartRouteWalk(vrf);
271 14 : return true;
272 : }
273 :
274 22 : void AgentRouteWalker::VrfWalkDoneInternal(DBTableBase *part) {
275 22 : VrfWalkDone(part);
276 22 : DecrementWalkCount();
277 22 : Callback(NULL);
278 22 : }
279 :
280 22 : void AgentRouteWalker::VrfWalkDone(DBTableBase *part) {
281 22 : }
282 :
283 : /*
284 : * Route entry notification handler
285 : */
286 0 : bool AgentRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
287 : DBEntryBase *e) {
288 0 : return true;
289 : }
290 :
291 540 : void AgentRouteWalker::RouteWalkDone(DBTableBase *part) {
292 540 : }
293 :
294 540 : void AgentRouteWalker::RouteWalkDoneInternal(DBTableBase *part,
295 : AgentRouteWalkerPtr ptr) {
296 540 : RouteWalkDone(part);
297 :
298 540 : AgentRouteTable *table = static_cast<AgentRouteTable *>(part);
299 540 : DecrementWalkCount();
300 540 : DecrementRouteWalkCount(table->vrf_entry());
301 540 : uint32_t vrf_id = table->vrf_id();
302 :
303 540 : VrfEntry *vrf = agent_->vrf_table()->
304 540 : 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 540 : Callback(vrf);
310 540 : }
311 :
312 562 : void AgentRouteWalker::DecrementWalkCount() {
313 562 : assert(walk_count_ != AgentRouteWalker::kInvalidWalkCount);
314 562 : walk_count_--;
315 562 : }
316 :
317 540 : void AgentRouteWalker::DecrementRouteWalkCount(const VrfEntry *vrf) {
318 540 : VrfRouteWalkCountMap::iterator it = route_walk_count_.find(vrf);
319 540 : if (it != route_walk_count_.end()) {
320 540 : it->second--;
321 540 : if (it->second == AgentRouteWalker::kInvalidWalkCount)
322 90 : route_walk_count_.erase(vrf);
323 : }
324 540 : }
325 :
326 540 : void AgentRouteWalker::IncrementRouteWalkCount(const VrfEntry *vrf) {
327 540 : route_walk_count_[vrf]++;
328 540 : }
329 :
330 562 : void AgentRouteWalker::Callback(VrfEntry *vrf) {
331 562 : if (vrf && AreAllRouteWalksDone(vrf)) {
332 : //Deletes the state on VRF
333 90 : OnRouteTableWalkCompleteForVrf(vrf);
334 : }
335 562 : if (AreAllWalksDone()) {
336 : //To be executed in callback where surity is there
337 : //that all walks are done.
338 76 : AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
339 : "All Walks are done",
340 : (vrf != NULL) ? vrf->GetName() : "Unknown",
341 : "NA");
342 76 : if (walk_done_cb_.empty() == false) {
343 12 : walk_done_cb_();
344 : }
345 : }
346 562 : }
347 :
348 0 : bool AgentRouteWalker::IsRouteTableWalkCompleted(RouteWalkerDBState *state) {
349 : RouteWalkerDBState::AgentRouteWalkerRefMapConstIter it =
350 0 : state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
351 0 : if (it == state->walker_ref_map_.end())
352 0 : return true;
353 :
354 0 : for (uint8_t table_type = Agent::ROUTE_TABLE_START;
355 0 : table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
356 0 : if (it->second[table_type] != DBTable::DBTableWalkRef())
357 0 : return false;
358 : }
359 0 : return true;
360 : }
361 :
362 : /*
363 : * Check if all route table walk have been reset for this VRF
364 : */
365 90 : void AgentRouteWalker::OnRouteTableWalkCompleteForVrf(VrfEntry *vrf) {
366 90 : RouteWalkerDBState *state = LocateRouteWalkerDBState(vrf);
367 90 : if (!state) {
368 0 : return;
369 : }
370 :
371 90 : AGENT_DBWALK_TRACE(AgentRouteWalkerTrace, name_,
372 : "All route walks are done",
373 : (vrf != NULL) ? vrf->GetName() : "Unknown",
374 : "NA");
375 :
376 90 : if (route_walk_done_for_vrf_cb_.empty())
377 68 : return;
378 :
379 22 : route_walk_done_for_vrf_cb_(vrf);
380 : }
381 :
382 562 : bool AgentRouteWalker::AreAllWalksDone() const {
383 562 : return (walk_count_ == AgentRouteWalker::kInvalidWalkCount);
384 : }
385 :
386 540 : bool AgentRouteWalker::AreAllRouteWalksDone(const VrfEntry *vrf) const {
387 540 : VrfRouteWalkCountMap::const_iterator it = route_walk_count_.find(vrf);
388 540 : return (it == route_walk_count_.end());
389 : }
390 :
391 : /* Callback set, his is called when all walks are done i.e. VRF + route */
392 18 : void AgentRouteWalker::WalkDoneCallback(WalkDone cb) {
393 18 : walk_done_cb_ = cb;
394 18 : }
395 :
396 : /*
397 : * Callback is registered to notify walk complete of all route tables for
398 : * a VRF.
399 : */
400 22 : void AgentRouteWalker::RouteWalkDoneForVrfCallback(RouteWalkDoneCb cb) {
401 22 : route_walk_done_for_vrf_cb_ = cb;
402 22 : }
403 :
404 134 : void AgentRouteWalker::ReleaseVrfWalkReference() {
405 134 : agent_->vrf_table()->WalkAgain(delete_walk_ref_);
406 134 : if (vrf_walk_ref_ != NULL) {
407 134 : agent_->vrf_table()->ReleaseWalker(vrf_walk_ref());
408 : }
409 134 : vrf_walk_ref_.reset();
410 134 : }
411 :
412 328 : bool AgentRouteWalker::Deregister(DBTablePartBase *partition,
413 : DBEntryBase *e) {
414 328 : VrfEntry *vrf = static_cast<VrfEntry *>(e);
415 328 : DBTable::ListenerId vrf_listener_id = mgr_->vrf_listener_id();
416 : RouteWalkerDBState *state =
417 328 : static_cast<RouteWalkerDBState *>(vrf->GetState(vrf->get_table(),
418 : vrf_listener_id));
419 328 : AgentRouteWalkerPtr walker_ptr = AgentRouteWalkerPtr(this);
420 :
421 328 : if (state == NULL)
422 295 : return true;
423 :
424 33 : if (vrf_walk_ref_.get() != NULL) {
425 : RouteWalkerDBState::AgentRouteWalkerRefMapIter it =
426 0 : state->walker_ref_map_.find(AgentRouteWalkerPtr(this));
427 0 : if (it != state->walker_ref_map_.end())
428 0 : RemoveWalkReferencesInRoutetable(it, state);
429 0 : 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.
434 33 : for (RouteWalkerDBState::AgentRouteWalkerRefMapIter it2 =
435 33 : state->walker_ref_map_.begin();
436 83 : it2 != state->walker_ref_map_.end(); it2++) {
437 50 : RemoveWalkReferencesInRoutetable(it2, state);
438 : }
439 33 : vrf->ClearState(partition->parent(), vrf_listener_id);
440 33 : delete state;
441 33 : return true;
442 328 : }
443 :
444 : void
445 134 : AgentRouteWalker::DeregisterDone(AgentRouteWalkerPtr walker) {
446 134 : const Agent *agent = walker.get()->agent();
447 134 : if (walker.get()->vrf_walk_ref().get() != NULL) {
448 0 : walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
449 : vrf_walk_ref());
450 : }
451 134 : if (walker.get()->delete_walk_ref().get() != NULL) {
452 134 : walker.get()->agent()->vrf_table()->ReleaseWalker(walker.get()->
453 : delete_walk_ref());
454 : }
455 :
456 134 : if (agent->oper_db()->agent_route_walk_manager()) {
457 134 : walker.get()->mgr()->RemoveWalker(walker);
458 134 : walker.get()->mgr()->TryUnregister();
459 : }
460 134 : walker.get()->deregister_done_ = true;
461 134 : }
462 :
463 10361 : void intrusive_ptr_add_ref(AgentRouteWalker *w) {
464 10361 : w->refcount_++;
465 10361 : }
466 :
467 10361 : void intrusive_ptr_release(AgentRouteWalker *w) {
468 20722 : if (w->refcount_.fetch_sub(1) == 1) {
469 134 : delete w;
470 : }
471 10361 : }
|