OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bgp_multicast.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "bgp/bgp_multicast.h"
6 
7 #include <boost/bind.hpp>
8 #include <boost/foreach.hpp>
9 
10 #include "base/string_util.h"
11 #include "base/task_annotations.h"
12 #include "bgp/bgp_log.h"
13 #include "bgp/bgp_mvpn.h"
14 #include "bgp/bgp_server.h"
15 #include "bgp/bgp_update.h"
17 #include "bgp/mvpn/mvpn_route.h"
19 #include "bgp/routing-instance/routing_instance_analytics_types.h"
22 
23 using std::string;
24 using std::vector;
25 
27 public:
28  explicit DeleteActor(McastTreeManager *tree_manager)
29  : LifetimeActor(tree_manager->table_->routing_instance()->server()->
30  lifetime_manager()),
31  tree_manager_(tree_manager) {
32  }
33  virtual ~DeleteActor() {
34  }
35 
36  virtual bool MayDelete() const {
37  return tree_manager_->MayDelete();
38  }
39 
40  virtual void Shutdown() {
42  }
43 
44  virtual void Destroy() {
46  }
47 
48 private:
50 };
51 
52 //
53 // Constructor for McastForwarder. The level is determined by the route type.
54 // We get the address of the forwarder and the label_block from the attributes
55 // of the active path. The LabelBLockPtr needs to be copied so that we can
56 // release the label when processing a delete notification - we won't have the
57 // path at that point.
58 //
59 // The RD will be zero for BGP learnt routes and the RouterId will be zero for
60 // XMPP learnt routes.
61 //
63  : sg_entry_(sg_entry),
64  route_(route),
65  global_tree_route_(NULL),
66  label_(0),
67  address_(0),
68  rd_(route->GetPrefix().route_distinguisher()),
69  router_id_(route->GetPrefix().router_id()) {
70  const BgpPath *path = route->BestPath();
71  const BgpAttr *attr = path->GetAttr();
72 
75  address_ = attr->nexthop().to_v4();
76  label_block_ = attr->label_block();
77  } else {
79  const EdgeDiscovery::Edge *edge = attr->edge_discovery()->edge_list[0];
80  address_ = edge->address;
81  label_block_ = edge->label_block;
82  }
83 
84  if (path->GetAttr()->ext_community())
86 }
87 
88 //
89 // Destructor for McastForwarder. Flushes forward and reverse links to and
90 // from other McastForwarders.
91 //
94  FlushLinks();
95  ReleaseLabel();
96 }
97 
98 //
99 // Update the McastForwarder based on information in the ErmVpnRoute.
100 // Return true if something changed.
101 //
103  McastForwarder forwarder(sg_entry_, route);
104 
105  bool changed = false;
106  if (label_block_ != forwarder.label_block_) {
107  ReleaseLabel();
108  label_block_ = forwarder.label_block_;
109  changed = true;
110  }
111  if (address_ != forwarder.address_) {
112  address_ = forwarder.address_;
113  changed = true;
114  }
115  if (encap_ != forwarder.encap_) {
116  encap_ = forwarder.encap_;
117  changed = true;
118  }
119 
120  return changed;
121 }
122 
123 //
124 // Printable string for McastForwarder.
125 //
126 std::string McastForwarder::ToString() const {
128  return rd_.ToString() + " -> " + integerToString(label_);
129  } else {
130  return router_id_.to_string() + " -> " + integerToString(label_);
131  }
132 }
133 
134 //
135 // Find a link to the given McastForwarder.
136 //
138  for (McastForwarderList::iterator it = tree_links_.begin();
139  it != tree_links_.end(); ++it) {
140  if (*it == forwarder) return forwarder;
141  }
142  return NULL;
143 }
144 
145 //
146 // Add a link to the given McastForwarder.
147 //
149  assert(!FindLink(forwarder));
150  tree_links_.push_back(forwarder);
151 }
152 
153 //
154 // Remove a link to the given McastForwarder.
155 //
157  for (McastForwarderList::iterator it = tree_links_.begin();
158  it != tree_links_.end(); ++it) {
159  if (*it == forwarder) {
160  tree_links_.erase(it);
161  return;
162  }
163  }
164 }
165 
166 //
167 // Flush all links from this McastForwarder. Takes care of removing the
168 // reverse links as well.
169 //
171  for (McastForwarderList::iterator it = tree_links_.begin();
172  it != tree_links_.end(); ++it) {
173  (*it)->RemoveLink(this);
174  }
175  tree_links_.clear();
176 }
177 
178 //
179 // Allocate a label for this McastForwarder. The label gets allocated from
180 // the LabelBlock corresponding to the label range advertised by the peer.
181 // This is used when updating the distribution tree for the McastSGEntry to
182 // this McastForwarder belongs.
183 //
185  label_ = label_block_->AllocateLabel();
186 }
187 
188 //
189 // Release the label, if any, for this McastForwarder. This is required when
190 // updating the distribution tree for the McastSGEntry to which we belong.
191 //
193  if (label_ != 0) {
194  label_block_->ReleaseLabel(label_);
195  label_ = 0;
196  }
197 }
198 
199 //
200 // Add the GlobalTreeRoute for this McastForwarder. The GlobalTreeRoute is
201 // used by the tree builder to tell the associated control-node about the
202 // forwarding edges for Native McastForwarders attached it.
203 //
206  assert(!global_tree_route_);
207 
208  // Bail if there's no label allocated.
209  if (label_ == 0)
210  return;
211 
212  // Bail if we can't build a source RD.
213  if (sg_entry_->GetSourceRd().IsZero())
214  return;
215 
216  // Construct the prefix and route key.
217  BgpTable *table = static_cast<BgpTable *>(route_->get_table());
221  ErmVpnRoute rt_key(prefix);
222 
223  // Find or create the route.
224  McastManagerPartition *partition = sg_entry_->partition();
225  DBTablePartition *tbl_partition =
226  static_cast<DBTablePartition *>(partition->GetTablePartition());
227  ErmVpnRoute *route =
228  static_cast<ErmVpnRoute *>(tbl_partition->Find(&rt_key));
229  if (!route) {
230  route = new ErmVpnRoute(prefix);
231  tbl_partition->Add(route);
232  } else {
233  route->ClearDelete();
234  }
235 
236  // Build the attributes. Need to go through the tree links to build the
237  // EdgeForwardingSpec.
238  BgpServer *server = table->routing_instance()->server();
239  BgpAttrSpec attr_spec;
240  BgpAttrNextHop nexthop(server->bgp_identifier());
241  attr_spec.push_back(&nexthop);
242  BgpAttrSourceRd source_rd(sg_entry_->GetSourceRd());
243  attr_spec.push_back(&source_rd);
244  EdgeForwardingSpec efspec;
245  for (McastForwarderList::const_iterator it = tree_links_.begin();
246  it != tree_links_.end(); ++it) {
249  edge->inbound_label = label_;
250  edge->SetOutboundIp4Address((*it)->address());
251  edge->outbound_label = (*it)->label();
252  efspec.edge_list.push_back(edge);
253  }
254  attr_spec.push_back(&efspec);
255  // Add tunnel encaps for remote nodes
256  ExtCommunitySpec ext;
257  ext.AddTunnelEncaps(encap_);
258  if (!ext.communities.empty())
259  attr_spec.push_back(&ext);
260  BgpAttrPtr attr = server->attr_db()->Locate(attr_spec);
261 
262  // Add a path with source BgpPath::Local.
263  BgpPath *path = new BgpPath(0, BgpPath::Local, attr);
264  route->InsertPath(path);
265  tbl_partition->Notify(route);
267 }
268 
269 //
270 // Delete the GlobalTreeRoute for this McastForwarder.
271 //
273  if (!global_tree_route_)
274  return;
275 
276  McastManagerPartition *partition = sg_entry_->partition();
277  DBTablePartition *tbl_partition =
278  static_cast<DBTablePartition *>(partition->GetTablePartition());
280 
281  if (!global_tree_route_->HasPaths()) {
282  tbl_partition->Delete(global_tree_route_);
283  } else {
284  tbl_partition->Notify(global_tree_route_);
285  }
286  global_tree_route_ = NULL;
287 }
288 
289 //
290 // Append list of BgpOListElems from the Local tree to the BgpOListSpec. The
291 // list is built based on the tree links in this McastForwarder.
292 //
295 
296  for (McastForwarderList::const_iterator it = tree_links_.begin();
297  it != tree_links_.end(); ++it) {
298  BgpOListElem elem((*it)->address(), (*it)->label(), (*it)->encap());
299  olist_spec->elements.push_back(elem);
300  }
301 }
302 
303 //
304 // Append list of BgpOListElems from the Global tree to the BgpOListSpec. The
305 // list is built based on EdgeForwarding attribute in the GlobalTreeRoute.
306 //
309 
310  // Bail if this is not the forest node for the Local tree.
311  if (!sg_entry_->IsForestNode(this))
312  return;
313 
315  if (!route)
316  return;
317 
318  const BgpPath *path = route->BestPath();
319  if (!path)
320  return;
321  const BgpAttr *attr = path->GetAttr();
322  vector<string> encaps;
323  if (attr && attr->ext_community())
324  encaps = attr->ext_community()->GetTunnelEncap();
325 
326  // Go through each forwarding edge and add it to the list.
327  const EdgeForwarding *eforwarding = path->GetAttr()->edge_forwarding();
328  for (EdgeForwarding::EdgeList::const_iterator it =
329  eforwarding->edge_list.begin(); it != eforwarding->edge_list.end();
330  ++it) {
331  const EdgeForwarding::Edge *edge = *it;
332  if (edge->inbound_address == address_) {
333  BgpOListElem elem(edge->outbound_address, edge->outbound_label,
334  encaps);
335  olist_spec->elements.push_back(elem);
336  }
337  }
338 }
339 
340 //
341 // Construct an UpdateInfo with the RibOutAttr that needs to be advertised to
342 // the IPeer for the ErmVpnRoute associated with this McastForwarder. This is
343 // used as Export method of the ErmVpnTable. It is expected that the caller
344 // fills in the target RibPeerSet in the UpdateInfo.
345 //
346 // The main functionality here is to transform the McastForwarderList for the
347 // distribution tree and the EdgeForwarding attribute from the GlobalTreeRoute
348 // into a BgpOList.
349 //
351  CHECK_CONCURRENCY("db::DBTable");
352 
354 
355  BgpOListSpec olist_spec(BgpAttribute::OList);
356  AddLocalOListElems(&olist_spec);
357  AddGlobalOListElems(&olist_spec);
358 
359  // Bail if there is no label allocated.
360  if (label_ == 0)
361  return NULL;
362 
363  BgpAttrSpec attr_spec;
364  attr_spec.push_back(&olist_spec);
365  BgpAttrPtr attr = table->server()->attr_db()->Locate(attr_spec);
366 
367  UpdateInfo *uinfo = new UpdateInfo;
368  uinfo->roattr = RibOutAttr(table, route_, attr.get(), label_, true, true);
369  if (route_ && sg_entry_->IsForestNode(this) &&
372  }
373  return uinfo;
374 }
375 
376 //
377 // Constructor for McastSGEntry.
378 //
380  Ip4Address group, Ip4Address source)
381  : partition_(partition),
382  group_(group),
383  source_(source),
384  forest_node_(NULL),
385  local_tree_route_(NULL),
386  tree_result_route_(NULL),
387  on_work_queue_(false) {
388  for (int level = McastTreeManager::LevelFirst;
389  level < McastTreeManager::LevelCount; ++level) {
390  ForwarderSet *forwarders = new ForwarderSet;
391  forwarder_sets_.push_back(forwarders);
392  update_needed_.push_back(false);
393  }
394 }
395 
396 //
397 // Destructor for McastSGEntry.
398 //
401 }
402 
403 //
404 // Printable string for McastSGEntry.
405 //
406 std::string McastSGEntry::ToString() const {
407  return group_.to_string() + "," + source_.to_string();
408 }
409 
410 //
411 // Add the given McastForwarder under this McastSGEntry and trigger update
412 // of the distribution tree.
413 //
415  uint8_t level = forwarder->level();
416  forwarder_sets_[level]->insert(forwarder);
417  update_needed_[level] = true;
418  partition_->EnqueueSGEntry(this);
419 }
420 
421 //
422 // Handle change for the given McastForwarder under this McastSGEntry. Trigger
423 // update of the distribution tree.
424 //
425 // Note that this method only handles the change = the caller determines that
426 // there has been a change.
427 //
429  uint8_t level = forwarder->level();
430  update_needed_[level] = true;
431  partition_->EnqueueSGEntry(this);
432 }
433 
434 //
435 // Delete the given McastForwarder from this McastSGEntry and trigger update
436 // of the distribution tree.
437 //
439  if (forwarder == forest_node_)
440  forest_node_ = NULL;
441  uint8_t level = forwarder->level();
442  forwarder_sets_[level]->erase(forwarder);
443  update_needed_[level] = true;
444  partition_->EnqueueSGEntry(this);
445 }
446 
447 //
448 // Get the SourceRD to be used when adding [Local|Global]TreeRoutes. This
449 // SourceRD gets used as the RD when the ErmVpnRoute is replicated from the
450 // VRF table to the VPN table.
451 //
452 // We simply use the RD for the forest node.
453 //
455  if (!forest_node_)
458 }
459 
460 //
461 // Add the LocalTreeRoute for this McastSGEntry. This route advertises a set
462 // of candidate edges from McastForwarders attached to this control-node that
463 // can be used by the tree builder to build the higher level tree. We simply
464 // advertise edges McastTreeManager::kDegree - 1 edges from the forest node.
465 //
466 // We advertise kDegree-1 candidate edges via the EdgeDiscovery attribute. All
467 // the edges are for the forest node for the tree of native McastForwarders.
468 // The label block for each edge in the EdgeDiscovery attribute is of size 1 -
469 // this is label that has been allocated for the forest node. Using a single
470 // label is acceptable because the tree builder algorithm does not change the
471 // relative order of nodes in the tree.
472 //
474  assert(!forest_node_);
475  assert(!local_tree_route_);
476 
477  // Select last usable leaf in the distribution tree as the forest node.
478  // A leaf is considered usable if it has a valid label i.e. it has not
479  // run out of labels.
480  uint8_t level = McastTreeManager::LevelNative;
481  ForwarderSet *forwarders = forwarder_sets_[level];
482  for (ForwarderSet::reverse_iterator rit = forwarders->rbegin();
483  rit != forwarders->rend(); ++rit) {
484  McastForwarder *forwarder = *rit;
485  if (forwarder->label()) {
486  forest_node_ = forwarder;
487  break;
488  }
489  }
490 
491  // Bail if we couldn't designate a forest node.
492  if (!forest_node_)
493  return;
494 
495  // Construct the prefix and route key.
496  BgpServer *server = partition_->server();
497  Ip4Address router_id(server->bgp_identifier());
500  ErmVpnRoute rt_key(prefix);
501 
502  // Find or create the route.
503  DBTablePartition *tbl_partition =
504  static_cast<DBTablePartition *>(partition_->GetTablePartition());
505  ErmVpnRoute *route =
506  static_cast<ErmVpnRoute *>(tbl_partition->Find(&rt_key));
507  if (!route) {
508  route = new ErmVpnRoute(prefix);
509  tbl_partition->Add(route);
510  } else {
511  route->ClearDelete();
512  }
513 
514  // Build the attributes.
515  BgpAttrSpec attr_spec;
516  BgpAttrNextHop nexthop(server->bgp_identifier());
517  attr_spec.push_back(&nexthop);
518  BgpAttrSourceRd source_rd(GetSourceRd());
519  attr_spec.push_back(&source_rd);
520  EdgeDiscoverySpec edspec;
521  for (int idx = 1; idx <= McastTreeManager::kDegree - 1; ++idx) {
525  edspec.edge_list.push_back(edge);
526  }
527  attr_spec.push_back(&edspec);
528  // Add tunnel encaps for remote nodes
529  ExtCommunitySpec ext;
531  if (!ext.communities.empty())
532  attr_spec.push_back(&ext);
533  BgpAttrPtr attr = server->attr_db()->Locate(attr_spec);
534 
535  // Add a path with source BgpPath::Local.
536  BgpPath *path = new BgpPath(0, BgpPath::Local, attr);
537  route->InsertPath(path);
538  tbl_partition->Notify(route);
539  local_tree_route_ = route;
540 }
541 
542 //
543 // Delete the LocalTreeRoute for this McastSGEntry.
544 //
546  if (!local_tree_route_)
547  return;
548 
549  forest_node_ = NULL;
550  DBTablePartition *tbl_partition =
551  static_cast<DBTablePartition *>(partition_->GetTablePartition());
553  if (!local_tree_route_->HasPaths()) {
554  tbl_partition->Delete(local_tree_route_);
555  } else {
556  tbl_partition->Notify(local_tree_route_);
557  }
558  local_tree_route_ = NULL;
559 }
560 
561 //
562 // Update the LocalTreeRoute for this McastSGEntry if RouterId has changed.
563 //
565  if (!local_tree_route_)
566  return;
567 
568  // Bail if the RouterId hasn't changed.
569  const BgpServer *server = partition_->server();
571  if (router_id.to_ulong() == server->bgp_identifier())
572  return;
573 
574  // Add and delete the route.
577 }
578 
579 //
580 // Update relevant [Local|Global]TreeRoutes for the McastSGEntry.
581 //
582 void McastSGEntry::UpdateRoutes(uint8_t level) {
583  if (level == McastTreeManager::LevelNative) {
586  } else {
587  ForwarderSet *forwarders = forwarder_sets_[level];
588  for (ForwarderSet::iterator it = forwarders->begin();
589  it != forwarders->end(); ++it) {
590  (*it)->DeleteGlobalTreeRoute();
591  (*it)->AddGlobalTreeRoute();
592  }
593  }
594 }
595 
598  return NULL;
600  assert(!forwarders->empty());
601  ForwarderSet::const_iterator it = forwarders->begin();
602  return (*it)->global_tree_route();
603 }
604 
605 //
606 // Implement tree builder election.
607 //
608 bool McastSGEntry::IsTreeBuilder(uint8_t level) const {
609  if (level == McastTreeManager::LevelNative)
610  return true;
611 
612  const ForwarderSet *forwarders = forwarder_sets_[level];
613  ForwarderSet::const_iterator it = forwarders->begin();
614  if (it == forwarders->end())
615  return false;
616 
617  Ip4Address router_id(partition_->server()->bgp_identifier());
618  if ((*it)->router_id() != router_id)
619  return false;
620 
621  return true;
622 }
623 
624 //
625 //
626 // Update specified distribution tree for the McastSGEntry. We traverse all
627 // McastForwarders in sorted order and arrange them in breadth first fashion
628 // in a k-ary tree. Building the tree in this manner guarantees that we get
629 // the same tree for a given set of forwarders, independent of the order in
630 // in which they joined. This predictability is deemed to be more important
631 // than other criteria such as minimizing disruption of traffic, minimizing
632 // the cost/weight of the tree etc.
633 //
634 void McastSGEntry::UpdateTree(uint8_t level) {
635  CHECK_CONCURRENCY("db::DBTable");
636 
637  if (!update_needed_[level])
638  return;
639  update_needed_[level] = false;
640 
641  int degree;
642  if (level == McastTreeManager::LevelNative) {
643  degree = McastTreeManager::kDegree;
644  } else {
645  degree = McastTreeManager::kDegree - 1;
646  }
647 
648  // First get rid of the previous distribution tree and enqueue all the
649  // associated ErmVpnRoutes for notification. Note that DBListeners will
650  // not get invoked until after this routine is done.
651  ForwarderSet *forwarders = forwarder_sets_[level];
652  for (ForwarderSet::iterator it = forwarders->begin();
653  it != forwarders->end(); ++it) {
654  (*it)->FlushLinks();
655  (*it)->ReleaseLabel();
656  partition_->GetTablePartition()->Notify((*it)->route());
657  }
658 
659  // Bail if we're not the tree builder.
660  if (!IsTreeBuilder(level)) {
661  UpdateRoutes(level);
662  return;
663  }
664 
665  // Create a vector of pointers to the McastForwarders in sorted order.
666  // We do this because std::set doesn't support random access iterators.
667  // Skip if we can't allocate a label for the McastForwarder.
668  McastForwarderList vec;
669  vec.reserve(forwarders->size());
670  for (ForwarderSet::iterator it = forwarders->begin();
671  it != forwarders->end(); ++it) {
672  McastForwarder *forwarder = *it;
673  forwarder->AllocateLabel();
674  if (!forwarder->label())
675  continue;
676  vec.push_back(forwarder);
677  }
678 
679  // Go through each McastForwarder in the vector and link it to it's parent
680  // McastForwarder in the k-ary tree. We also add a link from the parent to
681  // the entry in question.
682  for (McastForwarderList::iterator it = vec.begin(); it != vec.end(); ++it) {
683  int idx = it - vec.begin();
684  if (idx == 0)
685  continue;
686 
687  int parent_idx = (idx - 1) / degree;
688  McastForwarderList::iterator parent_it = vec.begin() + parent_idx;
689  assert(parent_it != vec.end());
690  McastForwarder *forwarder = *it;
691  McastForwarder *parent_forwarder = *parent_it;
692  forwarder->AddLink(parent_forwarder);
693  parent_forwarder->AddLink(forwarder);
694  }
695 
696  // Update [Local|Global]TreeRoutes.
697  UpdateRoutes(level);
698 }
699 
700 //
701 // Update distribution trees for both levels.
702 //
704  for (uint8_t level = McastTreeManager::LevelFirst;
705  level < McastTreeManager::LevelCount; ++level) {
706  UpdateTree(level);
707  }
708 }
709 
710 //
711 // Trigger notification of the ErmVpnRoute associated with the McastForwarder
712 // that is the forest node. This is used to trigger a rebuild of the BgpOlist
713 // when the GlobalTreeRoute is updated.
714 //
716  if (!forest_node_)
717  return;
719 }
720 
721 bool McastSGEntry::GetForestNodePMSI(uint32_t *label, Ip4Address *address,
722  vector<string> *tunnel_encap) const {
723  if (!forest_node_)
724  return false;
725  *label = forest_node_->label();
726  *address = forest_node_->address();
727  *tunnel_encap = forest_node_->encap();
728  return true;
729 }
730 
732  return (forwarder == forest_node_);
733 }
734 
735 bool McastSGEntry::empty() const {
737  return false;
739  return false;
741  return false;
742  return true;
743 }
744 
745 //
746 // Constructor for McastManagerPartition.
747 //
749  size_t part_id)
750  : tree_manager_(tree_manager),
751  part_id_(part_id),
752  update_count_(0),
753  work_queue_(TaskScheduler::GetInstance()->GetTaskId("db::DBTable"),
754  part_id_,
755  boost::bind(&McastManagerPartition::ProcessSGEntry, this, _1)) {
756 }
757 
758 //
759 // Destructor for McastManagerPartition.
760 //
763 }
764 
765 // Find the McastSGEntry for the given group and source.
767  const Ip4Address &group, const Ip4Address &source) {
768  return const_cast<McastSGEntry *>(
769  static_cast<const McastManagerPartition *>(this)->FindSGEntry(group,
770  source));
771 }
772 
773 //
774 // Find the McastSGEntry for the given group and source.
775 //
777  const Ip4Address &group, const Ip4Address &source) const {
778  McastSGEntry temp_sg_entry(const_cast<McastManagerPartition *>(this),
779  group, source);
780  SGList::const_iterator it = sg_list_.find(&temp_sg_entry);
781  return (it != sg_list_.end() ? *it : NULL);
782 }
783 
784 //
785 // Find or create the McastSGEntry for the given group and source.
786 //
788  Ip4Address group, Ip4Address source) {
789  McastSGEntry *sg_entry = FindSGEntry(group, source);
790  if (!sg_entry) {
791  sg_entry = new McastSGEntry(this, group, source);
792  sg_list_.insert(sg_entry);
793  }
794  return sg_entry;
795 }
796 
798  const Ip4Address &source, const Ip4Address &group) const {
799  const McastSGEntry *sg = FindSGEntry(group, source);
800  return sg ? sg->GetGlobalTreeRootRoute() : NULL;
801 }
802 
804  const Ip4Address &source, const Ip4Address &group) {
805  McastSGEntry *sg = FindSGEntry(group, source);
806  if (sg)
807  sg->NotifyForestNode();
808 }
809 
811  Ip4Address *address, vector<string> *encap) const {
812  const McastSGEntry *sg = FindSGEntry(rt->GetPrefix().group(),
813  rt->GetPrefix().source());
814  return sg ? sg->GetForestNodePMSI(label, address, encap) : false;
815 }
816 
817 //
818 // Enqueue the given McastSGEntry on the WorkQueue if it's not already on it.
819 //
821  if (sg_entry->on_work_queue())
822  return;
823  work_queue_.Enqueue(sg_entry);
824  sg_entry->set_on_work_queue();
825 }
826 
827 //
828 // Callback for the WorkQueue. Updates distribution trees for the McastSGEntry.
829 // Also gets rid of the McastSGEntry if it is eligible to be deleted.
830 //
832  CHECK_CONCURRENCY("db::DBTable");
833 
834  sg_entry->clear_on_work_queue();
835  sg_entry->UpdateTree();
836  update_count_++;
837 
838  if (sg_entry->empty()) {
839  sg_list_.erase(sg_entry);
840  delete sg_entry;
841  }
842 
843  if (sg_list_.empty())
845 
846  return true;
847 }
848 
849 //
850 // Get the DBTablePartBase for the ErmVpnTable for our partition id.
851 //
854 }
855 
857  return tree_manager_->table()->routing_instance();
858 }
859 
861  return tree_manager_->table()->server();
862 }
863 
865  return tree_manager_->table()->server();
866 }
867 
868 //
869 // Constructor for McastTreeManager.
870 //
872  : table_(table),
873  listener_id_(DBTable::kInvalidId),
874  table_delete_ref_(this, table->deleter()) {
875  deleter_.reset(new DeleteActor(this));
876 }
877 
878 //
879 // Destructor for McastTreeManager.
880 //
882 }
883 
884 //
885 // Initialize the McastTreeManager. We allocate the McastManagerPartitions
886 // and register a DBListener for the ErmVpnTable.
887 //
889  AllocPartitions();
891  boost::bind(&McastTreeManager::RouteListener, this, _1, _2),
892  "McastTreeManager");
893 }
894 
895 //
896 // Terminate the McastTreeManager. We free the McastManagerPartitions
897 // and unregister from the ErmVpnTable.
898 //
901  FreePartitions();
902 }
903 
904 //
905 // Allocate the McastManagerPartitions.
906 //
908  for (int part_id = 0; part_id < table_->PartitionCount(); part_id++) {
909  partitions_.push_back(new McastManagerPartition(this, part_id));
910  }
911 }
912 
913 //
914 // Free the McastManagerPartitions.
915 //
917  for (size_t part_id = 0; part_id < partitions_.size(); part_id++) {
918  delete partitions_[part_id];
919  }
920  partitions_.clear();
921 }
922 
924  return partitions_[part_id];
925 }
926 
928  return partitions_[part_id];
929 }
930 
931 //
932 // Get the DBTablePartBase for the ErmVpnTable for given partition id.
933 //
935  return table_->GetTablePartition(part_id);
936 }
937 
938 //
939 // Construct export state for the given ErmVpnRoute. Note that the route
940 // only needs to be exported to the IPeer from which it was learnt.
941 //
943  CHECK_CONCURRENCY("db::DBTable");
944 
945  DBState *dbstate = route->GetState(table_, listener_id_);
946  McastForwarder *forwarder = dynamic_cast<McastForwarder *>(dbstate);
947 
948  if (!forwarder)
949  return NULL;
950 
951  return forwarder->GetUpdateInfo(table_);
952 }
953 
954 //
955 // DBListener callback handler for Native and Local routes in the ErmVpnTable.
956 // It creates, updates or deletes the associated McastForwarder as appropriate.
957 //
958 // Creates a McastSGEntry if one doesn't already exist. However, McastSGEntrys
959 // don't get deleted from here. They only get deleted from WorkQueue callback
960 // routine i.e. McastManagerPartition::ProcessSGEntry.
961 //
963  ErmVpnRoute *route) {
964  CHECK_CONCURRENCY("db::DBTable");
965 
966  DBState *dbstate = route->GetState(table_, listener_id_);
967  if (!dbstate) {
968  // We have no previous DBState for this route.
969  // Bail if the route is not valid.
970  if (!route->IsValid())
971  return;
972 
973  // Create a new McastForwarder and associate it with the route.
974  McastSGEntry *sg_entry = partition->LocateSGEntry(
975  route->GetPrefix().group(), route->GetPrefix().source());
976  McastForwarder *forwarder = new McastForwarder(sg_entry, route);
977  sg_entry->AddForwarder(forwarder);
978  route->SetState(table_, listener_id_, forwarder);
979 
980  // Update local tree route if our RouterId has changed. Ideally,
981  // we should trigger an update of all local trees routes when we
982  // detect a change in RouterId. Instead, we currently check and
983  // update the local route when we detect a new local route from
984  // another node.
985  if (route->GetPrefix().type() == ErmVpnPrefix::LocalTreeRoute)
986  sg_entry->UpdateLocalTreeRoute();
987  } else {
988  McastSGEntry *sg_entry = partition->FindSGEntry(
989  route->GetPrefix().group(), route->GetPrefix().source());
990  assert(sg_entry);
991  McastForwarder *forwarder = dynamic_cast<McastForwarder *>(dbstate);
992  assert(forwarder);
993 
994  if (!route->IsValid()) {
995  // Delete the McastForwarder associated with the route.
996  route->ClearState(table_, listener_id_);
997  sg_entry->DeleteForwarder(forwarder);
998  delete forwarder;
999  } else if (forwarder->Update(route)) {
1000  // Trigger update of the distribution tree.
1001  sg_entry->ChangeForwarder(forwarder);
1002  }
1003  }
1004 }
1005 
1006 //
1007 // DBListener callback handler for GlobalTreeRoutes in the ErmVpnTable. It
1008 // updates the tree_result_route_ and triggers re-evaluation of the forest
1009 // node McastForwarder's BgpOlist.
1010 //
1012  ErmVpnRoute *route) {
1013  CHECK_CONCURRENCY("db::DBTable");
1014 
1015  DBState *dbstate = route->GetState(table_, listener_id_);
1016  if (!dbstate) {
1017  // We have no previous DBState for this route.
1018  // Bail if the route is not valid.
1019  if (!route->IsValid())
1020  return;
1021 
1022  // Ignore GlobalTreeRoute if it's not applicable to this control-node.
1023  BgpServer *server = table_->routing_instance()->server();
1024  if (route->GetPrefix().router_id().to_ulong() !=
1025  server->bgp_identifier())
1026  return;
1027 
1028  McastSGEntry *sg_entry = partition->LocateSGEntry(
1029  route->GetPrefix().group(), route->GetPrefix().source());
1030  route->SetState(table_, listener_id_, sg_entry);
1031  sg_entry->set_tree_result_route(route);
1032  sg_entry->NotifyForestNode();
1033  } else {
1034  McastSGEntry *sg_entry = dynamic_cast<McastSGEntry *>(dbstate);
1035  assert(sg_entry);
1036 
1037  if (!route->IsValid()) {
1038  sg_entry->clear_tree_result_route();
1039  route->ClearState(table_, listener_id_);
1040  partition->EnqueueSGEntry(sg_entry);
1041  }
1042  sg_entry->NotifyForestNode();
1043  }
1044 }
1045 
1046 //
1047 // DBListener callback handler for the ErmVpnTable. GlobalTreeRoutes provide
1048 // result information and hence are handled differently than Native and Local
1049 // routes, which result in update of a McastForwarder.
1050 //
1052  DBTablePartBase *tpart, DBEntryBase *db_entry) {
1053  CHECK_CONCURRENCY("db::DBTable");
1054 
1055  McastManagerPartition *partition = partitions_[tpart->index()];
1056  ErmVpnRoute *route = dynamic_cast<ErmVpnRoute *>(db_entry);
1057  if (route->GetPrefix().type() == ErmVpnPrefix::GlobalTreeRoute) {
1058  TreeResultListener(partition, route);
1059  } else {
1060  TreeNodeListener(partition, route);
1061  }
1062 }
1063 
1064 
1065 //
1066 // Check if the McastTreeManager can be deleted. This can happen only if all
1067 // the McastManagerPartitions are empty.
1068 //
1070  CHECK_CONCURRENCY("bgp::Config");
1071 
1072  for (PartitionList::const_iterator it = partitions_.begin();
1073  it != partitions_.end(); ++it) {
1074  if (!(*it)->empty())
1075  return false;
1076  }
1077 
1078  return true;
1079 }
1080 
1081 //
1082 // Initiate shutdown for the McastTreeManager.
1083 //
1085  CHECK_CONCURRENCY("bgp::Config");
1086 }
1087 
1088 //
1089 // Trigger deletion of the McastTreeManager and propagate the delete to any
1090 // dependents.
1091 //
1093  deleter_->Delete();
1094 }
1095 
1096 //
1097 // Attempt to enqueue a delete for the McastTreeManager.
1098 //
1100  if (!deleter()->IsDeleted())
1101  return;
1102  deleter()->RetryDelete();
1103 }
1104 
1105 //
1106 // Return the LifetimeActor for the McastTreeManager.
1107 //
1109  return deleter_.get();
1110 }
1111 
1112 //
1113 // Return the LifetimeActor for the McastTreeManager.
1114 // Const version.
1115 //
1117  return deleter_.get();
1118 }
1119 
1120 //
1121 // Return true if the McastTreeManager is deleted.
1122 //
1124  return deleter_->IsDeleted();
1125 }
1126 
1128  const Ip4Address &source, const Ip4Address &group) const {
1129  const McastManagerPartition *partition = GetPartition(table_->Hash(group));
1130  return partition->GetGlobalTreeRootRoute(source, group);
1131 }
1132 
1133 void McastTreeManager::NotifyForestNode(int part_id, const Ip4Address &source,
1134  const Ip4Address &group) {
1135  McastManagerPartition *partition = GetPartition(part_id);
1136  partition->NotifyForestNode(source, group);
1137 }
1138 
1140  Ip4Address *address, vector<string> *encap) const {
1141  if (!rt || !rt->IsUsable())
1142  return false;
1143  const McastManagerPartition *partition =
1145  return partition->GetForestNodePMSI(rt, label, address, encap);
1146 }
virtual ErmVpnRoute * GetGlobalTreeRootRoute(const Ip4Address &source, const Ip4Address &group) const
void SetIp4Address(Ip4Address addr)
Definition: bgp_attr.cc:450
boost::scoped_ptr< DeleteActor > deleter_
Elements elements
Definition: bgp_attr.h:694
bool deleted() const
McastManagerPartition(McastTreeManager *tree_manager, size_t part_id)
ErmVpnRoute * GetGlobalTreeRootRoute(const Ip4Address &source, const Ip4Address &group) const
Ip4Address source_
bool GetForestNodePMSI(ErmVpnRoute *rt, uint32_t *label, Ip4Address *address, std::vector< std::string > *encap) const
void DeleteLocalTreeRoute()
void ChangeForwarder(McastForwarder *forwarder)
const IpAddress & nexthop() const
Definition: bgp_attr.h:886
void STLDeleteValues(Container *container)
Definition: util.h:101
McastForwarder * FindLink(McastForwarder *forwarder)
const BgpPath * BestPath() const
Definition: bgp_route.cc:46
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
TypePtr Locate(Type *attr)
const ErmVpnPrefix & GetPrefix() const
Definition: ermvpn_route.h:81
RibOutAttr roattr
Definition: bgp_update.h:100
LabelBlockPtr label_block() const
Definition: bgp_attr.h:924
const RoutingInstance * routing_instance() const
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
void AddGlobalTreeRoute()
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
bool IsTreeBuilder(uint8_t level) const
RouteDistinguisher rd_
ErmVpnTable * table_
void clear_on_work_queue()
void RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry)
DBTableBase * get_table() const
Definition: db_entry.cc:119
BgpServer * server()
std::vector< bool > update_needed_
DBEntry * Find(const DBEntry *entry)
LabelBlockPtr label_block_
UpdateInfo * GetUpdateInfo(ErmVpnTable *table)
void AddLocalTreeRoute()
McastTreeManager(ErmVpnTable *table)
RoutingInstance * routing_instance()
Definition: bgp_table.h:148
void SetState(DBTableBase *tbl_base, ListenerId listener, DBState *state)
Definition: db_entry.cc:22
void NotifyForestNode(int part_id, const Ip4Address &source, const Ip4Address &group)
static const int kDegree
void SetOutboundIp4Address(Ip4Address addr)
Definition: bgp_attr.cc:609
EdgeList edge_list
Definition: bgp_attr.h:459
void clear_tree_result_route()
virtual void Initialize()
virtual ~McastTreeManager()
LabelBlockPtr label_block
Definition: bgp_attr.h:481
Ip4Address group_
ErmVpnRoute * local_tree_route_
uint8_t level() const
std::vector< BgpAttribute * > BgpAttrSpec
Definition: bgp_attr.h:822
void AddLocalOListElems(BgpOListSpec *olist_spec)
bool ProcessSGEntry(McastSGEntry *sg_entry)
EdgeList edge_list
Definition: bgp_attr.h:600
bool GetForestNodePMSI(uint32_t *label, Ip4Address *address, std::vector< std::string > *encap) const
McastSGEntry * FindSGEntry(const Ip4Address &group, const Ip4Address &source)
std::vector< std::string > encap_
void Delete(DBEntryBase *)
uint32_t label() const
McastManagerPartition * partition_
ErmVpnTable * table()
void Unregister(ListenerId listener)
Definition: db_table.cc:186
void RetryDelete()
Definition: lifetime.cc:71
const Ip4Address & source_address() const
Definition: bgp_ribout.h:121
bool IsUsable() const
Definition: bgp_route.cc:324
bool on_work_queue()
std::set< McastForwarder *, McastForwarderCompare > ForwarderSet
virtual UpdateInfo * GetUpdateInfo(ErmVpnRoute *route)
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
void DeleteGlobalTreeRoute()
bool Update(ErmVpnRoute *route)
ErmVpnRoute * route_
void DeleteForwarder(McastForwarder *forwarder)
const RouteDistinguisher & GetSourceRd() const
Ip4Address address
Definition: bgp_attr.h:480
void TreeResultListener(McastManagerPartition *partition, ErmVpnRoute *route)
boost::intrusive_ptr< const BgpAttr > BgpAttrPtr
Definition: bgp_attr.h:991
bool empty() const
uint8_t type() const
Definition: ermvpn_route.h:56
void UpdateRoutes(uint8_t level)
Ip4Address inbound_address
Definition: bgp_attr.h:588
void UpdateLocalTreeRoute()
void SetInboundIp4Address(Ip4Address addr)
Definition: bgp_attr.cc:602
ErmVpnRoute * tree_result_route_
void set_on_work_queue()
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
WorkQueue< McastSGEntry * > work_queue_
std::string ToString() const
DeleteActor(McastTreeManager *tree_manager)
uint32_t outbound_label
Definition: bgp_attr.h:589
void SetLabels(uint32_t first_label, uint32_t last_label)
Definition: bgp_attr.cc:462
McastSGEntry * LocateSGEntry(Ip4Address group, Ip4Address source)
Ip4Address router_id() const
Definition: ermvpn_route.h:58
#define CHECK_CONCURRENCY(...)
void RemoveLink(McastForwarder *forwarder)
virtual size_t Hash(const DBEntry *entry) const
Definition: ermvpn_table.cc:41
virtual void Terminate()
Ip4Address address() const
const RouteDistinguisher & route_distinguisher() const
Definition: ermvpn_route.h:57
static RouteDistinguisher kZeroRd
Definition: rd.h:14
McastSGEntry(McastManagerPartition *partition, Ip4Address group, Ip4Address source)
EdgeList edge_list
Definition: bgp_attr.h:493
void ClearDelete()
Definition: db_entry.h:48
Ip4Address source() const
Definition: ermvpn_route.h:60
std::vector< std::string > encap() const
void ClearState(DBTableBase *tbl_base, ListenerId listener)
Definition: db_entry.cc:73
PartitionList partitions_
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
DBTablePartBase * GetTablePartition(size_t part_id)
virtual bool MayDelete() const
void AddTunnelEncaps(std::vector< std::string > encaps)
Definition: community.cc:213
Ip4Address address_
void InsertPath(BgpPath *path)
Definition: bgp_route.cc:60
Ip4Address group() const
Definition: ermvpn_route.h:59
virtual int PartitionCount() const
Definition: ermvpn_table.h:44
std::vector< McastForwarder * > McastForwarderList
Definition: bgp_multicast.h:32
bool IsForestNode(McastForwarder *forwarder)
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:436
void DestroyTreeManager()
BgpServer * server()
Definition: bgp_table.cc:88
bool RemovePath(BgpPath::PathSource src, const IPeer *peer=NULL, uint32_t path_id=0)
Definition: bgp_route.cc:262
bool MayDelete() const
std::vector< ForwarderSet * > forwarder_sets_
ErmVpnRoute * global_tree_route_
ErmVpnRoute * GetGlobalTreeRootRoute() const
uint32_t bgp_identifier() const
Definition: bgp_server.h:208
const ExtCommunity * ext_community() const
Definition: bgp_attr.h:915
void AddGlobalOListElems(BgpOListSpec *olist_spec)
Ip4Address outbound_address
Definition: bgp_attr.h:588
std::string ToString() const
BgpAttrDB * attr_db()
Definition: bgp_server.h:181
void NotifyForestNode()
McastTreeManager * tree_manager_
void set_tree_result_route(ErmVpnRoute *route)
bool HasPaths() const
Definition: bgp_route.h:27
const BgpAttr * GetAttr() const
Definition: bgp_path.h:87
McastForwarderList tree_links_
std::vector< std::string > GetTunnelEncap() const
Definition: community.cc:595
std::string ToString() const
Definition: rd.cc:56
Ip4Address router_id_
void AddLink(McastForwarder *forwarder)
const ErmVpnRoute * tree_result_route() const
EdgeList edge_list
Definition: bgp_attr.h:566
const EdgeForwarding * edge_forwarding() const
Definition: bgp_attr.h:921
void GetMvpnSourceAddress(ErmVpnRoute *ermvpn_route, Ip4Address *address) const
McastForwarder(McastSGEntry *sg_entry, ErmVpnRoute *route)
virtual void Add(DBEntry *entry)
DBTablePartBase * get_table_partition() const
Definition: db_entry.cc:115
const EdgeDiscovery * edge_discovery() const
Definition: bgp_attr.h:918
std::vector< uint64_t > communities
Definition: community.h:143
void Notify(DBEntryBase *entry)
bool IsZero() const
Definition: rd.h:43
ErmVpnRoute * route()
LifetimeActor * deleter()
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
Ip4Address group() const
void EnqueueSGEntry(McastSGEntry *sg_entry)
Ip4Address source() const
void TreeNodeListener(McastManagerPartition *partition, ErmVpnRoute *route)
virtual bool GetForestNodePMSI(ErmVpnRoute *rt, uint32_t *label, Ip4Address *address, std::vector< std::string > *encap) const
DBTablePartBase * GetTablePartition()
McastManagerPartition * partition()
McastManagerPartition * GetPartition(int part_id)
McastTreeManager * tree_manager_
void NotifyForestNode(const Ip4Address &source, const Ip4Address &group)
virtual bool IsValid() const
McastSGEntry * sg_entry_
int index() const
void AddForwarder(McastForwarder *forwarder)
McastForwarder * forest_node_