LCOV - code coverage report
Current view: top level - bgp - bgp_multicast.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 46 46 100.0 %
Date: 2026-06-08 02:02:55 Functions: 26 26 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef SRC_BGP_BGP_MULTICAST_H_
       6             : #define SRC_BGP_BGP_MULTICAST_H_
       7             : 
       8             : #include <boost/scoped_ptr.hpp>
       9             : 
      10             : #include <set>
      11             : #include <string>
      12             : #include <vector>
      13             : 
      14             : #include "base/label_block.h"
      15             : #include "base/lifetime.h"
      16             : #include "base/queue_task.h"
      17             : #include "base/address.h"
      18             : #include "bgp/bgp_ribout.h"
      19             : #include "db/db_entry.h"
      20             : #include "net/rd.h"
      21             : 
      22             : class BgpOListSpec;
      23             : class BgpServer;
      24             : class DBTablePartBase;
      25             : class ErmVpnRoute;
      26             : class ErmVpnTable;
      27             : class McastForwarder;
      28             : class McastManagerPartition;
      29             : class McastSGEntry;
      30             : class McastTreeManager;
      31             : class RoutingInstance;
      32             : struct UpdateInfo;
      33             : 
      34             : typedef std::vector<McastForwarder *> McastForwarderList;
      35             : 
      36             : //
      37             : // This class represents membership of a vRouter or a control-node in a (G,S)
      38             : // within a multicast table.
      39             : //
      40             : // A vRouter is considered a member if it has advertised a route for (G,S) via
      41             : // XMPP. The level_ field in McastForwarder is set to LevelNative in this case.
      42             : //
      43             : // A control-node is considered to be a member if it has advertised (via BGP)
      44             : // an ErmVpnRoute of type LocalRoute for (G,S). The level_ field gets set to
      45             : // LevelLocal in this case.
      46             : 
      47             : // There's a 1:1 correspondence between an ErmVpnRoute of type NativeRoute or
      48             : // LocalRoute and a McastForwarder. Routes in the ErmVpnTable are keyed by RD,
      49             : // RouterId, Group and Source. When these routes are processed, we invert the
      50             : // information and create a McastSGEntry for each unique (G,S).  Information
      51             : // from the RD and the IPeer from which we learnt the route is used to create
      52             : // a McastForwarder. The McastForwarder is part of a set in the McastSGEntry
      53             : // for the (G,S).
      54             : //
      55             : // A McastForwarder gets created when the DBListener for the McastTreeManager
      56             : // sees a new ErmVpnRoute of type NativeRoute or LocalRoute. It's deleted when
      57             : // the DBListener detects that the route in question has been deleted.
      58             : //
      59             : // A McastForwarder is associated with the ErmVpnRoute by setting it to be the
      60             : // DBState for the McastTreeManager's listener id. The McastForwarder keeps a
      61             : // back pointer to the ErmVpnRoute.
      62             : //
      63             : // The LabelBlockPtr is obtained from the attributes of the best path for the
      64             : // ErmVpnRoute.  It's used to allocate labels for the McastForwarder without
      65             : // needing to reach into the route.  More importantly, it's required to release
      66             : // the currently allocated label when the route gets marked for deletion, at
      67             : // which time there's no active path for the route.
      68             : //
      69             : // A McastForwarder contains a vector of pointers to other McastForwarders at
      70             : // the same NodeLevel within the McastSGEntry.  The collection of these links
      71             : // constitutes the distribution tree for the McastSGEntry at that NodeLevel.
      72             : // Note that only a single MPLS label is used for a McastForwarder in a given
      73             : // distribution tree. Thus the label can be stored in the McastForwarder itself
      74             : // and does not need to be part of the link information.
      75             : //
      76             : // If this control-node is elected as the tree builder for the (G,S), a global
      77             : // distribution tree of all Local McastForwarders is built.  Relevant edges of
      78             : // this global distribution tree are advertised to each control-node by adding
      79             : // a GlobalTreeRoute for each Local McastForwarder. The global_tree_route_ is
      80             : // used to keep track of this ErmVpnRoute and [Add|Delete]GlobalTreeRoute are
      81             : // used to add or delete the route.
      82             : //
      83             : class McastForwarder : public DBState {
      84             : public:
      85             :     McastForwarder(McastSGEntry *sg_entry, ErmVpnRoute *route);
      86             :     ~McastForwarder();
      87             : 
      88             :     bool Update(ErmVpnRoute *route);
      89             :     std::string ToString() const;
      90             :     uint8_t GetLevel() const;
      91             : 
      92             :     McastForwarder *FindLink(McastForwarder *forwarder);
      93             :     void AddLink(McastForwarder *forwarder);
      94             :     void RemoveLink(McastForwarder *forwarder);
      95             :     void FlushLinks();
      96             : 
      97             :     void AllocateLabel();
      98             :     void ReleaseLabel();
      99             : 
     100             :     void AddGlobalTreeRoute();
     101             :     void DeleteGlobalTreeRoute();
     102             :     UpdateInfo *GetUpdateInfo(ErmVpnTable *table);
     103             : 
     104        5007 :     uint8_t level() const { return level_; }
     105       16800 :     uint32_t label() const { return label_; }
     106           8 :     const LabelBlock *label_block() const { return label_block_.get(); }
     107        7474 :     Ip4Address address() const { return address_; }
     108        4686 :     std::vector<std::string> encap() const { return encap_; }
     109       13029 :     ErmVpnRoute *route() { return route_; }
     110       43336 :     const RouteDistinguisher &route_distinguisher() const { return rd_; }
     111       26212 :     Ip4Address router_id() const { return router_id_; }
     112             : 
     113             :     bool empty() { return tree_links_.empty(); }
     114        1707 :     ErmVpnRoute *global_tree_route() const { return global_tree_route_; }
     115             : 
     116             : private:
     117             :     friend class BgpMulticastTest;
     118             :     friend class ShowMulticastManagerDetailHandler;
     119             : 
     120             :     void AddLocalOListElems(BgpOListSpec *olist_spec);
     121             :     void AddGlobalOListElems(BgpOListSpec *olist_spec);
     122             : 
     123             :     McastSGEntry *sg_entry_;
     124             :     ErmVpnRoute *route_;
     125             :     ErmVpnRoute *global_tree_route_;
     126             :     uint8_t level_;
     127             :     LabelBlockPtr label_block_;
     128             :     uint32_t label_;
     129             :     Ip4Address address_;
     130             :     RouteDistinguisher rd_;
     131             :     Ip4Address router_id_;
     132             :     std::vector<std::string> encap_;
     133             :     McastForwarderList tree_links_;
     134             : 
     135             :     DISALLOW_COPY_AND_ASSIGN(McastForwarder);
     136             : };
     137             : 
     138             : //
     139             : // Key comparison class for McastForwarder.
     140             : //
     141             : struct McastForwarderCompare {
     142       12430 :     bool operator()(const McastForwarder *lhs,
     143             :                     const McastForwarder *rhs) const {
     144       12430 :         if (lhs->route_distinguisher() < rhs->route_distinguisher())
     145        3192 :             return true;
     146        9238 :         if (lhs->route_distinguisher() > rhs->route_distinguisher())
     147        4051 :             return false;
     148        5187 :         if (lhs->router_id() < rhs->router_id())
     149         858 :             return true;
     150        4329 :         if (lhs->router_id() > rhs->router_id())
     151         465 :             return false;
     152             : 
     153        3864 :         return false;
     154             :     }
     155             : };
     156             : 
     157             : //
     158             : // This class represents a (G,S) entry within a McastManagerPartition. The
     159             : // routes in the ErmVpnTable are keyed by RD, RouterId, Group and Source.
     160             : // When these routes are processed, we rearrange the information and create a
     161             : // McastSGEntry for each unique (G,S). The RD and RouterId in the ErmVpnRoute
     162             : // represent a McastForwarder.
     163             : //
     164             : // A McastSGEntry is part of a set in the McastManagerPartition. In addition
     165             : // is may also temporarily be on the WorkQueue in the McastManagerPartition
     166             : // if the distribution tree needs to be updated.
     167             : //
     168             : // A McastSGEntry is created when the DBListener for the ErmVpnTable sees the
     169             : // first ErmVpnRoute containing the (G,S) and needs to create a McastForwarder.
     170             : // It is destroyed when all McastForwarders under it are gone. The delete is
     171             : // done from the McastManagerPartition's WorkQueue callback routine to ensure
     172             : // that there are no stale references to it on the WorkQueue.  Note that the
     173             : // WorkQueue cannot contain more than one reference to a given McastSGEntry.
     174             : //
     175             : // Two sets of pointers to McastForwarders are maintained in a McastSGEntry -
     176             : // for Native and Local tree levels. The McastForwarders at the Native level
     177             : // correspond to vRouters that have subscribed to the (G,S). McastForwarders
     178             : // at the Local level correspond to control-nodes (including this one) that
     179             : // are advertising their local subtree's candidate edges via a LocalTreeRoute.
     180             : // The sets are keyed by the RD and RouterId of the McastForwarders.
     181             : //
     182             : // A local distribution tree of all Native McastForwarders is built and the
     183             : // last leaf in the tree is designated as the forest node.  The forest_node_
     184             : // is used to keep track of this McastForwarder.  A LocalTreeRoute is added to
     185             : // the ErmVpnTable and the forest node's candidate edges are advertised using
     186             : // the EdgeDiscovery attribute. The local_tree_route_ keeps track of the route.
     187             : //
     188             : // If this control-node is elected to be the tree builder for this (G,S), a
     189             : // global distribution tree of all Local McastForwarders is built.  Relevant
     190             : // edges of this global distribution tree are advertised to each control-node
     191             : // by adding a GlobalTreeRoute for each Local McastForwarder.  The forwarding
     192             : // edges are encoded using the EdgeForwarding attribute.
     193             : //
     194             : // Whether the tree builder is this control-node or another control-node, the
     195             : // tree_result_route_ member keeps track of the GlobalTreeRoute that contains
     196             : // the forwarding edges relevant to this control-node.  The RouterId in the
     197             : // GlobalTreeRoute is used to decide if it's for this control-node.  We set
     198             : // our DBState on this ErmVpnRoute to be the McastSGEntry.
     199             : //
     200             : // The McastSGEntry is enqueued on the WorkQueue in the McastManagerPartition
     201             : // when a McastForwarder is added, changed or deleted so that the distribution
     202             : // tree and the necessary LocalTreeRoute or GlobalTreeRoutes can be updated.
     203             : //
     204             : class McastSGEntry : public DBState {
     205             : public:
     206             :     McastSGEntry(McastManagerPartition *partition,
     207             :                  Ip4Address group, Ip4Address source);
     208             :     ~McastSGEntry();
     209             : 
     210             :     std::string ToString() const;
     211             : 
     212             :     void AddForwarder(McastForwarder *forwarder);
     213             :     void ChangeForwarder(McastForwarder *forwarder);
     214             :     void DeleteForwarder(McastForwarder *forwarder);
     215             : 
     216             :     const RouteDistinguisher &GetSourceRd() const;
     217             :     void AddLocalTreeRoute();
     218             :     void DeleteLocalTreeRoute();
     219             :     void UpdateLocalTreeRoute();
     220             :     void UpdateTree();
     221             :     void NotifyForestNode();
     222             :     bool IsForestNode(McastForwarder *forwarder);
     223             : 
     224      145190 :     Ip4Address group() const { return group_; }
     225      135432 :     Ip4Address source() const { return source_; }
     226        2720 :     McastManagerPartition *partition() { return partition_; }
     227        2236 :     const ErmVpnRoute *tree_result_route() const { return tree_result_route_; }
     228         445 :     void set_tree_result_route(ErmVpnRoute *route) {
     229         445 :         tree_result_route_ = route;
     230         445 :     }
     231         445 :     void clear_tree_result_route() { tree_result_route_ = NULL; }
     232             : 
     233        5452 :     bool on_work_queue() { return on_work_queue_; }
     234        3378 :     void set_on_work_queue() { on_work_queue_ = true; }
     235        3378 :     void clear_on_work_queue() { on_work_queue_ = false; }
     236             : 
     237             :     bool empty() const;
     238             :     ErmVpnRoute *GetGlobalTreeRootRoute() const;
     239             :     bool GetForestNodePMSI(uint32_t *label, Ip4Address *address,
     240             :                            std::vector<std::string> *encap) const;
     241             :     bool IsTreeBuilder(uint8_t level) const;
     242             : 
     243             : private:
     244             :     friend class BgpMulticastTest;
     245             :     friend class ShowMulticastManagerDetailHandler;
     246             : 
     247             :     typedef std::set<McastForwarder *, McastForwarderCompare> ForwarderSet;
     248             : 
     249             :     void UpdateTree(uint8_t level);
     250             :     void UpdateRoutes(uint8_t level);
     251             : 
     252             :     McastManagerPartition *partition_;
     253             :     Ip4Address group_, source_;
     254             :     McastForwarder *forest_node_;
     255             :     ErmVpnRoute *local_tree_route_;
     256             :     ErmVpnRoute *tree_result_route_;
     257             :     std::vector<ForwarderSet *> forwarder_sets_;
     258             :     std::vector<bool> update_needed_;
     259             :     bool on_work_queue_;
     260             : 
     261             :     DISALLOW_COPY_AND_ASSIGN(McastSGEntry);
     262             : };
     263             : 
     264             : //
     265             : // Key comparison class for McastSGEntry.
     266             : //
     267             : struct McastSGEntryCompare {
     268       37390 :     bool operator()(const McastSGEntry *lhs, const McastSGEntry *rhs) const {
     269       37390 :         if (lhs->group().to_ulong() < rhs->group().to_ulong()) {
     270        2866 :             return true;
     271             :         }
     272       34524 :         if (lhs->group().to_ulong() > rhs->group().to_ulong()) {
     273         819 :             return false;
     274             :         }
     275       33705 :         if (lhs->source().to_ulong() < rhs->source().to_ulong()) {
     276         375 :             return true;
     277             :         }
     278       33330 :         if (lhs->source().to_ulong() > rhs->source().to_ulong()) {
     279         166 :             return false;
     280             :         }
     281       33164 :         return false;
     282             :     }
     283             : };
     284             : 
     285             : //
     286             : // This class represents a partition in the McastTreeManager. It is used to
     287             : // maintain membership information for a subset of the (G,S) entries in the
     288             : // associated ErmVpnTable and to calculate and store distribution trees for
     289             : // each of those (G,S) entries.
     290             : //
     291             : // The partition for a (G,S) is determined by a hash function. Consequently,
     292             : // information about all McastForwarders that have sent joins for a (G,S) is
     293             : // always under a single partition.
     294             : //
     295             : // A McastManagerPartition keeps a set of pointers to McastSGEntrys for the
     296             : // (G,S) states that fall under the partition. The set is keyed by the group
     297             : // and source addresses.
     298             : //
     299             : // A WorkQueue of pointers to McastSGEntrys is used to keep track of entries
     300             : // that need their distribution tree to be updated. The use of the WorkQueue
     301             : // also allows us to combine multiple McastForwarder join/leave events into
     302             : // a smaller number of updates to the distribution tree.
     303             : //
     304             : // All McastManagerPartitions are allocated when the McastTreeManager gets
     305             : // initialized and are freed when the McastTreeManager is terminated.
     306             : //
     307             : class McastManagerPartition {
     308             : public:
     309             :     McastManagerPartition(McastTreeManager *tree_manager, size_t part_id);
     310             :     ~McastManagerPartition();
     311             : 
     312             :     McastSGEntry *FindSGEntry(const Ip4Address &group,
     313             :                               const Ip4Address &source);
     314             :     const McastSGEntry *FindSGEntry(const Ip4Address &group,
     315             :                                     const Ip4Address &source) const;
     316             :     McastSGEntry *LocateSGEntry(Ip4Address group, Ip4Address source);
     317             :     void EnqueueSGEntry(McastSGEntry *sg_entry);
     318             : 
     319             :     DBTablePartBase *GetTablePartition();
     320             :     const RoutingInstance *routing_instance() const;
     321             :     BgpServer *server();
     322             :     const BgpServer *server() const;
     323             :     McastTreeManager *tree_manager() const { return tree_manager_; }
     324       42873 :     bool empty() const { return sg_list_.empty(); }
     325         190 :     size_t size() const { return sg_list_.size(); }
     326             :     ErmVpnRoute *GetGlobalTreeRootRoute(const Ip4Address &source,
     327             :                                         const Ip4Address &group) const;
     328             :     void NotifyForestNode(const Ip4Address &source, const Ip4Address &group);
     329             :     bool GetForestNodePMSI(ErmVpnRoute *rt, uint32_t *label,
     330             :                            Ip4Address *address,
     331             :                            std::vector<std::string> *encap) const;
     332             : 
     333             : private:
     334             :     friend class BgpMulticastTest;
     335             :     friend class ShowMulticastManagerDetailHandler;
     336             : 
     337             :     typedef std::set<McastSGEntry *, McastSGEntryCompare> SGList;
     338             : 
     339             :     bool ProcessSGEntry(McastSGEntry *sg_entry);
     340             : 
     341             :     McastTreeManager *tree_manager_;
     342             :     size_t part_id_;
     343             :     SGList sg_list_;
     344             :     int update_count_;
     345             :     WorkQueue<McastSGEntry *> work_queue_;
     346             : 
     347             :     DISALLOW_COPY_AND_ASSIGN(McastManagerPartition);
     348             : };
     349             : 
     350             : //
     351             : // This class represents the multicast tree manager for an ErmVpnTable.
     352             : //
     353             : // It is responsible for listening to route notifications on the associated
     354             : // ErmVpnTable and building distribution trees for edge replicated multicast.
     355             : // A local distribution tree consisting of all the vRouters that subscribed
     356             : // to this control-node is built for each (G,S).  Further, if this control
     357             : // node is elected to be the tree builder for a (G,S) a global distribution
     358             : // is also built.  The global tree is built by selecting edges from the set
     359             : // of candidate edges advertised by each control-node.
     360             : //
     361             : // It also provides the ErmVpnTable class with an API to get the UpdateInfo
     362             : // for a route in the ErmVpnTable. This is used by the table's Export method
     363             : // to construct the RibOutAttr for the multicast routes. This is how we send
     364             : // the label and OList information for a (G,S) to the XMPP peers.
     365             : //
     366             : // A McastTableManager keeps a vector of pointers to McastManagerPartitions.
     367             : // The number of partitions is the same as the DB partition count. Each such
     368             : // partition contains a subset of (G,S) entries learnt from the route table.
     369             : // The concurrency model is that each McastManagerPartition can be updated
     370             : // with membership information and can build distribution trees independently
     371             : // of the other partitions.
     372             : //
     373             : // There's a 1:1 relationship between the McastTreeManager a ErmVpnTable with
     374             : // the McastTreeManager being dependent of the ErmVpnTable via LifetimeManager
     375             : // infrastructure. The McastTreeManager is created when the ErmVpnTable gets
     376             : // associated with a RoutingInstance. A McastTreeManager can be destroyed when
     377             : // all McastManagerPartitions are empty i.e. when all McastSGEntrys in all the
     378             : // partition have been cleaned up. Actual deletion happens via LifetimeManager
     379             : // infrastructure.
     380             : //
     381             : // Note that we do not create a McastTreeManager for the ErmVpnTable in the
     382             : // default routing instance i.e. bgp.ermvpn.0.
     383             : //
     384             : class McastTreeManager {
     385             : public:
     386             :     static const int kDegree = 4;
     387             : 
     388             :     typedef std::vector<McastManagerPartition *> PartitionList;
     389             :     typedef PartitionList::const_iterator const_iterator;
     390             : 
     391             :     enum NodeLevel {
     392             :         LevelFirst = 0,
     393             :         LevelNative = 0,
     394             :         LevelLocal = 1,
     395             :         LevelCount = 2,
     396             :     };
     397             : 
     398             :     explicit McastTreeManager(ErmVpnTable *table);
     399             :     virtual ~McastTreeManager();
     400             : 
     401        6864 :     const_iterator begin() const { return partitions_.begin(); }
     402        7054 :     const_iterator end() const { return partitions_.end(); }
     403             : 
     404             :     virtual void Initialize();
     405             :     virtual void Terminate();
     406             : 
     407             :     McastManagerPartition *GetPartition(int part_id);
     408             :     const McastManagerPartition *GetPartition(int part_id) const;
     409             : 
     410             :     virtual UpdateInfo *GetUpdateInfo(ErmVpnRoute *route);
     411             :     DBTablePartBase *GetTablePartition(size_t part_id);
     412        8664 :     ErmVpnTable *table() { return table_; }
     413       10306 :     const ErmVpnTable *table() const { return table_; }
     414             : 
     415             :     void ManagedDelete();
     416             :     void Shutdown();
     417             :     bool MayDelete() const;
     418             :     void RetryDelete();
     419             : 
     420             :     LifetimeActor *deleter();
     421             :     const LifetimeActor *deleter() const;
     422             :     bool deleted() const;
     423             :     const ErmVpnRoute *GetGlobalErmVpnTreeMvpnRoute() const;
     424             :     virtual ErmVpnRoute *GetGlobalTreeRootRoute(const Ip4Address &source,
     425             :                                                 const Ip4Address &group) const;
     426             :     void NotifyForestNode(int part_id, const Ip4Address &source,
     427             :                           const Ip4Address &group);
     428             :     virtual bool GetForestNodePMSI(ErmVpnRoute *rt, uint32_t *label,
     429             :             Ip4Address *address, std::vector<std::string> *encap) const;
     430             : 
     431             : private:
     432             :     friend class BgpMulticastTest;
     433             :     friend class ShowMulticastManagerDetailHandler;
     434             : 
     435             :     class DeleteActor;
     436             : 
     437             :     void AllocPartitions();
     438             :     void FreePartitions();
     439             :     void TreeNodeListener(McastManagerPartition *partition,
     440             :         ErmVpnRoute *route);
     441             :     void TreeResultListener(McastManagerPartition *partition,
     442             :         ErmVpnRoute *route);
     443             :     void RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry);
     444             : 
     445             :     ErmVpnTable *table_;
     446             :     int listener_id_;
     447             :     PartitionList partitions_;
     448             : 
     449             :     boost::scoped_ptr<DeleteActor> deleter_;
     450             :     LifetimeRef<McastTreeManager> table_delete_ref_;
     451             : 
     452             :     DISALLOW_COPY_AND_ASSIGN(McastTreeManager);
     453             : };
     454             : 
     455             : #endif  // SRC_BGP_BGP_MULTICAST_H_

Generated by: LCOV version 1.14