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