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