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 163190 : void BgpMembershipManager::NotifyPeerRegistration(IPeer *peer, BgpTable *table,
85 : bool unregister) {
86 163190 : CHECK_CONCURRENCY("bgp::PeerMembership");
87 :
88 163190 : if (!peer->IsXmppPeer())
89 25818 : return;
90 :
91 137372 : for (PeerRegistrationListenerList::iterator iter =
92 137372 : registration_callbacks_.begin();
93 686380 : iter != registration_callbacks_.end(); ++iter) {
94 549008 : if (*iter != NULL) {
95 549008 : PeerRegistrationCallback callback = *iter;
96 549008 : (callback)(peer, table, unregister);
97 549008 : }
98 : }
99 : }
100 :
101 81617 : bool BgpMembershipManager::AssertRegister(PeerRibState *prs, bool do_assert) {
102 81617 : if (prs->action() != NONE) {
103 1 : if (do_assert)
104 0 : assert(prs->action() == NONE);
105 1 : return false;
106 : }
107 :
108 81616 : if (prs->ribout_registered()) {
109 1 : if (do_assert)
110 0 : assert(!prs->ribout_registered());
111 1 : return false;
112 : }
113 :
114 81615 : 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 81616 : void BgpMembershipManager::Register(IPeer *peer, BgpTable *table,
120 : const RibExportPolicy &policy, int instance_id) {
121 81616 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
122 : "bgp::StateMachine", "xmpp::StateMachine");
123 :
124 81611 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
125 81617 : PeerRibState *prs = LocatePeerRibState(peer, table);
126 81617 : if (!AssertRegister(prs))
127 2 : return;
128 81615 : current_jobs_count_++;
129 81614 : total_jobs_count_++;
130 81614 : prs->set_ribin_registered(true);
131 81614 : prs->set_action(RIBOUT_ADD);
132 81613 : Event *event = new Event(REGISTER_RIB, peer, table, policy, instance_id);
133 81611 : EnqueueEvent(event);
134 81617 : }
135 :
136 6900 : bool BgpMembershipManager::AssertRegisterRibIn(PeerRibState *prs, IPeer *peer,
137 : bool do_assert) {
138 6900 : if (prs->action() != NONE) {
139 1 : if (do_assert)
140 0 : assert(prs->action() == NONE);
141 1 : return false;
142 : }
143 :
144 6899 : 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 6896 : if (prs->ribout_registered()) {
151 0 : if (do_assert)
152 0 : assert(!prs->ribout_registered());
153 0 : return false;
154 : }
155 :
156 6896 : return true;
157 : }
158 :
159 : // Synchronously register the IPeer to the BgpTable for RIBIN.
160 6900 : void BgpMembershipManager::RegisterRibIn(IPeer *peer, BgpTable *table) {
161 6900 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper",
162 : "bgp::StateMachine", "xmpp::StateMachine");
163 :
164 6899 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
165 6900 : PeerRibState *prs = LocatePeerRibState(peer, table);
166 6900 : if (!AssertRegisterRibIn(prs, peer))
167 4 : return;
168 6896 : prs->set_ribin_registered(true);
169 6900 : }
170 :
171 77579 : bool BgpMembershipManager::AssertUnregister(PeerRibState *prs, bool do_assert) {
172 77579 : if (!prs || prs->action() != NONE) {
173 4 : if (do_assert)
174 0 : assert(prs && prs->action() == NONE);
175 4 : return false;
176 : }
177 :
178 77575 : if (!prs->ribin_registered()) {
179 0 : if (do_assert)
180 0 : assert(prs->ribin_registered());
181 0 : return false;
182 : }
183 :
184 77575 : 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 77579 : void BgpMembershipManager::Unregister(IPeer *peer, BgpTable *table) {
190 77579 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
191 :
192 77579 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
193 77579 : PeerRibState *prs = FindPeerRibState(peer, table);
194 77579 : if (!AssertUnregister(prs))
195 4 : return;
196 :
197 77575 : current_jobs_count_++;
198 77575 : total_jobs_count_++;
199 :
200 77575 : if (!prs->ribout_registered()) {
201 346 : UnregisterRibInUnlocked(prs);
202 346 : return;
203 : }
204 :
205 77229 : prs->set_action(RIBIN_DELETE_RIBOUT_DELETE);
206 77229 : prs->set_ribin_registered(false);
207 77229 : prs->set_instance_id(-1);
208 77229 : prs->set_subscription_gen_id(0);
209 77229 : Event *event = new Event(UNREGISTER_RIB, peer, table);
210 77229 : EnqueueEvent(event);
211 77579 : }
212 :
213 : //
214 : // Unregister the IPeer from the BgpTable for RIBIN.
215 : //
216 1805 : void BgpMembershipManager::UnregisterRibIn(IPeer *peer, BgpTable *table) {
217 1805 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
218 :
219 1805 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
220 1805 : current_jobs_count_++;
221 1805 : total_jobs_count_++;
222 1805 : PeerRibState *prs = FindPeerRibState(peer, table);
223 1805 : assert(prs && prs->action() == NONE);
224 1805 : assert(prs->ribin_registered() && !prs->ribout_registered());
225 1805 : UnregisterRibInUnlocked(prs);
226 1805 : }
227 :
228 : //
229 : // Common routine to handle unregister of IPeer from Table for RIBIN.
230 : //
231 2151 : void BgpMembershipManager::UnregisterRibInUnlocked(PeerRibState *prs) {
232 2151 : prs->set_ribin_registered(false);
233 2151 : prs->set_instance_id(-1);
234 2151 : prs->set_subscription_gen_id(0);
235 2151 : prs->set_action(RIBIN_DELETE);
236 2151 : prs->UnregisterRibIn();
237 5946 : 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 2151 : }
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 4386 : void BgpMembershipManager::UnregisterRibOut(IPeer *peer, BgpTable *table) {
249 4386 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
250 :
251 4386 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
252 4386 : current_jobs_count_++;
253 4386 : total_jobs_count_++;
254 4386 : PeerRibState *prs = FindPeerRibState(peer, table);
255 4386 : assert(prs && prs->action() == NONE);
256 4386 : assert(prs->ribin_registered());
257 4386 : assert(prs->ribout_registered());
258 4386 : prs->set_instance_id(-1);
259 4386 : prs->set_subscription_gen_id(0);
260 4386 : prs->set_action(RIBIN_WALK_RIBOUT_DELETE);
261 4386 : Event *event = new Event(UNREGISTER_RIB, peer, table);
262 4386 : EnqueueEvent(event);
263 4386 : }
264 :
265 3829 : bool BgpMembershipManager::AssertWalkRibIn(PeerRibState *prs, bool do_assert) {
266 3829 : if (!prs || prs->action() != NONE) {
267 4 : if (do_assert)
268 0 : assert(prs && prs->action() == NONE);
269 4 : return false;
270 : }
271 :
272 3825 : if (!prs->ribin_registered()) {
273 0 : if (do_assert)
274 0 : assert(prs->ribin_registered());
275 0 : return false;
276 : }
277 :
278 3825 : 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 3829 : void BgpMembershipManager::WalkRibIn(IPeer *peer, BgpTable *table) {
287 3829 : CHECK_CONCURRENCY("bgp::Config", "bgp::StateMachine", "xmpp::StateMachine");
288 :
289 3829 : tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true);
290 3829 : PeerRibState *prs = FindPeerRibState(peer, table);
291 3829 : if (!AssertWalkRibIn(prs))
292 4 : return;
293 3825 : current_jobs_count_++;
294 3825 : total_jobs_count_++;
295 3825 : prs->set_action(RIBIN_WALK);
296 3825 : prs->WalkRibIn();
297 9647 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
298 : table, "Walk table requested for action " << prs->action());
299 3829 : }
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 101558 : bool BgpMembershipManager::GetRegistrationInfo(
306 : const IPeer *peer, const BgpTable *table,
307 : int *instance_id, uint64_t *subscription_gen_id) const {
308 101558 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
309 101561 : const PeerRibState *prs = FindPeerRibState(peer, table);
310 101532 : if (!prs)
311 33094 : return false;
312 68438 : if (instance_id)
313 68402 : *instance_id = prs->instance_id();
314 68438 : if (subscription_gen_id)
315 66894 : *subscription_gen_id = prs->subscription_gen_id();
316 68438 : return true;
317 101532 : }
318 :
319 : //
320 : // Update the registration info of the IPeer for the BgpTable.
321 : //
322 68222 : void BgpMembershipManager::SetRegistrationInfo(
323 : const IPeer *peer, const BgpTable *table,
324 : int instance_id, uint64_t subscription_gen_id) {
325 68222 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
326 68222 : PeerRibState *prs = FindPeerRibState(peer, table);
327 68217 : if (!prs)
328 0 : return;
329 68217 : prs->set_instance_id(instance_id);
330 68217 : prs->set_subscription_gen_id(subscription_gen_id);
331 68216 : }
332 :
333 : //
334 : // Return true if the IPeer is registered to the BgpTable.
335 : //
336 226909 : bool BgpMembershipManager::IsRegistered(const IPeer *peer,
337 : const BgpTable *table) const {
338 226909 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
339 226909 : const PeerRibState *prs = FindPeerRibState(peer, table);
340 453818 : return (prs && prs->ribin_registered() && prs->ribout_registered());
341 226909 : }
342 :
343 : //
344 : // Return true if the IPeer is registered to the BgpTable for RibIn.
345 : //
346 4022 : bool BgpMembershipManager::IsRibInRegistered(const IPeer *peer,
347 : const BgpTable *table) const {
348 4022 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
349 4022 : const PeerRibState *prs = FindPeerRibState(peer, table);
350 8044 : return (prs && prs->ribin_registered());
351 4022 : }
352 :
353 : //
354 : // Return true if the IPeer is registered to the BgpTable for RibOut.
355 : //
356 68198 : bool BgpMembershipManager::IsRibOutRegistered(const IPeer *peer,
357 : const BgpTable *table) const {
358 68198 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
359 68202 : const PeerRibState *prs = FindPeerRibState(peer, table);
360 136401 : return (prs && prs->ribout_registered());
361 68198 : }
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 20271 : void BgpMembershipManager::GetRegisteredRibs(const IPeer *peer,
382 : list<BgpTable *> *table_list) const {
383 20271 : tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false);
384 20271 : table_list->clear();
385 20271 : const PeerState *ps = FindPeerState(peer);
386 20271 : if (ps)
387 9852 : ps->GetRegisteredRibs(table_list);
388 20271 : }
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 1716521 : bool BgpMembershipManager::IsQueueEmpty() const {
430 1716521 : 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 88517 : BgpMembershipManager::PeerState *BgpMembershipManager::LocatePeerState(
450 : IPeer *peer) {
451 88517 : PeerStateMap::iterator loc = peer_state_map_.find(peer);
452 88512 : if (loc == peer_state_map_.end()) {
453 8647 : PeerState *ps = new PeerState(this, peer);
454 8647 : peer_state_map_.insert(make_pair(peer, ps));
455 8647 : return ps;
456 : } else {
457 79867 : return loc->second;
458 : }
459 : }
460 :
461 : //
462 : // Find the PeerState for given IPeer.
463 : //
464 488217 : BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
465 : const IPeer *peer) {
466 488217 : PeerStateMap::iterator loc = peer_state_map_.find(peer);
467 488211 : return (loc != peer_state_map_.end() ? loc->second : NULL);
468 : }
469 :
470 : //
471 : // Find the PeerState for given IPeer.
472 : // Const version.
473 : //
474 421507 : const BgpMembershipManager::PeerState *BgpMembershipManager::FindPeerState(
475 : const IPeer *peer) const {
476 421507 : PeerStateMap::const_iterator loc = peer_state_map_.find(peer);
477 421484 : return (loc != peer_state_map_.end() ? loc->second : NULL);
478 : }
479 :
480 : //
481 : // Destroy the given PeerState.
482 : //
483 8647 : void BgpMembershipManager::DestroyPeerState(PeerState *ps) {
484 8647 : peer_state_map_.erase(ps->peer());
485 8647 : delete ps;
486 8647 : }
487 :
488 : //
489 : // Find or create the RibState for given BgpTable.
490 : //
491 88514 : BgpMembershipManager::RibState *BgpMembershipManager::LocateRibState(
492 : BgpTable *table) {
493 88514 : RibStateMap::iterator loc = rib_state_map_.find(table);
494 88514 : if (loc == rib_state_map_.end()) {
495 31191 : RibState *rs = new RibState(this, table);
496 31191 : rib_state_map_.insert(make_pair(table, rs));
497 31191 : return rs;
498 : } else {
499 57324 : return loc->second;
500 : }
501 : }
502 :
503 : //
504 : // Find the RibState for given BgpTable.
505 : //
506 488211 : BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
507 : const BgpTable *table) {
508 488211 : RibStateMap::iterator loc = rib_state_map_.find(table);
509 488210 : return (loc != rib_state_map_.end() ? loc->second : NULL);
510 : }
511 :
512 : //
513 : // Find the RibState for given BgpTable.
514 : // Const version.
515 : //
516 401762 : const BgpMembershipManager::RibState *BgpMembershipManager::FindRibState(
517 : const BgpTable *table) const {
518 401762 : RibStateMap::const_iterator loc = rib_state_map_.find(table);
519 401761 : return (loc != rib_state_map_.end() ? loc->second : NULL);
520 : }
521 :
522 : //
523 : // Destroy the given RibState.
524 : //
525 31191 : void BgpMembershipManager::DestroyRibState(RibState *rs) {
526 31191 : rib_state_map_.erase(rs->table());
527 31191 : delete rs;
528 31191 : }
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 169126 : void BgpMembershipManager::EnqueueRibState(RibState *rs) {
535 169126 : walker_->Enqueue(rs);
536 169126 : }
537 :
538 : //
539 : // Find or create the PeerRibState for given (IPeer, BgpTable).
540 : //
541 88515 : BgpMembershipManager::PeerRibState *BgpMembershipManager::LocatePeerRibState(
542 : IPeer *peer, BgpTable *table) {
543 88515 : PeerState *ps = LocatePeerState(peer);
544 88514 : RibState *rs = LocateRibState(table);
545 88514 : PeerRibState *prs = ps->LocatePeerRibState(rs);
546 88515 : rs->InsertPeerRibState(prs);
547 88517 : return prs;
548 : }
549 :
550 : //
551 : // Find the PeerRibState for given (IPeer, BgpTable).
552 : //
553 488217 : BgpMembershipManager::PeerRibState *BgpMembershipManager::FindPeerRibState(
554 : const IPeer *peer, const BgpTable *table) {
555 488217 : PeerState *ps = FindPeerState(peer);
556 488211 : RibState *rs = FindRibState(table);
557 488211 : 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 400694 : BgpMembershipManager::FindPeerRibState(
566 : const IPeer *peer, const BgpTable *table) const {
567 400694 : const PeerState *ps = FindPeerState(peer);
568 400669 : const RibState *rs = FindRibState(table);
569 400666 : 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 79380 : void BgpMembershipManager::DestroyPeerRibState(PeerRibState *prs) {
577 79380 : PeerState *ps = prs->peer_state();
578 79380 : RibState *rs = prs->rib_state();
579 79380 : if (ps->RemovePeerRibState(prs))
580 8647 : DestroyPeerState(ps);
581 79380 : if (rs->RemovePeerRibState(prs))
582 31191 : DestroyRibState(rs);
583 79380 : delete prs;
584 79380 : }
585 :
586 : //
587 : // Trigger REGISTER_RIB_COMPLETE event.
588 : //
589 81575 : void BgpMembershipManager::TriggerRegisterRibCompleteEvent(IPeer *peer,
590 : BgpTable *table) {
591 81575 : Event *event = new Event(REGISTER_RIB_COMPLETE, peer, table);
592 81575 : EnqueueEvent(event);
593 81575 : }
594 :
595 : //
596 : // Trigger UNREGISTER_RIB_COMPLETE event.
597 : //
598 81615 : void BgpMembershipManager::TriggerUnregisterRibCompleteEvent(IPeer *peer,
599 : BgpTable *table) {
600 81615 : Event *event = new Event(UNREGISTER_RIB_COMPLETE, peer, table);
601 81615 : EnqueueEvent(event);
602 81615 : }
603 :
604 : //
605 : // Trigger WALK_RIB_COMPLETE event.
606 : //
607 5976 : void BgpMembershipManager::TriggerWalkRibCompleteEvent(IPeer *peer,
608 : BgpTable *table) {
609 5976 : Event *event = new Event(WALK_RIB_COMPLETE, peer, table);
610 5976 : EnqueueEvent(event);
611 5976 : }
612 :
613 : //
614 : // Process REGISTER_RIB event.
615 : //
616 81615 : void BgpMembershipManager::ProcessRegisterRibEvent(Event *event) {
617 81615 : IPeer *peer = event->peer;
618 81615 : BgpTable *table = event->table;
619 81615 : PeerRibState *prs = FindPeerRibState(peer, table);
620 81615 : assert(prs && prs->action() == RIBOUT_ADD);
621 81615 : assert(prs->ribin_registered());
622 81615 : 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 81615 : 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 81575 : prs->RegisterRibOut(event->policy);
636 117866 : 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 81575 : void BgpMembershipManager::ProcessRegisterRibCompleteEvent(Event *event) {
645 81575 : IPeer *peer = event->peer;
646 81575 : BgpTable *table = event->table;
647 81575 : PeerRibState *prs = FindPeerRibState(peer, table);
648 81575 : assert(prs && prs->action() == RIBOUT_ADD);
649 81575 : assert(prs->ribin_registered());
650 81575 : assert(prs->ribout_registered());
651 117866 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
652 : table, "Register table completed for action " << prs->action());
653 81575 : prs->clear_action();
654 81575 : peer->MembershipRequestCallback(table);
655 81575 : NotifyPeerRegistration(peer, table, false);
656 81575 : current_jobs_count_--;
657 81575 : }
658 :
659 : //
660 : // Process UNREGISTER_RIB event.
661 : //
662 81615 : void BgpMembershipManager::ProcessUnregisterRibEvent(Event *event) {
663 81615 : IPeer *peer = event->peer;
664 81615 : BgpTable *table = event->table;
665 81615 : PeerRibState *prs = FindPeerRibState(peer, table);
666 81615 : assert(prs);
667 81615 : assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
668 : prs->action() == RIBIN_WALK_RIBOUT_DELETE);
669 81615 : if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
670 77229 : assert(!prs->ribin_registered());
671 81615 : if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
672 4386 : assert(prs->ribin_registered());
673 81615 : assert(prs->ribout_registered());
674 :
675 81615 : prs->DeactivateRibOut();
676 117986 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
677 : table, "Unregister table requested for action " << prs->action());
678 81615 : }
679 :
680 : //
681 : // Process UNREGISTER_RIB_COMPLETE event.
682 : //
683 81615 : void BgpMembershipManager::ProcessUnregisterRibCompleteEvent(Event *event) {
684 81615 : IPeer *peer = event->peer;
685 81615 : BgpTable *table = event->table;
686 81615 : PeerRibState *prs = FindPeerRibState(peer, table);
687 81615 : assert(prs);
688 81615 : assert(prs->action() == RIBIN_DELETE_RIBOUT_DELETE ||
689 : prs->action() == RIBIN_WALK_RIBOUT_DELETE);
690 81615 : if (prs->action() == RIBIN_DELETE_RIBOUT_DELETE)
691 77229 : assert(!prs->ribin_registered());
692 81615 : if (prs->action() == RIBIN_WALK_RIBOUT_DELETE)
693 4386 : assert(prs->ribin_registered());
694 :
695 81615 : prs->UnregisterRibOut();
696 117986 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
697 : table, "Unregister table completed for action " << prs->action());
698 81615 : prs->clear_action();
699 81615 : if (!prs->ribin_registered() && !prs->ribout_registered())
700 77229 : DestroyPeerRibState(prs);
701 :
702 81615 : peer->MembershipRequestCallback(table);
703 81615 : NotifyPeerRegistration(peer, table, true);
704 81615 : current_jobs_count_--;
705 81615 : }
706 :
707 : //
708 : // Process WALK_RIB_COMPLETE event.
709 : //
710 5976 : void BgpMembershipManager::ProcessWalkRibCompleteEvent(Event *event) {
711 5976 : IPeer *peer = event->peer;
712 5976 : BgpTable *table = event->table;
713 5976 : PeerRibState *prs = FindPeerRibState(peer, table);
714 5976 : assert(prs);
715 5976 : assert(prs->action() == RIBIN_WALK || prs->action() == RIBIN_DELETE);
716 5976 : if (prs->action() == RIBIN_WALK) {
717 3825 : assert(prs->ribin_registered());
718 9647 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
719 : table, "Walk table completed for action " << prs->action());
720 : } else {
721 2151 : assert(!prs->ribin_registered());
722 5946 : BGP_LOG_PEER_TABLE(peer, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_SYSLOG,
723 : table, "Unregister table completed for action " << prs->action());
724 : }
725 5976 : prs->clear_action();
726 5976 : if (!prs->ribin_registered() && !prs->ribout_registered())
727 2151 : DestroyPeerRibState(prs);
728 5976 : peer->MembershipRequestCallback(table);
729 5976 : current_jobs_count_--;
730 5976 : }
731 :
732 : //
733 : // Internal handler for an Event.
734 : // Exists so that test code can override it.
735 : //
736 332396 : bool BgpMembershipManager::EventCallbackInternal(Event *event) {
737 332396 : switch (event->event_type) {
738 81615 : case REGISTER_RIB:
739 81615 : ProcessRegisterRibEvent(event);
740 81615 : break;
741 81575 : case REGISTER_RIB_COMPLETE:
742 81575 : ProcessRegisterRibCompleteEvent(event);
743 81575 : break;
744 81615 : case UNREGISTER_RIB:
745 81615 : ProcessUnregisterRibEvent(event);
746 81615 : break;
747 81615 : case UNREGISTER_RIB_COMPLETE:
748 81615 : ProcessUnregisterRibCompleteEvent(event);
749 81615 : break;
750 5976 : case WALK_RIB_COMPLETE:
751 5976 : ProcessWalkRibCompleteEvent(event);
752 5976 : break;
753 0 : default:
754 0 : assert(false);
755 : break;
756 : }
757 :
758 332396 : delete event;
759 332396 : return true;
760 : }
761 :
762 : //
763 : // Handler for an Event.
764 : //
765 332396 : bool BgpMembershipManager::EventCallback(Event *event) {
766 332396 : CHECK_CONCURRENCY("bgp::PeerMembership");
767 332396 : return EventCallbackInternal(event);
768 : }
769 :
770 : //
771 : // Constructor.
772 : //`
773 250781 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
774 250781 : BgpTable *table)
775 250781 : : event_type(event_type),
776 250781 : peer(peer),
777 250781 : table(table),
778 250781 : instance_id(-1) {
779 250781 : }
780 :
781 : //
782 : // Constructor.
783 : //`
784 81615 : BgpMembershipManager::Event::Event(EventType event_type, IPeer *peer,
785 81615 : BgpTable *table, const RibExportPolicy &policy, int instance_id)
786 81615 : : event_type(event_type),
787 81615 : peer(peer),
788 81615 : table(table),
789 81615 : policy(policy),
790 81611 : instance_id(instance_id) {
791 81611 : }
792 :
793 : //
794 : // Constructor.
795 : //`
796 8647 : BgpMembershipManager::PeerState::PeerState(BgpMembershipManager *manager,
797 8647 : IPeer *peer)
798 8647 : : manager_(manager),
799 8647 : peer_(peer) {
800 8647 : }
801 :
802 : //
803 : // Destructor.
804 : //`
805 8647 : BgpMembershipManager::PeerState::~PeerState() {
806 8647 : assert(rib_map_.empty());
807 8647 : }
808 :
809 : //
810 : // Find or create the PeerRibState for given RibState.
811 : //
812 : BgpMembershipManager::PeerRibState *
813 88514 : BgpMembershipManager::PeerState::LocatePeerRibState(RibState *rs) {
814 88514 : PeerRibStateMap::iterator loc = rib_map_.find(rs);
815 88513 : if (loc == rib_map_.end()) {
816 79376 : PeerRibState *prs = new PeerRibState(manager_, this, rs);
817 79376 : rib_map_.insert(make_pair(rs, prs));
818 79379 : return prs;
819 : } else {
820 9136 : return loc->second;
821 : }
822 : }
823 :
824 : //
825 : // Find the PeerRibState for given RibState.
826 : //
827 : BgpMembershipManager::PeerRibState *
828 488209 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) {
829 488209 : PeerRibStateMap::iterator loc = rib_map_.find(rs);
830 488210 : 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 247045 : BgpMembershipManager::PeerState::FindPeerRibState(const RibState *rs) const {
839 247045 : PeerRibStateMap::const_iterator loc = rib_map_.find(rs);
840 247055 : 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 79380 : bool BgpMembershipManager::PeerState::RemovePeerRibState(PeerRibState *prs) {
848 79380 : PeerRibStateMap::iterator loc = rib_map_.find(prs->rib_state());
849 79380 : if (loc != rib_map_.end())
850 79380 : rib_map_.erase(loc);
851 158760 : return rib_map_.empty();
852 : }
853 :
854 : //
855 : // Fill in the list of registered BgpTables.
856 : //
857 9852 : void BgpMembershipManager::PeerState::GetRegisteredRibs(
858 : list<BgpTable *> *table_list) const {
859 9852 : for (PeerRibStateMap::const_iterator loc = rib_map_.begin();
860 93241 : loc != rib_map_.end(); ++loc) {
861 83389 : const RibState *rs = loc->first;
862 83389 : table_list->push_back(rs->table());
863 : }
864 9852 : }
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 31191 : BgpMembershipManager::RibState::RibState(BgpMembershipManager *manager,
887 31191 : BgpTable *table)
888 31191 : : manager_(manager),
889 31191 : table_(table),
890 31191 : request_count_(0),
891 31191 : walk_count_(0),
892 31191 : table_delete_ref_(this, table->deleter()) {
893 31191 : }
894 :
895 : //
896 : // Destructor.
897 : //
898 31191 : BgpMembershipManager::RibState::~RibState() {
899 31191 : assert(peer_rib_list_.empty());
900 31191 : assert(pending_peer_rib_list_.empty());
901 31191 : }
902 :
903 : //
904 : // Enqueue given PeerRibState into the pending PeerRibStateList.
905 : //
906 169126 : void BgpMembershipManager::RibState::EnqueuePeerRibState(PeerRibState *prs) {
907 169126 : request_count_++;
908 169126 : pending_peer_rib_list_.insert(prs);
909 169126 : manager_->EnqueueRibState(this);
910 169126 : }
911 :
912 : //
913 : // Clear the pending PeerRibStateList.
914 : //
915 130530 : void BgpMembershipManager::RibState::ClearPeerRibStateList() {
916 130530 : pending_peer_rib_list_.clear();
917 130530 : }
918 :
919 : //
920 : // Insert given PeerRibState into the regular PeerRibStateList.
921 : //
922 88515 : void BgpMembershipManager::RibState::InsertPeerRibState(PeerRibState *prs) {
923 88515 : peer_rib_list_.insert(prs);
924 88517 : }
925 :
926 : //
927 : // Remove given PeerRibState from the regular PeerRibStateList.
928 : //
929 79380 : bool BgpMembershipManager::RibState::RemovePeerRibState(PeerRibState *prs) {
930 79380 : peer_rib_list_.erase(prs);
931 79380 : 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 79377 : BgpMembershipManager::PeerRibState::PeerRibState(BgpMembershipManager *manager,
958 79377 : PeerState *ps, RibState *rs)
959 79377 : : manager_(manager),
960 79377 : ps_(ps),
961 79377 : rs_(rs),
962 79377 : ribout_(NULL),
963 79377 : ribout_index_(-1),
964 79377 : action_(BgpMembershipManager::NONE),
965 79377 : ribin_registered_(false),
966 79377 : ribout_registered_(false),
967 79377 : instance_id_(-1),
968 79377 : subscription_gen_id_(0) {
969 79377 : }
970 :
971 : //
972 : // Destructor.
973 : //
974 79380 : BgpMembershipManager::PeerRibState::~PeerRibState() {
975 79380 : assert(!ribout_);
976 79380 : assert(ribout_index_ == -1);
977 79380 : assert(action_ == BgpMembershipManager::NONE);
978 79380 : assert(!ribin_registered_);
979 79380 : assert(!ribout_registered_);
980 79380 : assert(instance_id_ == -1);
981 79380 : assert(subscription_gen_id_ == 0);
982 79380 : }
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 81575 : void BgpMembershipManager::PeerRibState::RegisterRibOut(
993 : const RibExportPolicy &policy) {
994 81575 : CHECK_CONCURRENCY("bgp::PeerMembership");
995 :
996 81575 : BgpUpdateSender *sender = manager_->server()->update_sender();
997 81575 : ribout_ = rs_->table()->RibOutLocate(sender, policy);
998 81575 : ribout_->RegisterListener();
999 81575 : ribout_->Register(ps_->peer());
1000 81575 : ribout_index_ = ribout_->GetPeerIndex(ps_->peer());
1001 81575 : ribout_registered_ = true;
1002 81575 : rs_->EnqueuePeerRibState(this);
1003 81575 : }
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 81615 : void BgpMembershipManager::PeerRibState::DeactivateRibOut() {
1016 81615 : CHECK_CONCURRENCY("bgp::PeerMembership");
1017 81615 : if (ribout_) {
1018 81575 : ribout_->Deactivate(ps_->peer());
1019 81575 : 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 81615 : }
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 81615 : void BgpMembershipManager::PeerRibState::UnregisterRibOut() {
1036 81615 : CHECK_CONCURRENCY("bgp::PeerMembership");
1037 :
1038 81615 : if (!ribout_)
1039 40 : return;
1040 81575 : assert(ribout_index_ != -1);
1041 81575 : ribout_->Unregister(ps_->peer());
1042 81575 : ribout_ = NULL;
1043 81575 : ribout_index_ = -1;
1044 81575 : ribout_registered_ = false;
1045 : }
1046 :
1047 : //
1048 : // Unregister the RibIn for the IPeer.
1049 : //
1050 2151 : void BgpMembershipManager::PeerRibState::UnregisterRibIn() {
1051 2151 : rs_->EnqueuePeerRibState(this);
1052 2151 : }
1053 :
1054 : //
1055 : // Walk the RibIn for the IPeer.
1056 : //
1057 3825 : void BgpMembershipManager::PeerRibState::WalkRibIn() {
1058 3825 : rs_->EnqueuePeerRibState(this);
1059 3825 : }
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 169126 : void BgpMembershipManager::Walker::Enqueue(RibState *rs) {
1109 169126 : if (rib_state_set_.find(rs) != rib_state_set_.end())
1110 38596 : return;
1111 130530 : rib_state_set_.insert(rs);
1112 130530 : rib_state_list_.push_back(rs);
1113 130530 : rib_state_list_size_++;
1114 130530 : if (!walk_started_)
1115 120819 : trigger_->Set();
1116 : }
1117 :
1118 : //
1119 : // Return true if the Walk does not have any pending items.
1120 : //
1121 1698693 : bool BgpMembershipManager::Walker::IsQueueEmpty() const {
1122 1698693 : 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 163150 : BgpMembershipManager::Walker::LocateRibOutState(RibOut *ribout) {
1130 163150 : RibOutStateMap::iterator loc = ribout_state_map_.find(ribout);
1131 163150 : if (loc == ribout_state_map_.end()) {
1132 126621 : RibOutState *ros = new RibOutState(ribout);
1133 126621 : ribout_state_map_.insert(make_pair(ribout, ros));
1134 126621 : ribout_state_list_.push_back(ros);
1135 126621 : ribout_state_list_size_++;
1136 126621 : return ros;
1137 : } else {
1138 36529 : return loc->second;
1139 : }
1140 : }
1141 :
1142 : //
1143 : // Process table walk callback from DB infrastructure.
1144 : //
1145 594094 : bool BgpMembershipManager::Walker::WalkCallback(DBTablePartBase *tpart,
1146 : DBEntryBase *db_entry) {
1147 594094 : CHECK_CONCURRENCY("db::DBTable");
1148 :
1149 : // Walk all RibOutStates and handle join/leave processing.
1150 594019 : for (RibOutStateList::iterator it = ribout_state_list_.begin();
1151 1049767 : it != ribout_state_list_.end(); ++it) {
1152 455468 : RibOutState *ros = *it;
1153 455458 : RibOut *ribout = ros->ribout();
1154 455445 : ribout->bgp_export()->Join(tpart, ros->join_bitset(), db_entry);
1155 455618 : ribout->bgp_export()->Leave(tpart, ros->leave_bitset(), db_entry);
1156 : }
1157 :
1158 : // Bail if there's no peers that need RibIn processing.
1159 594326 : if (peer_list_.empty())
1160 102766 : return true;
1161 :
1162 : // Walk through all eligible paths and notify the source peer if needed.
1163 491550 : bool notify = false;
1164 491550 : BgpRoute *route = static_cast<BgpRoute *>(db_entry);
1165 983094 : for (Route::PathList::iterator it = route->GetPathList().begin(), next = it;
1166 1910651 : it != route->GetPathList().end(); it = next) {
1167 463862 : next++;
1168 :
1169 463862 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
1170 463862 : IPeer *peer = path->GetPeer();
1171 :
1172 : // Skip resolved paths - PathResolver is responsible for them.
1173 463903 : if (path->IsResolved())
1174 363024 : continue;
1175 :
1176 : // Skip aliased paths - EvpnManager is responsible for them.
1177 462090 : if (path->IsAliased())
1178 0 : continue;
1179 :
1180 : // Skip secondary paths.
1181 462082 : if (dynamic_cast<BgpSecondaryPath *>(path))
1182 270216 : continue;
1183 :
1184 : // Skip if there's no walk requested for this IPeer.
1185 191866 : if (!peer || peer_list_.find(peer) == peer_list_.end())
1186 90999 : continue;
1187 :
1188 100790 : notify |= peer->MembershipPathCallback(tpart, route, path);
1189 : }
1190 :
1191 491308 : rs_->table()->InputCommonPostProcess(tpart, route, notify);
1192 491601 : 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 130530 : void BgpMembershipManager::Walker::WalkDoneCallback(DBTableBase *table_base) {
1201 130530 : CHECK_CONCURRENCY("db::Walker");
1202 130530 : assert(rs_->table() == table_base);
1203 130530 : walk_completed_ = true;
1204 130530 : trigger_->Set();
1205 130530 : }
1206 :
1207 : //
1208 : // Start a walk for the BgpTable corresponding to the next RibState in the
1209 : // RibStateList.
1210 : //
1211 156783 : void BgpMembershipManager::Walker::WalkStart() {
1212 156783 : CHECK_CONCURRENCY("bgp::PeerMembership");
1213 :
1214 156783 : assert(walk_ref_ == NULL);
1215 156783 : assert(!rs_);
1216 156783 : assert(peer_rib_list_.empty());
1217 156783 : assert(peer_list_.empty());
1218 156783 : assert(ribout_state_map_.empty());
1219 156783 : assert(ribout_state_list_.empty());
1220 156783 : assert(rib_state_list_size_ == rib_state_set_.size());
1221 :
1222 : // Bail if the list if empty.
1223 156783 : if (rib_state_list_.empty())
1224 26253 : return;
1225 :
1226 : // Get and remove the first RibState from the RibStateList.
1227 130530 : rs_ = rib_state_list_.front();
1228 130530 : rib_state_list_.pop_front();
1229 130530 : rib_state_list_size_--;
1230 130530 : 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 299656 : for (RibState::iterator it = rs_->begin(); it != rs_->end(); ++it) {
1236 169126 : PeerRibState *prs = *it;
1237 169126 : peer_rib_list_.insert(prs);
1238 :
1239 : // Update PeerList for RIBIN actions and RibOutStateMap for RIBOUT
1240 : // actions.
1241 169126 : switch (prs->action()) {
1242 81575 : case RIBOUT_ADD: {
1243 81575 : RibOutState *ros = LocateRibOutState(prs->ribout());
1244 81575 : ros->JoinPeer(prs->ribout_index());
1245 81575 : break;
1246 : }
1247 5976 : case RIBIN_DELETE:
1248 : case RIBIN_WALK: {
1249 5976 : IPeer *peer = prs->peer_state()->peer();
1250 5976 : peer_list_.insert(peer);
1251 5976 : break;
1252 : }
1253 81575 : case RIBIN_WALK_RIBOUT_DELETE:
1254 : case RIBIN_DELETE_RIBOUT_DELETE: {
1255 81575 : IPeer *peer = prs->peer_state()->peer();
1256 81575 : peer_list_.insert(peer);
1257 81575 : RibOutState *ros = LocateRibOutState(prs->ribout());
1258 81575 : ros->LeavePeer(prs->ribout_index());
1259 81575 : 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 130530 : rs_->ClearPeerRibStateList();
1272 :
1273 : // Start the walk.
1274 130530 : rs_->increment_walk_count();
1275 130530 : BgpTable *table = rs_->table();
1276 261060 : walk_ref_ = table->AllocWalker(
1277 : boost::bind(&BgpMembershipManager::Walker::WalkCallback, this, _1, _2),
1278 130530 : boost::bind(&BgpMembershipManager::Walker::WalkDoneCallback, this, _2));
1279 130530 : walk_started_ = true;
1280 130530 : if (!postpone_walk_)
1281 130524 : 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 130530 : void BgpMembershipManager::Walker::WalkFinish() {
1292 130530 : CHECK_CONCURRENCY("bgp::PeerMembership");
1293 :
1294 130530 : assert(walk_ref_ != NULL);
1295 130530 : assert(rs_);
1296 130530 : assert(!peer_rib_list_.empty());
1297 130530 : assert(!peer_list_.empty() || !ribout_state_map_.empty());
1298 130530 : assert(rib_state_list_size_ == rib_state_set_.size());
1299 130530 : assert(ribout_state_list_size_ == ribout_state_map_.size());
1300 :
1301 130530 : BgpTable *table = rs_->table();
1302 130530 : for (PeerRibList::iterator it = peer_rib_list_.begin();
1303 299656 : it != peer_rib_list_.end(); ++it) {
1304 169126 : PeerRibState *prs = *it;
1305 169126 : IPeer *peer = prs->peer_state()->peer();
1306 :
1307 169126 : switch (prs->action()) {
1308 81575 : case RIBOUT_ADD:
1309 81575 : manager_->TriggerRegisterRibCompleteEvent(peer, table);
1310 81575 : break;
1311 5976 : case RIBIN_DELETE:
1312 : case RIBIN_WALK:
1313 5976 : manager_->TriggerWalkRibCompleteEvent(peer, table);
1314 5976 : break;
1315 81575 : case RIBIN_WALK_RIBOUT_DELETE:
1316 : case RIBIN_DELETE_RIBOUT_DELETE:
1317 81575 : manager_->TriggerUnregisterRibCompleteEvent(peer, table);
1318 81575 : break;
1319 0 : default:
1320 0 : assert(false);
1321 : break;
1322 : }
1323 : }
1324 :
1325 130530 : table->ReleaseWalker(walk_ref_);
1326 130530 : rs_ = NULL;
1327 130530 : peer_rib_list_.clear();
1328 130530 : peer_list_.clear();
1329 130530 : ribout_state_list_.clear();
1330 130530 : ribout_state_list_size_ = 0;
1331 130530 : STLDeleteElements(&ribout_state_map_);
1332 :
1333 130530 : walk_started_ = false;
1334 130530 : walk_completed_ = false;
1335 130530 : }
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 156783 : bool BgpMembershipManager::Walker::WalkTrigger() {
1343 156783 : CHECK_CONCURRENCY("bgp::PeerMembership");
1344 :
1345 156783 : if (!walk_started_) {
1346 26253 : assert(!walk_completed_);
1347 26253 : WalkStart();
1348 130530 : } else if (walk_completed_) {
1349 130530 : WalkFinish();
1350 130530 : WalkStart();
1351 : }
1352 156783 : 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 : }
|