Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_membership.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include "base/task_annotations.h"
10 : #include "base/task_trigger.h"
11 : #include "bgp/bgp_export.h"
12 : #include "bgp/bgp_log.h"
13 : #include "bgp/bgp_peer_types.h"
14 : #include "bgp/bgp_route.h"
15 : #include "bgp/bgp_server.h"
16 : #include "bgp/bgp_update_sender.h"
17 : #include "bgp/routing-instance/routing_instance.h"
18 :
19 : using std::list;
20 : using std::make_pair;
21 : using std::string;
22 : using std::vector;
23 :
24 : //
25 : // Constructor for BgpMembershipManager.
26 : //
27 9742 : BgpMembershipManager::BgpMembershipManager(BgpServer *server)
28 9742 : : server_(server),
29 9742 : walker_(new Walker(this)),
30 19484 : event_queue_(new WorkQueue<Event *>(
31 19484 : TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0,
32 29226 : boost::bind(&BgpMembershipManager::EventCallback, this, _1))) {
33 9742 : current_jobs_count_ = 0;
34 9742 : total_jobs_count_ = 0;
35 9742 : }
36 :
37 : //
38 : // Destructor for BgpMembershipManager.
39 : //
40 19448 : BgpMembershipManager::~BgpMembershipManager() {
41 9742 : assert(current_jobs_count_ == 0);
42 9742 : assert(rib_state_map_.empty());
43 9742 : assert(peer_state_map_.empty());
44 19448 : }
45 :
46 38968 : int BgpMembershipManager::RegisterPeerRegistrationCallback(
47 : PeerRegistrationCallback callback) {
48 38968 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
49 :
50 38968 : size_t id = registration_bmap_.find_first();
51 38968 : if (id == registration_bmap_.npos) {
52 38968 : id = registration_callbacks_.size();
53 38968 : registration_callbacks_.push_back(callback);
54 : } else {
55 0 : registration_bmap_.reset(id);
56 0 : if (registration_bmap_.none()) {
57 0 : registration_bmap_.clear();
58 : }
59 0 : registration_callbacks_[id] = callback;
60 : }
61 38968 : return id;
62 38968 : }
63 :
64 38552 : void BgpMembershipManager::UnregisterPeerRegistrationCallback(int id) {
65 38552 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
66 :
67 38552 : registration_callbacks_[id] = NULL;
68 38552 : if ((size_t) id == registration_callbacks_.size() - 1) {
69 88784 : while (!registration_callbacks_.empty() &&
70 39573 : registration_callbacks_.back() == NULL) {
71 38552 : registration_callbacks_.pop_back();
72 : }
73 10659 : if (registration_bmap_.size() > registration_callbacks_.size()) {
74 10411 : registration_bmap_.resize(registration_callbacks_.size());
75 : }
76 : } else {
77 27893 : if ((size_t) id >= registration_bmap_.size()) {
78 27857 : registration_bmap_.resize(id + 1);
79 : }
80 27893 : registration_bmap_.set(id);
81 : }
82 38552 : }
83 :
84 163286 : void BgpMembershipManager::NotifyPeerRegistration(IPeer *peer, BgpTable *table,
85 : bool unregister) {
86 163286 : CHECK_CONCURRENCY("bgp::PeerMembership");
87 :
88 163286 : if (!peer->IsXmppPeer())
89 25948 : return;
90 :
91 137338 : for (PeerRegistrationListenerList::iterator iter =
92 137338 : registration_callbacks_.begin();
93 686210 : iter != registration_callbacks_.end(); ++iter) {
94 548872 : if (*iter != NULL) {
95 548872 : PeerRegistrationCallback callback = *iter;
96 548872 : (callback)(peer, table, unregister);
97 548872 : }
98 : }
99 : }
100 :
101 81665 : bool BgpMembershipManager::AssertRegister(PeerRibState *prs, bool do_assert) {
102 81665 : if (prs->action() != NONE) {
103 1 : if (do_assert)
104 0 : assert(prs->action() == NONE);
105 1 : return false;
106 : }
107 :
108 81663 : if (prs->ribout_registered()) {
109 1 : if (do_assert)
110 0 : assert(!prs->ribout_registered());
111 1 : return false;
112 : }
113 :
114 81661 : return true;
115 : }
116 :
117 : // Register the IPeer to the BgpTable.
118 : // Post a REGISTER_RIB event to deal with concurrency issues with RibOut.
119 81659 : void BgpMembershipManager::Register(IPeer *peer, BgpTable *table,
120 : const RibExportPolicy &policy, int instance_id) {
121 81659 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
122 : "bgp::StateMachine", "xmpp::StateMachine");
123 :
124 81661 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
125 81664 : PeerRibState *prs = LocatePeerRibState(peer, table);
126 81665 : if (!AssertRegister(prs))
127 2 : return;
128 81660 : current_jobs_count_++;
129 81663 : total_jobs_count_++;
130 81663 : prs->set_ribin_registered(true);
131 81663 : prs->set_action(RIBOUT_ADD);
132 81662 : Event *event = new Event(REGISTER_RIB, peer, table, policy, instance_id);
133 81654 : EnqueueEvent(event);
134 81665 : }
135 :
136 6994 : bool BgpMembershipManager::AssertRegisterRibIn(PeerRibState *prs, IPeer *peer,
137 : bool do_assert) {
138 6994 : if (prs->action() != NONE) {
139 1 : if (do_assert)
140 0 : assert(prs->action() == NONE);
141 1 : return false;
142 : }
143 :
144 6992 : if (prs->ribin_registered() && !peer->IsInGRTimerWaitState()) {
145 3 : if (do_assert)
146 0 : assert(!prs->ribin_registered() || peer->IsInGRTimerWaitState());
147 3 : return false;
148 : }
149 :
150 6989 : if (prs->ribout_registered()) {
151 0 : if (do_assert)
152 0 : assert(!prs->ribout_registered());
153 0 : return false;
154 : }
155 :
156 6989 : return true;
157 : }
158 :
159 : // Synchronously register the IPeer to the BgpTable for RIBIN.
160 6995 : void BgpMembershipManager::RegisterRibIn(IPeer *peer, BgpTable *table) {
161 6995 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
162 : "bgp::StateMachine", "xmpp::StateMachine");
163 :
164 6996 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
165 6995 : PeerRibState *prs = LocatePeerRibState(peer, table);
166 6994 : if (!AssertRegisterRibIn(prs, peer))
167 4 : return;
168 6989 : prs->set_ribin_registered(true);
169 6993 : }
170 :
171 77707 : bool BgpMembershipManager::AssertUnregister(PeerRibState *prs, bool do_assert) {
172 77707 : if (!prs || prs->action() != NONE) {
173 4 : if (do_assert)
174 0 : assert(prs && prs->action() == NONE);
175 4 : return false;
176 : }
177 :
178 77703 : if (!prs->ribin_registered()) {
179 0 : if (do_assert)
180 0 : assert(prs->ribin_registered());
181 0 : return false;
182 : }
183 :
184 77703 : return true;
185 : }
186 :
187 : // Unregister the IPeer from the BgpTable.
188 : // Post an UNREGISTER_RIB event to deal with concurrency issues with RibOut.
189 77707 : void BgpMembershipManager::Unregister(IPeer *peer, BgpTable *table) {
190 77707 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
191 :
192 77707 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
193 77707 : PeerRibState *prs = FindPeerRibState(peer, table);
194 77707 : if (!AssertUnregister(prs))
195 4 : return;
196 :
197 77703 : current_jobs_count_++;
198 77703 : total_jobs_count_++;
199 :
200 77703 : if (!prs->ribout_registered()) {
201 346 : UnregisterRibInUnlocked(prs);
202 346 : return;
203 : }
204 :
205 77357 : prs->set_action(RIBIN_DELETE_RIBOUT_DELETE);
206 77357 : prs->set_ribin_registered(false);
207 77357 : prs->set_instance_id(-1);
208 77357 : prs->set_subscription_gen_id(0);
209 77357 : Event *event = new Event(UNREGISTER_RIB, peer, table);
210 77357 : EnqueueEvent(event);
211 77707 : }
212 :
213 : //
214 : // Unregister the IPeer from the BgpTable for RIBIN.
215 : //
216 1802 : void BgpMembershipManager::UnregisterRibIn(IPeer *peer, BgpTable *table) {
217 1802 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
218 :
219 1802 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
220 1802 : current_jobs_count_++;
221 1802 : total_jobs_count_++;
222 1802 : PeerRibState *prs = FindPeerRibState(peer, table);
223 1802 : assert(prs && prs->action() == NONE);
224 1802 : assert(prs->ribin_registered() && !prs->ribout_registered());
225 1802 : UnregisterRibInUnlocked(prs);
226 1802 : }
227 :
228 : //
229 : // Common routine to handle unregister of IPeer from Table for RIBIN.
230 : //
231 2148 : void BgpMembershipManager::UnregisterRibInUnlocked(PeerRibState *prs) {
232 2148 : prs->set_ribin_registered(false);
233 2148 : prs->set_instance_id(-1);
234 2148 : prs->set_subscription_gen_id(0);
235 2148 : prs->set_action(RIBIN_DELETE);
236 2148 : prs->UnregisterRibIn();
237 5943 : BGP_LOG_PEER_TABLE(prs->peer(), SandeshLevel::SYS_DEBUG,
238 : BGP_LOG_FLAG_SYSLOG, prs->table(),
239 : "Unregister table requested for action " << prs->action());
240 2148 : }
241 :
242 : //
243 : // Unregister the IPeer from the BgpTable.
244 : // Post an UNREGISTER_RIB event to deal with concurrency issues with RibOut.
245 : // The action is set to RIBIN_WALK_RIBOUT_DELETE.
246 : // This API is to be used when handling graceful restart of the peer.
247 : //
248 4306 : void BgpMembershipManager::UnregisterRibOut(IPeer *peer, BgpTable *table) {
249 4306 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
250 :
251 4306 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
252 4306 : current_jobs_count_++;
253 4306 : total_jobs_count_++;
254 4306 : PeerRibState *prs = FindPeerRibState(peer, table);
255 4306 : assert(prs && prs->action() == NONE);
256 4306 : assert(prs->ribin_registered());
257 4306 : assert(prs->ribout_registered());
258 4306 : prs->set_instance_id(-1);
259 4306 : prs->set_subscription_gen_id(0);
260 4306 : prs->set_action(RIBIN_WALK_RIBOUT_DELETE);
261 4306 : Event *event = new Event(UNREGISTER_RIB, peer, table);
262 4306 : EnqueueEvent(event);
263 4306 : }
264 :
265 3774 : bool BgpMembershipManager::AssertWalkRibIn(PeerRibState *prs, bool do_assert) {
266 3774 : if (!prs || prs->action() != NONE) {
267 4 : if (do_assert)
268 0 : assert(prs && prs->action() == NONE);
269 4 : return false;
270 : }
271 :
272 3770 : if (!prs->ribin_registered()) {
273 0 : if (do_assert)
274 0 : assert(prs->ribin_registered());
275 0 : return false;
276 : }
277 :
278 3770 : return true;
279 : }
280 :
281 : //
282 : // Trigger a walk of IPeer's RIBIN for the BgpTable.
283 : // This API can be used when sweeping paths as part of graceful restart.
284 : // It can also be used in future when re-evaluating import policy for a peer.
285 : //
286 3774 : void BgpMembershipManager::WalkRibIn(IPeer *peer, BgpTable *table) {
287 3774 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
288 :
289 3774 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
290 3774 : PeerRibState *prs = FindPeerRibState(peer, table);
291 3774 : if (!AssertWalkRibIn(prs))
292 4 : return;
293 3770 : current_jobs_count_++;
294 3770 : total_jobs_count_++;
295 3770 : prs->set_action(RIBIN_WALK);
296 3770 : prs->WalkRibIn();
297 9555 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
298 : table, "Walk table requested for action " << prs->action());
299 3774 : }
300 :
301 : //
302 : // Fill in the registration info of the IPeer for the BgpTable.
303 : // Return true if the IPeer is registered with the BgpTable, false otherwise.
304 : //
305 101344 : bool BgpMembershipManager::GetRegistrationInfo(
306 : const IPeer *peer, const BgpTable *table,
307 : int *instance_id, uint64_t *subscription_gen_id) const {
308 101344 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
309 101356 : const PeerRibState *prs = FindPeerRibState(peer, table);
310 101315 : if (!prs)
311 33016 : return false;
312 68299 : if (instance_id)
313 68275 : *instance_id = prs->instance_id();
314 68300 : if (subscription_gen_id)
315 66764 : *subscription_gen_id = prs->subscription_gen_id();
316 68299 : return true;
317 101315 : }
318 :
319 : //
320 : // Update the registration info of the IPeer for the BgpTable.
321 : //
322 68202 : void BgpMembershipManager::SetRegistrationInfo(
323 : const IPeer *peer, const BgpTable *table,
324 : int instance_id, uint64_t subscription_gen_id) {
325 68202 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
326 68205 : PeerRibState *prs = FindPeerRibState(peer, table);
327 68192 : if (!prs)
328 0 : return;
329 68192 : prs->set_instance_id(instance_id);
330 68192 : prs->set_subscription_gen_id(subscription_gen_id);
331 68192 : }
332 :
333 : //
334 : // Return true if the IPeer is registered to the BgpTable.
335 : //
336 222831 : bool BgpMembershipManager::IsRegistered(const IPeer *peer,
337 : const BgpTable *table) const {
338 222831 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
339 222831 : const PeerRibState *prs = FindPeerRibState(peer, table);
340 445662 : return (prs && prs->ribin_registered() && prs->ribout_registered());
341 222831 : }
342 :
343 : //
344 : // Return true if the IPeer is registered to the BgpTable for RibIn.
345 : //
346 4029 : bool BgpMembershipManager::IsRibInRegistered(const IPeer *peer,
347 : const BgpTable *table) const {
348 4029 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
349 4029 : const PeerRibState *prs = FindPeerRibState(peer, table);
350 8058 : return (prs && prs->ribin_registered());
351 4029 : }
352 :
353 : //
354 : // Return true if the IPeer is registered to the BgpTable for RibOut.
355 : //
356 68179 : bool BgpMembershipManager::IsRibOutRegistered(const IPeer *peer,
357 : const BgpTable *table) const {
358 68179 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
359 68184 : const PeerRibState *prs = FindPeerRibState(peer, table);
360 136362 : return (prs && prs->ribout_registered());
361 68174 : }
362 :
363 : //
364 : // Return RibOut's output queue depth.
365 : //
366 0 : uint32_t BgpMembershipManager::GetRibOutQueueDepth(const IPeer *peer,
367 : const BgpTable *table) const {
368 0 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
369 0 : const PeerRibState *prs = FindPeerRibState(peer, table);
370 0 : if (!prs || !prs->ribout_registered())
371 0 : return 0;
372 0 : RibOut *ribout = prs->ribout();
373 0 : if (!ribout)
374 0 : return 0;
375 0 : return ribout->GetQueueSize();
376 0 : }
377 :
378 : //
379 : // Fill in the list of registered BgpTables for given IPeer.
380 : //
381 20180 : void BgpMembershipManager::GetRegisteredRibs(const IPeer *peer,
382 : list<BgpTable *> *table_list) const {
383 20180 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
384 20180 : table_list->clear();
385 20180 : const PeerState *ps = FindPeerState(peer);
386 20180 : if (ps)
387 9742 : ps->GetRegisteredRibs(table_list);
388 20180 : }
389 :
390 : //
391 : //
392 : // Fill membership introspect information for a BgpTable.
393 : //
394 1093 : void BgpMembershipManager::FillRoutingInstanceTableInfo(
395 : ShowRoutingInstanceTable *srit, const BgpTable *table) const {
396 1093 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
397 1093 : BgpTable *nc_table = const_cast<BgpTable *>(table);
398 1093 : const RibState *rs = FindRibState(nc_table);
399 1093 : if (rs)
400 980 : rs->FillRoutingInstanceTableInfo(srit);
401 1093 : }
402 :
403 : //
404 : // Fill membership introspect information for an IPeer.
405 : //
406 543 : void BgpMembershipManager::FillPeerMembershipInfo(const IPeer *peer,
407 : BgpNeighborResp *resp) const {
408 543 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
409 543 : assert(resp->get_routing_tables().empty());
410 543 : IPeer *nc_peer = const_cast<IPeer *>(peer);
411 :
412 543 : BgpUpdateSender *sender = server_->update_sender();
413 543 : if (sender->PeerIsRegistered(nc_peer)) {
414 1058 : resp->set_send_state(
415 529 : sender->PeerInSync(nc_peer) ? "in sync" : "not in sync");
416 : } else {
417 14 : resp->set_send_state("not advertising");
418 : }
419 :
420 543 : const PeerState *ps = FindPeerState(nc_peer);
421 543 : if (ps)
422 529 : ps->FillPeerMembershipInfo(resp);
423 543 : }
424 :
425 : //
426 : // Return true if no pending work in the BgpMembershipManager itself and
427 : // in the Walker.
428 : //
429 1718929 : bool BgpMembershipManager::IsQueueEmpty() const {
430 1718929 : return (event_queue_->IsQueueEmpty() && walker_->IsQueueEmpty());
431 : }
432 :
433 : //
434 : // Return number of PeerRibStates.
435 : //
436 170 : size_t BgpMembershipManager::GetMembershipCount() const {
437 170 : size_t count = 0;
438 170 : for (PeerStateMap::const_iterator loc = peer_state_map_.begin();
439 1107 : loc != peer_state_map_.end(); ++loc) {
440 937 : const PeerState *ps = loc->second;
441 937 : count += ps->GetMembershipCount();
442 : }
443 170 : return count;
444 : }
445 :
446 : //
447 : // Find or create the PeerState for given IPeer.
448 : //
449 88659 : BgpMembershipManager::PeerState *BgpMembershipManager::LocatePeerState(
450 : IPeer *peer) {
451 88659 : PeerStateMap::iterator loc = peer_state_map_.find(peer);
452 88650 : if (loc == peer_state_map_.end()) {
453 8667 : PeerState *ps = new PeerState(this, peer);
454 8667 : peer_state_map_.insert(make_pair(peer, ps));
455 8669 : return ps;
456 : } else {
457 79983 : return loc->second;
458 : }
459 : }
460 :
461 : //
462 : // Find the PeerState for given IPeer.
463 : //
464 488323 : BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
465 : const IPeer *peer) {
466 488323 : PeerStateMap::iterator loc = peer_state_map_.find(peer);
467 488314 : return (loc != peer_state_map_.end() ? loc->second : NULL);
468 : }
469 :
470 : //
471 : // Find the PeerState for given IPeer.
472 : // Const version.
473 : //
474 417121 : const BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
475 : const IPeer *peer) const {
476 417121 : PeerStateMap::const_iterator loc = peer_state_map_.find(peer);
477 417094 : return (loc != peer_state_map_.end() ? loc->second : NULL);
478 : }
479 :
480 : //
481 : // Destroy the given PeerState.
482 : //
483 8669 : void BgpMembershipManager::DestroyPeerState(PeerState *ps) {
484 8669 : peer_state_map_.erase(ps->peer());
485 8669 : delete ps;
486 8669 : }
487 :
488 : //
489 : // Find or create the RibState for given BgpTable.
490 : //
491 88652 : BgpMembershipManager::RibState *BgpMembershipManager::LocateRibState(
492 : BgpTable *table) {
493 88652 : RibStateMap::iterator loc = rib_state_map_.find(table);
494 88647 : if (loc == rib_state_map_.end()) {
495 31263 : RibState *rs = new RibState(this, table);
496 31264 : rib_state_map_.insert(make_pair(table, rs));
497 31265 : return rs;
498 : } else {
499 57388 : return loc->second;
500 : }
501 : }
502 :
503 : //
504 : // Find the RibState for given BgpTable.
505 : //
506 488313 : BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
507 : const BgpTable *table) {
508 488313 : RibStateMap::iterator loc = rib_state_map_.find(table);
509 488310 : return (loc != rib_state_map_.end() ? loc->second : NULL);
510 : }
511 :
512 : //
513 : // Find the RibState for given BgpTable.
514 : // Const version.
515 : //
516 397462 : const BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
517 : const BgpTable *table) const {
518 397462 : RibStateMap::const_iterator loc = rib_state_map_.find(table);
519 397460 : return (loc != rib_state_map_.end() ? loc->second : NULL);
520 : }
521 :
522 : //
523 : // Destroy the given RibState.
524 : //
525 31265 : void BgpMembershipManager::DestroyRibState(RibState *rs) {
526 31265 : rib_state_map_.erase(rs->table());
527 31265 : delete rs;
528 31265 : }
529 :
530 : //
531 : // Request the Walker to schedule a table walk for the given RibState.
532 : // Note that the Walker accumulates requests and starts walks asynchronously.
533 : //
534 169164 : void BgpMembershipManager::EnqueueRibState(RibState *rs) {
535 169164 : walker_->Enqueue(rs);
536 169164 : }
537 :
538 : //
539 : // Find or create the PeerRibState for given (IPeer, BgpTable).
540 : //
541 88659 : BgpMembershipManager::PeerRibState *BgpMembershipManager::LocatePeerRibState(
542 : IPeer *peer, BgpTable *table) {
543 88659 : PeerState *ps = LocatePeerState(peer);
544 88652 : RibState *rs = LocateRibState(table);
545 88651 : PeerRibState *prs = ps->LocatePeerRibState(rs);
546 88654 : rs->InsertPeerRibState(prs);
547 88659 : return prs;
548 : }
549 :
550 : //
551 : // Find the PeerRibState for given (IPeer, BgpTable).
552 : //
553 488323 : BgpMembershipManager::PeerRibState *BgpMembershipManager::FindPeerRibState(
554 : const IPeer *peer, const BgpTable *table) {
555 488323 : PeerState *ps = FindPeerState(peer);
556 488313 : RibState *rs = FindRibState(table);
557 488311 : return (ps && rs ? ps->FindPeerRibState(rs) : NULL);
558 : }
559 :
560 : //
561 : // Find the PeerRibState for given (IPeer, BgpTable).
562 : // Const version.
563 : //
564 : const BgpMembershipManager::PeerRibState *
565 396398 : BgpMembershipManager::FindPeerRibState(
566 : const IPeer *peer, const BgpTable *table) const {
567 396398 : const PeerState *ps = FindPeerState(peer);
568 396369 : const RibState *rs = FindRibState(table);
569 396366 : return (ps && rs ? ps->FindPeerRibState(rs) : NULL);
570 : }
571 :
572 : //
573 : // Destroy the given PeerRibState.
574 : // Also destroy the PeerState and/or RibState if they are no longer required.
575 : //
576 79505 : void BgpMembershipManager::DestroyPeerRibState(PeerRibState *prs) {
577 79505 : PeerState *ps = prs->peer_state();
578 79505 : RibState *rs = prs->rib_state();
579 79505 : if (ps->RemovePeerRibState(prs))
580 8669 : DestroyPeerState(ps);
581 79505 : if (rs->RemovePeerRibState(prs))
582 31265 : DestroyRibState(rs);
583 79505 : delete prs;
584 79505 : }
585 :
586 : //
587 : // Trigger REGISTER_RIB_COMPLETE event.
588 : //
589 81623 : void BgpMembershipManager::TriggerRegisterRibCompleteEvent(IPeer *peer,
590 : BgpTable *table) {
591 81623 : Event *event = new Event(REGISTER_RIB_COMPLETE, peer, table);
592 81623 : EnqueueEvent(event);
593 81623 : }
594 :
595 : //
596 : // Trigger UNREGISTER_RIB_COMPLETE event.
597 : //
598 81663 : void BgpMembershipManager::TriggerUnregisterRibCompleteEvent(IPeer *peer,
599 : BgpTable *table) {
600 81663 : Event *event = new Event(UNREGISTER_RIB_COMPLETE, peer, table);
601 81663 : EnqueueEvent(event);
602 81663 : }
603 :
604 : //
605 : // Trigger WALK_RIB_COMPLETE event.
606 : //
607 5918 : void BgpMembershipManager::TriggerWalkRibCompleteEvent(IPeer *peer,
608 : BgpTable *table) {
609 5918 : Event *event = new Event(WALK_RIB_COMPLETE, peer, table);
610 5918 : EnqueueEvent(event);
611 5918 : }
612 :
613 : //
614 : // Process REGISTER_RIB event.
615 : //
616 81663 : void BgpMembershipManager::ProcessRegisterRibEvent(Event *event) {
617 81663 : IPeer *peer = event->peer;
618 81663 : BgpTable *table = event->table;
619 81663 : PeerRibState *prs = FindPeerRibState(peer, table);
620 81663 : assert(prs && prs->action() == RIBOUT_ADD);
621 81663 : assert(prs->ribin_registered());
622 81663 : prs->set_instance_id(event->instance_id);
623 :
624 : // Notify completion right away if the table is marked for deletion.
625 : // Mark the ribout as registered even though no RibOut gets created.
626 : // The unregister code path handles a PeerRibState without a RibOut.
627 81663 : if (table->IsDeleted()) {
628 40 : prs->set_ribout_registered(true);
629 40 : prs->clear_action();
630 40 : peer->MembershipRequestCallback(table);
631 40 : current_jobs_count_--;
632 40 : return;
633 : }
634 :
635 81623 : prs->RegisterRibOut(event->policy);
636 117868 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
637 : table, "Register table requested for action " << prs->action());
638 : }
639 :
640 :
641 : //
642 : // Process REGISTER_RIB_COMPLETE event.
643 : //
644 81623 : void BgpMembershipManager::ProcessRegisterRibCompleteEvent(Event *event) {
645 81623 : IPeer *peer = event->peer;
646 81623 : BgpTable *table = event->table;
647 81623 : PeerRibState *prs = FindPeerRibState(peer, table);
648 81623 : assert(prs && prs->action() == RIBOUT_ADD);
649 81623 : assert(prs->ribin_registered());
650 81623 : assert(prs->ribout_registered());
651 117868 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
652 : table, "Register table completed for action " << prs->action());
653 81623 : prs->clear_action();
654 81623 : peer->MembershipRequestCallback(table);
655 81623 : NotifyPeerRegistration(peer, table, false);
656 81623 : current_jobs_count_--;
657 81623 : }
658 :
659 : //
660 : // Process UNREGISTER_RIB event.
661 : //
662 81663 : void BgpMembershipManager::ProcessUnregisterRibEvent(Event *event) {
663 81663 : IPeer *peer = event->peer;
664 81663 : BgpTable *table = event->table;
665 81663 : PeerRibState *prs = FindPeerRibState(peer, table);
666 81663 : assert(prs);
667 81663 : assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
668 : prs->action() == RIBIN_WALK_RIBOUT_DELETE);
669 81663 : if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
670 77357 : assert(!prs->ribin_registered());
671 81663 : if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
672 4306 : assert(prs->ribin_registered());
673 81663 : assert(prs->ribout_registered());
674 :
675 81663 : prs->DeactivateRibOut();
676 117988 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
677 : table, "Unregister table requested for action " << prs->action());
678 81663 : }
679 :
680 : //
681 : // Process UNREGISTER_RIB_COMPLETE event.
682 : //
683 81663 : void BgpMembershipManager::ProcessUnregisterRibCompleteEvent(Event *event) {
684 81663 : IPeer *peer = event->peer;
685 81663 : BgpTable *table = event->table;
686 81663 : PeerRibState *prs = FindPeerRibState(peer, table);
687 81663 : assert(prs);
688 81663 : assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
689 : prs->action() == RIBIN_WALK_RIBOUT_DELETE);
690 81663 : if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
691 77357 : assert(!prs->ribin_registered());
692 81663 : if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
693 4306 : assert(prs->ribin_registered());
694 :
695 81663 : prs->UnregisterRibOut();
696 117988 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
697 : table, "Unregister table completed for action " << prs->action());
698 81663 : prs->clear_action();
699 81663 : if (!prs->ribin_registered() && !prs->ribout_registered())
700 77357 : DestroyPeerRibState(prs);
701 :
702 81663 : peer->MembershipRequestCallback(table);
703 81663 : NotifyPeerRegistration(peer, table, true);
704 81663 : current_jobs_count_--;
705 81663 : }
706 :
707 : //
708 : // Process WALK_RIB_COMPLETE event.
709 : //
710 5918 : void BgpMembershipManager::ProcessWalkRibCompleteEvent(Event *event) {
711 5918 : IPeer *peer = event->peer;
712 5918 : BgpTable *table = event->table;
713 5918 : PeerRibState *prs = FindPeerRibState(peer, table);
714 5918 : assert(prs);
715 5918 : assert(prs->action() == RIBIN_WALK || prs->action() == RIBIN_DELETE);
716 5918 : if (prs->action() == RIBIN_WALK) {
717 3770 : assert(prs->ribin_registered());
718 9555 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
719 : table, "Walk table completed for action " << prs->action());
720 : } else {
721 2148 : assert(!prs->ribin_registered());
722 5943 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
723 : table, "Unregister table completed for action " << prs->action());
724 : }
725 5918 : prs->clear_action();
726 5918 : if (!prs->ribin_registered() && !prs->ribout_registered())
727 2148 : DestroyPeerRibState(prs);
728 5918 : peer->MembershipRequestCallback(table);
729 5918 : current_jobs_count_--;
730 5918 : }
731 :
732 : //
733 : // Internal handler for an Event.
734 : // Exists so that test code can override it.
735 : //
736 332530 : bool BgpMembershipManager::EventCallbackInternal(Event *event) {
737 332530 : switch (event->event_type) {
738 81663 : case REGISTER_RIB:
739 81663 : ProcessRegisterRibEvent(event);
740 81663 : break;
741 81623 : case REGISTER_RIB_COMPLETE:
742 81623 : ProcessRegisterRibCompleteEvent(event);
743 81623 : break;
744 81663 : case UNREGISTER_RIB:
745 81663 : ProcessUnregisterRibEvent(event);
746 81663 : break;
747 81663 : case UNREGISTER_RIB_COMPLETE:
748 81663 : ProcessUnregisterRibCompleteEvent(event);
749 81663 : break;
750 5918 : case WALK_RIB_COMPLETE:
751 5918 : ProcessWalkRibCompleteEvent(event);
752 5918 : break;
753 0 : default:
754 0 : assert(false);
755 : break;
756 : }
757 :
758 332530 : delete event;
759 332530 : return true;
760 : }
761 :
762 : //
763 : // Handler for an Event.
764 : //
765 332530 : bool BgpMembershipManager::EventCallback(Event *event) {
766 332530 : CHECK_CONCURRENCY("bgp::PeerMembership");
767 332530 : return EventCallbackInternal(event);
768 : }
769 :
770 : //
771 : // Constructor.
772 : //`
773 250867 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
774 250867 : BgpTable *table)
775 250867 : : event_type(event_type),
776 250867 : peer(peer),
777 250867 : table(table),
778 250867 : instance_id(-1) {
779 250867 : }
780 :
781 : //
782 : // Constructor.
783 : //`
784 81659 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
785 81659 : BgpTable *table, const RibExportPolicy &policy, int instance_id)
786 81659 : : event_type(event_type),
787 81659 : peer(peer),
788 81659 : table(table),
789 81659 : policy(policy),
790 81654 : instance_id(instance_id) {
791 81654 : }
792 :
793 : //
794 : // Constructor.
795 : //`
796 8667 : BgpMembershipManager::PeerState::PeerState(BgpMembershipManager *manager,
797 8667 : IPeer *peer)
798 8667 : : manager_(manager),
799 8667 : peer_(peer) {
800 8667 : }
801 :
802 : //
803 : // Destructor.
804 : //`
805 8669 : BgpMembershipManager::PeerState::~PeerState() {
806 8669 : assert(rib_map_.empty());
807 8669 : }
808 :
809 : //
810 : // Find or create the PeerRibState for given RibState.
811 : //
812 : BgpMembershipManager::PeerRibState *
813 88651 : BgpMembershipManager::PeerState::LocatePeerRibState(RibState *rs) {
814 88651 : PeerRibStateMap::iterator loc = rib_map_.find(rs);
815 88650 : if (loc == rib_map_.end()) {
816 79500 : PeerRibState *prs = new PeerRibState(manager_, this, rs);
817 79504 : rib_map_.insert(make_pair(rs, prs));
818 79505 : return prs;
819 : } else {
820 9150 : return loc->second;
821 : }
822 : }
823 :
824 : //
825 : // Find the PeerRibState for given RibState.
826 : //
827 : BgpMembershipManager::PeerRibState *
828 488309 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) {
829 488309 : PeerRibStateMap::iterator loc = rib_map_.find(rs);
830 488309 : return (loc != rib_map_.end() ? loc->second : NULL);
831 : }
832 :
833 : //
834 : // Find the PeerRibState for given RibState.
835 : // Const version.
836 : //
837 : const BgpMembershipManager::PeerRibState *
838 246578 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) const {
839 246578 : PeerRibStateMap::const_iterator loc = rib_map_.find(rs);
840 246574 : return (loc != rib_map_.end() ? loc->second : NULL);
841 : }
842 :
843 : //
844 : // Remove given PeerRibState from PeerRibStateMap.
845 : // Return true if the PeerState itself can we deleted.
846 : //
847 79505 : bool BgpMembershipManager::PeerState::RemovePeerRibState(PeerRibState *prs) {
848 79505 : PeerRibStateMap::iterator loc = rib_map_.find(prs->rib_state());
849 79505 : if (loc != rib_map_.end())
850 79505 : rib_map_.erase(loc);
851 159010 : return rib_map_.empty();
852 : }
853 :
854 : //
855 : // Fill in the list of registered BgpTables.
856 : //
857 9742 : void BgpMembershipManager::PeerState::GetRegisteredRibs(
858 : list<BgpTable *> *table_list) const {
859 9742 : for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
860 93118 : loc != rib_map_.end(); ++loc) {
861 83376 : const RibState *rs = loc->first;
862 83376 : table_list->push_back(rs->table());
863 : }
864 9742 : }
865 :
866 : //
867 : // Fill introspect information.
868 : //
869 529 : void BgpMembershipManager::PeerState::FillPeerMembershipInfo(
870 : BgpNeighborResp *resp) const {
871 529 : vector<BgpNeighborRoutingTable> table_list;
872 529 : for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
873 10083 : loc != rib_map_.end(); ++loc) {
874 9554 : const RibState *rs = loc->first;
875 9554 : BgpNeighborRoutingTable table;
876 9554 : table.set_name(rs->table()->name());
877 9554 : table.set_current_state("subscribed");
878 9554 : table_list.push_back(table);
879 9554 : }
880 529 : resp->set_routing_tables(table_list);
881 529 : }
882 :
883 : //
884 : // Constructor.
885 : //
886 31263 : BgpMembershipManager::RibState::RibState(BgpMembershipManager *manager,
887 31263 : BgpTable *table)
888 31263 : : manager_(manager),
889 31263 : table_(table),
890 31263 : request_count_(0),
891 31263 : walk_count_(0),
892 31263 : table_delete_ref_(this, table->deleter()) {
893 31264 : }
894 :
895 : //
896 : // Destructor.
897 : //
898 31265 : BgpMembershipManager::RibState::~RibState() {
899 31265 : assert(peer_rib_list_.empty());
900 31265 : assert(pending_peer_rib_list_.empty());
901 31265 : }
902 :
903 : //
904 : // Enqueue given PeerRibState into the pending PeerRibStateList.
905 : //
906 169164 : void BgpMembershipManager::RibState::EnqueuePeerRibState(PeerRibState *prs) {
907 169164 : request_count_++;
908 169164 : pending_peer_rib_list_.insert(prs);
909 169164 : manager_->EnqueueRibState(this);
910 169164 : }
911 :
912 : //
913 : // Clear the pending PeerRibStateList.
914 : //
915 129566 : void BgpMembershipManager::RibState::ClearPeerRibStateList() {
916 129566 : pending_peer_rib_list_.clear();
917 129566 : }
918 :
919 : //
920 : // Insert given PeerRibState into the regular PeerRibStateList.
921 : //
922 88655 : void BgpMembershipManager::RibState::InsertPeerRibState(PeerRibState *prs) {
923 88655 : peer_rib_list_.insert(prs);
924 88659 : }
925 :
926 : //
927 : // Remove given PeerRibState from the regular PeerRibStateList.
928 : //
929 79505 : bool BgpMembershipManager::RibState::RemovePeerRibState(PeerRibState *prs) {
930 79505 : peer_rib_list_.erase(prs);
931 79505 : return peer_rib_list_.empty();
932 : }
933 :
934 : //
935 : // Fill introspect information.
936 : //
937 980 : void BgpMembershipManager::RibState::FillRoutingInstanceTableInfo(
938 : ShowRoutingInstanceTable *srit) const {
939 980 : ShowTableMembershipInfo stmi;
940 980 : stmi.set_requests(request_count_);
941 980 : stmi.set_walks(walk_count_);
942 980 : vector<ShowMembershipPeerInfo> peers;
943 980 : for (PeerRibList::const_iterator it = peer_rib_list_.begin();
944 2940 : it != peer_rib_list_.end(); ++it) {
945 1960 : const PeerRibState *prs = *it;
946 1960 : ShowMembershipPeerInfo smpi;
947 1960 : prs->FillMembershipInfo(&smpi);
948 1960 : peers.push_back(smpi);
949 1960 : }
950 980 : stmi.set_peers(peers);
951 980 : srit->set_membership(stmi);
952 980 : }
953 :
954 : //
955 : // Constructor.
956 : //
957 79504 : BgpMembershipManager::PeerRibState::PeerRibState(BgpMembershipManager *manager,
958 79504 : PeerState *ps, RibState *rs)
959 79504 : : manager_(manager),
960 79504 : ps_(ps),
961 79504 : rs_(rs),
962 79504 : ribout_(NULL),
963 79504 : ribout_index_(-1),
964 79504 : action_(BgpMembershipManager::NONE),
965 79504 : ribin_registered_(false),
966 79504 : ribout_registered_(false),
967 79504 : instance_id_(-1),
968 79504 : subscription_gen_id_(0) {
969 79504 : }
970 :
971 : //
972 : // Destructor.
973 : //
974 79505 : BgpMembershipManager::PeerRibState::~PeerRibState() {
975 79505 : assert(!ribout_);
976 79505 : assert(ribout_index_ == -1);
977 79505 : assert(action_ == BgpMembershipManager::NONE);
978 79505 : assert(!ribin_registered_);
979 79505 : assert(!ribout_registered_);
980 79505 : assert(instance_id_ == -1);
981 79505 : assert(subscription_gen_id_ == 0);
982 79505 : }
983 :
984 : //
985 : // Create RibOut for this PeerRibState and registers the RibOut as a listener
986 : // for the BgpTable.
987 : //
988 : // Register the IPeer to the RibOut.
989 : // This PeerRibState is added to the pending PeerRibStateList of RibState
990 : // so that Join processing is handled when walking the BgpTable.
991 : //
992 81623 : void BgpMembershipManager::PeerRibState::RegisterRibOut(
993 : const RibExportPolicy &policy) {
994 81623 : CHECK_CONCURRENCY("bgp::PeerMembership");
995 :
996 81623 : BgpUpdateSender *sender = manager_->server()->update_sender();
997 81623 : ribout_ = rs_->table()->RibOutLocate(sender, policy);
998 81623 : ribout_->RegisterListener();
999 81623 : ribout_->Register(ps_->peer());
1000 81623 : ribout_index_ = ribout_->GetPeerIndex(ps_->peer());
1001 81623 : ribout_registered_ = true;
1002 81623 : rs_->EnqueuePeerRibState(this);
1003 81623 : }
1004 :
1005 : //
1006 : // Deactivate the IPeer in the RibOut.
1007 : // This ensures that the IPeer will stop exporting routes from now onwards.
1008 : //
1009 : // Note that this is called before Leave processing for the IPeer is started.
1010 : //
1011 : // Bypass the Walker and directly post an UNREGISTER_RIB_COMPLETE event if
1012 : // there's no RibOut. This happens if the table was marked deleted when the
1013 : // register was processed.
1014 : //
1015 81663 : void BgpMembershipManager::PeerRibState::DeactivateRibOut() {
1016 81663 : CHECK_CONCURRENCY("bgp::PeerMembership");
1017 81663 : if (ribout_) {
1018 81623 : ribout_->Deactivate(ps_->peer());
1019 81623 : rs_->EnqueuePeerRibState(this);
1020 : } else {
1021 40 : assert(ribout_index_ == -1);
1022 40 : ribout_registered_ = false;
1023 40 : manager_->TriggerUnregisterRibCompleteEvent(ps_->peer(), rs_->table());
1024 : }
1025 81663 : }
1026 :
1027 : //
1028 : // Unregister the IPeer from the BgpTable.
1029 : // Unregister the IPeer from the RibOut, which may result in deletion of the
1030 : // RibOut itself.
1031 : //
1032 : // Note that this is called only after Leave processing for the IPeer has been
1033 : // completed.
1034 : //
1035 81663 : void BgpMembershipManager::PeerRibState::UnregisterRibOut() {
1036 81663 : CHECK_CONCURRENCY("bgp::PeerMembership");
1037 :
1038 81663 : if (!ribout_)
1039 40 : return;
1040 81623 : assert(ribout_index_ != -1);
1041 81623 : ribout_->Unregister(ps_->peer());
1042 81623 : ribout_ = NULL;
1043 81623 : ribout_index_ = -1;
1044 81623 : ribout_registered_ = false;
1045 : }
1046 :
1047 : //
1048 : // Unregister the RibIn for the IPeer.
1049 : //
1050 2148 : void BgpMembershipManager::PeerRibState::UnregisterRibIn() {
1051 2148 : rs_->EnqueuePeerRibState(this);
1052 2148 : }
1053 :
1054 : //
1055 : // Walk the RibIn for the IPeer.
1056 : //
1057 3770 : void BgpMembershipManager::PeerRibState::WalkRibIn() {
1058 3770 : rs_->EnqueuePeerRibState(this);
1059 3770 : }
1060 :
1061 : //
1062 : // Fill introspect information.
1063 : //
1064 1960 : void BgpMembershipManager::PeerRibState::FillMembershipInfo(
1065 : ShowMembershipPeerInfo *smpi) const {
1066 1960 : smpi->set_peer(ps_->peer()->ToString());
1067 1960 : smpi->set_ribin_registered(ribin_registered_);
1068 1960 : smpi->set_ribout_registered(ribout_registered_);
1069 1960 : smpi->set_instance_id(instance_id_);
1070 1960 : smpi->set_generation_id(subscription_gen_id_);
1071 1960 : }
1072 :
1073 : //
1074 : // Constructor.
1075 : //
1076 9742 : BgpMembershipManager::Walker::Walker(BgpMembershipManager *manager)
1077 9742 : : manager_(manager),
1078 19484 : trigger_(new TaskTrigger(
1079 : boost::bind(&BgpMembershipManager::Walker::WalkTrigger, this),
1080 19484 : TaskScheduler::GetInstance()->GetTaskId("bgp::PeerMembership"), 0)),
1081 9742 : postpone_walk_(false),
1082 9742 : walk_started_(false),
1083 9742 : walk_completed_(false),
1084 9742 : rs_(NULL),
1085 9742 : rib_state_list_size_(0),
1086 19484 : ribout_state_list_size_(0) {
1087 9742 : }
1088 :
1089 : //
1090 : // Destructor.
1091 : //
1092 9742 : BgpMembershipManager::Walker::~Walker() {
1093 9742 : assert(rib_state_set_.empty());
1094 9742 : assert(rib_state_list_.empty());
1095 9742 : assert(!postpone_walk_);
1096 9742 : assert(!rs_);
1097 9742 : assert(walk_ref_ == NULL);
1098 9742 : assert(peer_rib_list_.empty());
1099 9742 : assert(peer_list_.empty());
1100 9742 : assert(ribout_state_map_.empty());
1101 9742 : assert(ribout_state_list_.empty());
1102 9742 : }
1103 :
1104 : //
1105 : // Add the given RibState to the RibStateList if it's not already present.
1106 : // Trigger processing of the RibStateList if a walk is not already in progress.
1107 : //
1108 169164 : void BgpMembershipManager::Walker::Enqueue(RibState *rs) {
1109 169164 : if (rib_state_set_.find(rs) != rib_state_set_.end())
1110 39598 : return;
1111 129566 : rib_state_set_.insert(rs);
1112 129566 : rib_state_list_.push_back(rs);
1113 129566 : rib_state_list_size_++;
1114 129566 : if (!walk_started_)
1115 118508 : trigger_->Set();
1116 : }
1117 :
1118 : //
1119 : // Return true if the Walk does not have any pending items.
1120 : //
1121 1702538 : bool BgpMembershipManager::Walker::IsQueueEmpty() const {
1122 1702538 : return (rib_state_list_.empty() && !trigger_->IsSet() && !rs_);
1123 : }
1124 :
1125 : //
1126 : // Find or create the RibOutState for given RibOut.
1127 : //
1128 : BgpMembershipManager::Walker::RibOutState *
1129 163246 : BgpMembershipManager::Walker::LocateRibOutState(RibOut *ribout) {
1130 163246 : RibOutStateMap::iterator loc = ribout_state_map_.find(ribout);
1131 163246 : if (loc == ribout_state_map_.end()) {
1132 125847 : RibOutState *ros = new RibOutState(ribout);
1133 125847 : ribout_state_map_.insert(make_pair(ribout, ros));
1134 125847 : ribout_state_list_.push_back(ros);
1135 125847 : ribout_state_list_size_++;
1136 125847 : return ros;
1137 : } else {
1138 37399 : return loc->second;
1139 : }
1140 : }
1141 :
1142 : //
1143 : // Process table walk callback from DB infrastructure.
1144 : //
1145 583774 : bool BgpMembershipManager::Walker::WalkCallback(DBTablePartBase *tpart,
1146 : DBEntryBase *db_entry) {
1147 583774 : CHECK_CONCURRENCY("db::DBTable");
1148 :
1149 : // Walk all RibOutStates and handle join/leave processing.
1150 583627 : for (RibOutStateList::iterator it = ribout_state_list_.begin();
1151 1032066 : it != ribout_state_list_.end(); ++it) {
1152 448145 : RibOutState *ros = *it;
1153 448125 : RibOut *ribout = ros->ribout();
1154 448119 : ribout->bgp_export()->Join(tpart, ros->join_bitset(), db_entry);
1155 448271 : ribout->bgp_export()->Leave(tpart, ros->leave_bitset(), db_entry);
1156 : }
1157 :
1158 : // Bail if there's no peers that need RibIn processing.
1159 583952 : if (peer_list_.empty())
1160 102286 : return true;
1161 :
1162 : // Walk through all eligible paths and notify the source peer if needed.
1163 481636 : bool notify = false;
1164 481636 : BgpRoute *route = static_cast<BgpRoute *>(db_entry);
1165 963278 : for (Route::PathList::iterator it = route->GetPathList().begin(), next = it;
1166 1855758 : it != route->GetPathList().end(); it = next) {
1167 446291 : next++;
1168 :
1169 446291 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
1170 446291 : IPeer *peer = path->GetPeer();
1171 :
1172 : // Skip resolved paths - PathResolver is responsible for them.
1173 446372 : if (path->IsResolved())
1174 346393 : continue;
1175 :
1176 : // Skip aliased paths - EvpnManager is responsible for them.
1177 444446 : if (path->IsAliased())
1178 0 : continue;
1179 :
1180 : // Skip secondary paths.
1181 444440 : if (dynamic_cast<BgpSecondaryPath *>(path))
1182 254992 : continue;
1183 :
1184 : // Skip if there's no walk requested for this IPeer.
1185 189448 : if (!peer || peer_list_.find(peer) == peer_list_.end())
1186 89493 : continue;
1187 :
1188 99880 : notify |= peer->MembershipPathCallback(tpart, route, path);
1189 : }
1190 :
1191 481401 : rs_->table()->InputCommonPostProcess(tpart, route, notify);
1192 481692 : return true;
1193 : }
1194 :
1195 : //
1196 : // Process table walk done callback from DB infrastructure.
1197 : // Just note that the walk has completed and trigger processing from the
1198 : // bgp::PeerMembership task.
1199 : //
1200 129566 : void BgpMembershipManager::Walker::WalkDoneCallback(DBTableBase *table_base) {
1201 129566 : CHECK_CONCURRENCY("db::Walker");
1202 129566 : assert(rs_->table() == table_base);
1203 129566 : walk_completed_ = true;
1204 129566 : trigger_->Set();
1205 129566 : }
1206 :
1207 : //
1208 : // Start a walk for the BgpTable corresponding to the next RibState in the
1209 : // RibStateList.
1210 : //
1211 155080 : void BgpMembershipManager::Walker::WalkStart() {
1212 155080 : CHECK_CONCURRENCY("bgp::PeerMembership");
1213 :
1214 155080 : assert(walk_ref_ == NULL);
1215 155080 : assert(!rs_);
1216 155080 : assert(peer_rib_list_.empty());
1217 155080 : assert(peer_list_.empty());
1218 155080 : assert(ribout_state_map_.empty());
1219 155080 : assert(ribout_state_list_.empty());
1220 155080 : assert(rib_state_list_size_ == rib_state_set_.size());
1221 :
1222 : // Bail if the list if empty.
1223 155080 : if (rib_state_list_.empty())
1224 25514 : return;
1225 :
1226 : // Get and remove the first RibState from the RibStateList.
1227 129566 : rs_ = rib_state_list_.front();
1228 129566 : rib_state_list_.pop_front();
1229 129566 : rib_state_list_size_--;
1230 129566 : assert(rib_state_set_.erase(rs_) == 1);
1231 :
1232 : // Process all pending PeerRibStates for chosen RibState.
1233 : // Insert the PeerRibStates into PeerRibList for post processing when
1234 : // table walk is complete.
1235 298730 : for (RibState::iterator it = rs_->begin(); it != rs_->end(); ++it) {
1236 169164 : PeerRibState *prs = *it;
1237 169164 : peer_rib_list_.insert(prs);
1238 :
1239 : // Update PeerList for RIBIN actions and RibOutStateMap for RIBOUT
1240 : // actions.
1241 169164 : switch (prs->action()) {
1242 81623 : case RIBOUT_ADD: {
1243 81623 : RibOutState *ros = LocateRibOutState(prs->ribout());
1244 81623 : ros->JoinPeer(prs->ribout_index());
1245 81623 : break;
1246 : }
1247 5918 : case RIBIN_DELETE:
1248 : case RIBIN_WALK: {
1249 5918 : IPeer *peer = prs->peer_state()->peer();
1250 5918 : peer_list_.insert(peer);
1251 5918 : break;
1252 : }
1253 81623 : case RIBIN_WALK_RIBOUT_DELETE:
1254 : case RIBIN_DELETE_RIBOUT_DELETE: {
1255 81623 : IPeer *peer = prs->peer_state()->peer();
1256 81623 : peer_list_.insert(peer);
1257 81623 : RibOutState *ros = LocateRibOutState(prs->ribout());
1258 81623 : ros->LeavePeer(prs->ribout_index());
1259 81623 : break;
1260 : }
1261 0 : default: {
1262 0 : assert(false);
1263 : break;
1264 : }
1265 : }
1266 : }
1267 :
1268 : // Clear the pending PeerRibStates in the RibState.
1269 : // This allows the RibState to accumulate new PeerRibStates for a future
1270 : // walk of it's BgpTable.
1271 129566 : rs_->ClearPeerRibStateList();
1272 :
1273 : // Start the walk.
1274 129566 : rs_->increment_walk_count();
1275 129566 : BgpTable *table = rs_->table();
1276 259132 : walk_ref_ = table->AllocWalker(
1277 : boost::bind(&BgpMembershipManager::Walker::WalkCallback, this, _1, _2),
1278 129566 : boost::bind(&BgpMembershipManager::Walker::WalkDoneCallback, this, _2));
1279 129566 : walk_started_ = true;
1280 129566 : if (!postpone_walk_)
1281 129560 : table->WalkTable(walk_ref_);
1282 : }
1283 :
1284 : //
1285 : // Finish processing of the walk of BgpTable for current RibState.
1286 : //
1287 : // The walk complete notification is handled by WalkDoneCallback but all the
1288 : // book-keeping and triggering of Events is handled by this method since it
1289 : // needs to happen in bgp::PeerMembership task.
1290 : //
1291 129566 : void BgpMembershipManager::Walker::WalkFinish() {
1292 129566 : CHECK_CONCURRENCY("bgp::PeerMembership");
1293 :
1294 129566 : assert(walk_ref_ != NULL);
1295 129566 : assert(rs_);
1296 129566 : assert(!peer_rib_list_.empty());
1297 129566 : assert(!peer_list_.empty() || !ribout_state_map_.empty());
1298 129566 : assert(rib_state_list_size_ == rib_state_set_.size());
1299 129566 : assert(ribout_state_list_size_ == ribout_state_map_.size());
1300 :
1301 129566 : BgpTable *table = rs_->table();
1302 129566 : for (PeerRibList::iterator it = peer_rib_list_.begin();
1303 298730 : it != peer_rib_list_.end(); ++it) {
1304 169164 : PeerRibState *prs = *it;
1305 169164 : IPeer *peer = prs->peer_state()->peer();
1306 :
1307 169164 : switch (prs->action()) {
1308 81623 : case RIBOUT_ADD:
1309 81623 : manager_->TriggerRegisterRibCompleteEvent(peer, table);
1310 81623 : break;
1311 5918 : case RIBIN_DELETE:
1312 : case RIBIN_WALK:
1313 5918 : manager_->TriggerWalkRibCompleteEvent(peer, table);
1314 5918 : break;
1315 81623 : case RIBIN_WALK_RIBOUT_DELETE:
1316 : case RIBIN_DELETE_RIBOUT_DELETE:
1317 81623 : manager_->TriggerUnregisterRibCompleteEvent(peer, table);
1318 81623 : break;
1319 0 : default:
1320 0 : assert(false);
1321 : break;
1322 : }
1323 : }
1324 :
1325 129566 : table->ReleaseWalker(walk_ref_);
1326 129566 : rs_ = NULL;
1327 129566 : peer_rib_list_.clear();
1328 129566 : peer_list_.clear();
1329 129566 : ribout_state_list_.clear();
1330 129566 : ribout_state_list_size_ = 0;
1331 129566 : STLDeleteElements(&ribout_state_map_);
1332 :
1333 129566 : walk_started_ = false;
1334 129566 : walk_completed_ = false;
1335 129566 : }
1336 :
1337 : //
1338 : // Handler for TaskTrigger.
1339 : // Start a new walk or finish processing for the current walk and start a new
1340 : // one.
1341 : //
1342 155080 : bool BgpMembershipManager::Walker::WalkTrigger() {
1343 155080 : CHECK_CONCURRENCY("bgp::PeerMembership");
1344 :
1345 155080 : if (!walk_started_) {
1346 25514 : assert(!walk_completed_);
1347 25514 : WalkStart();
1348 129566 : } else if (walk_completed_) {
1349 129566 : WalkFinish();
1350 129566 : WalkStart();
1351 : }
1352 155080 : return true;
1353 : }
1354 :
1355 : //
1356 : // Disable the TaskTrigger so that the Walker can accumulate RibStates in the
1357 : // RibStateList.
1358 : // Testing only.
1359 : //
1360 28 : void BgpMembershipManager::Walker::SetQueueDisable(bool value) {
1361 28 : if (value) {
1362 14 : trigger_->set_disable();
1363 : } else {
1364 14 : trigger_->set_enable();
1365 : }
1366 28 : }
1367 :
1368 : //
1369 : // Force the Walker to trigger walks that are postponed.
1370 : // Testing only.
1371 : //
1372 6 : void BgpMembershipManager::Walker::PostponeWalk() {
1373 6 : assert(!walk_started_);
1374 6 : assert(walk_ref_ == NULL);
1375 6 : postpone_walk_ = true;
1376 6 : }
1377 :
1378 : //
1379 : // Tell the DBTableWalkMgr to resume walk that was postponed previously.
1380 : // Testing only.
1381 : //
1382 6 : void BgpMembershipManager::Walker::ResumeWalk() {
1383 6 : assert(walk_started_);
1384 6 : assert(!walk_completed_);
1385 6 : assert(walk_ref_ != NULL);
1386 6 : postpone_walk_ = false;
1387 6 : BgpTable *table = rs_->table();
1388 6 : table->WalkTable(walk_ref_);
1389 6 : }
|