LCOV - code coverage report
Current view: top level - bgp - bgp_evpn.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 56 57 98.2 %
Date: 2026-06-11 01:56:02 Functions: 36 36 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef SRC_BGP_BGP_EVPN_H_
       6             : #define SRC_BGP_BGP_EVPN_H_
       7             : 
       8             : #include <boost/ptr_container/ptr_map.hpp>
       9             : #include <boost/scoped_ptr.hpp>
      10             : #include <tbb/spin_rw_mutex.h>
      11             : 
      12             : #include <list>
      13             : #include <set>
      14             : #include <vector>
      15             : #include <atomic>
      16             : 
      17             : #include "base/lifetime.h"
      18             : #include "base/task_trigger.h"
      19             : #include "base/address.h"
      20             : #include "bgp/bgp_attr.h"
      21             : #include "bgp/bgp_path.h"
      22             : #include "db/db_entry.h"
      23             : 
      24             : class BgpPath;
      25             : class DBTablePartition;
      26             : class DBTablePartBase;
      27             : class EvpnRoute;
      28             : class ErmVpnRoute;
      29             : class EvpnState;
      30             : class EvpnTable;
      31             : class ErmVpnTable;
      32             : class EvpnManagerPartition;
      33             : class EvpnManager;
      34             : class ShowEvpnTable;
      35             : struct UpdateInfo;
      36             : 
      37             : typedef boost::intrusive_ptr<EvpnState> EvpnStatePtr;
      38             : 
      39             : /// @brief This is the base class for a multicast node in an EVPN instance. 
      40             : /// The node could either represent a local vRouter that's connected to a 
      41             : /// control node via XMPP or a remote vRouter/PE that's discovered via BGP.
      42             : ///
      43             : /// In normal operation, the EvpnMcastNodes corresponding to vRouters (local
      44             : /// or remote) support edge replication, while those corresponding to EVPN PEs
      45             : /// do not.  However, for test purposes, it's possible to have vRouters that
      46             : /// no not support edge replication.
      47             : class EvpnMcastNode : public DBState {
      48             : public:
      49             :     enum Type {
      50             :         LocalNode,
      51             :         RemoteNode
      52             :     };
      53             :     /// @brief Constructor for EvpnMcastNode. The type indicates whether this is a local
      54             :     /// or remote EvpnMcastNode.
      55             :     EvpnMcastNode(EvpnManagerPartition *partition, EvpnRoute *route,
      56             :         uint8_t type);
      57             :     EvpnMcastNode(EvpnManagerPartition *partition, EvpnRoute *route,
      58             :         uint8_t type, EvpnStatePtr state);
      59             :     ~EvpnMcastNode();
      60             : 
      61             :     /// @brief Update the label and attributes for a EvpnMcastNode.
      62             :     /// Return true if either of them changed.
      63             :     bool UpdateAttributes(EvpnRoute *route);
      64             : 
      65             :     /// @brief Handle update of EvpnLocalMcastNode.
      66             :     ///
      67             :     /// We delete and add the Inclusive Multicast route to ensure that all the
      68             :     /// attributes are updated. An in-place update is not always possible since
      69             :     /// the vRouter address is part of the key for the Inclusive Multicast route.
      70             :     virtual void TriggerUpdate() = 0;
      71             : 
      72        8300 :     EvpnStatePtr state() { return state_; };
      73        8430 :     void set_state(EvpnStatePtr state) { state_ = state; };
      74       58791 :     EvpnRoute *route() { return route_; }
      75       30180 :     uint8_t type() const { return type_; }
      76       18826 :     const BgpAttr *attr() const { return attr_.get(); }
      77       18826 :     uint32_t label() const { return label_; }
      78      120859 :     Ip4Address address() const { return address_; }
      79        1648 :     Ip4Address replicator_address() const { return replicator_address_; }
      80      130430 :     bool edge_replication_not_supported() const {
      81      130430 :         return edge_replication_not_supported_;
      82             :     }
      83       20690 :     bool assisted_replication_supported() const {
      84       20690 :         return assisted_replication_supported_;
      85             :     }
      86      122204 :     bool assisted_replication_leaf() const {
      87      122204 :         return assisted_replication_leaf_;
      88             :     }
      89             : 
      90             : protected:
      91             :     EvpnManagerPartition *partition_;
      92             :     EvpnStatePtr state_;
      93             :     EvpnRoute *route_;
      94             :     uint8_t type_;
      95             :     BgpAttrPtr attr_;
      96             :     uint32_t label_;
      97             :     Ip4Address address_;
      98             :     Ip4Address replicator_address_;
      99             :     bool edge_replication_not_supported_;
     100             :     bool assisted_replication_supported_;
     101             :     bool assisted_replication_leaf_;
     102             : 
     103             : private:
     104             :     DISALLOW_COPY_AND_ASSIGN(EvpnMcastNode);
     105             : };
     106             : 
     107             : 
     108             : /// @brief This class represents (in the context of an EVPN instance) a local 
     109             : /// vRouter that's connected to a control node via XMPP.  An EvpnLocalMcastNode
     110             : /// gets created and associated as DBState with the broadcast MAC route advertised
     111             : /// by the vRouter.
     112             : ///
     113             : /// The EvpnLocalMcastNode mainly exists to translate the broadcast MAC route
     114             : /// advertised by the vRouter into an EVPN Inclusive Multicast route.  In the
     115             : /// other direction, EvpnLocalMcastNode serves as the anchor point to build a
     116             : /// vRouter specific ingress replication olist so that the vRouter can send
     117             : /// multicast traffic to EVPN PEs (and possibly vRouters in test environment)
     118             : /// that do not support edge replication.
     119             : ///
     120             : /// An Inclusive Multicast route is added for each EvpnLocalMcastNode. The
     121             : /// attributes of the Inclusive Multicast route are based on the broadcast
     122             : /// MAC route corresponding to the EvpnLocalMcastNode.  The label for the
     123             : /// broadcast MAC route is advertised as the label for ingress replication
     124             : /// in the PmsiTunnel attribute.
     125             : class EvpnLocalMcastNode : public EvpnMcastNode {
     126             : public:
     127             : 
     128             :     /// @brief Constructor for EvpnLocalMcastNode.
     129             :     ///
     130             :     /// Add an Inclusive Multicast route corresponding to Broadcast MAC route.
     131             :     ///
     132             :     /// Need to Notify the Broadcast MAC route so that the table Export method
     133             :     /// can run and build the OList. OList is not built till EvpnLocalMcastNode
     134             :     /// has been created.
     135             :     EvpnLocalMcastNode(EvpnManagerPartition *partition, EvpnRoute *route);
     136             :     EvpnLocalMcastNode(EvpnManagerPartition *partition, EvpnRoute *route,
     137             :                        EvpnStatePtr state);
     138             :     virtual ~EvpnLocalMcastNode();
     139             : 
     140             :     /// @brief Handle update of EvpnLocalMcastNode.
     141             :     ///
     142             :     /// We delete and add the Inclusive Multicast route to ensure that all the
     143             :     /// attributes are updated. An in-place update is not always possible since
     144             :     /// the vRouter address is part of the key for the Inclusive Multicast route.
     145             :     virtual void TriggerUpdate();
     146             : 
     147             :     UpdateInfo *GetUpdateInfo(EvpnRoute *route);
     148             :     EvpnRoute *inclusive_mcast_route() { return inclusive_mcast_route_; }
     149             : 
     150             : private:
     151             :     /// @brief Add Inclusive Multicast route for this EvpnLocalMcastNode.
     152             :     /// The attributes are based on the Broadcast MAC route.
     153             :     void AddInclusiveMulticastRoute();
     154             : 
     155             :     /// @brief Delete Inclusive Multicast route for this EvpnLocalMcastNode.
     156             :     void DeleteInclusiveMulticastRoute();
     157             : 
     158             :     EvpnRoute *inclusive_mcast_route_;
     159             : 
     160             :     DISALLOW_COPY_AND_ASSIGN(EvpnLocalMcastNode);
     161             : };
     162             : 
     163             : 
     164             : /// @brief This class represents (in the context of an EVPN instance) a remote
     165             : /// vRouter or PE discovered via BGP.  An EvpnRemoteMcastNode is created and
     166             : /// associated as DBState with the Inclusive Multicast route in question.
     167             : ///
     168             : /// An EvpnRemoteMcastNode also gets created for the Inclusive Multicast route
     169             : /// that's added for each EvpnLocalMcastNode. This is required only to support
     170             : /// test mode where vRouter acts like PE that doesn't support edge replication.
     171             : class EvpnRemoteMcastNode : public EvpnMcastNode {
     172             : public:
     173             :     EvpnRemoteMcastNode(EvpnManagerPartition *partition, EvpnRoute *route);
     174             :     EvpnRemoteMcastNode(EvpnManagerPartition *partition, EvpnRoute *route,
     175             :                         EvpnStatePtr state);
     176             :     virtual ~EvpnRemoteMcastNode();
     177             : 
     178             :     /// @brief Handle update of EvpnRemoteMcastNode.
     179             :     virtual void TriggerUpdate();
     180             : 
     181             : private:
     182             :     DISALLOW_COPY_AND_ASSIGN(EvpnRemoteMcastNode);
     183             : };
     184             : 
     185             : 
     186             : /// @brief This class represents a remote EVPN segment that has 2 or more PEs 
     187             : /// that are multi-homed to it. An EvpnSegment is created when we see a MAC 
     188             : /// route with a non-NULL ESI or when we see an AD route for the ESI in question.
     189             : ///
     190             : /// An EvpnSegment contains a vector of lists of MAC routes that are dependent
     191             : /// on it. There's a list entry in the vector for each DB partition.  All the
     192             : /// MAC routes in a given partition that are associated with the EvpnSegment are
     193             : /// in inserted in the list for that partition. The lists are updated as and
     194             : /// when the EvpnSegment for MAC routes is updated.
     195             : ///
     196             : /// An EvpnSegment contains a list of Remote PEs that have advertised per-ESI
     197             : /// AD routes for the EVPN segment in question. The list is updated when paths
     198             : /// are added/deleted from the AD route. A change in the contents of the list
     199             : /// triggers an update of all dependent MAC routes, so that their aliased paths
     200             : /// can be updated. The single-active state of the EvpnSegment is also updated
     201             : /// when the PE list is updated. The PE list is updated from the context of the
     202             : /// bgp::EvpnSegment task.
     203             : class EvpnSegment : public DBState {
     204             : public:
     205             :     EvpnSegment(EvpnManager *evpn_manager, const EthernetSegmentId &esi);
     206             :     ~EvpnSegment();
     207             : 
     208             :     class RemotePe {
     209             :     public:
     210             :         RemotePe(const BgpPath *path);
     211             : 
     212             :         /// @brief Equality operator for EvpnSegment::RemotePe.
     213             :         /// Do not compare esi_valid and single_active fields since they are
     214             :         /// derived.
     215             :         bool operator==(const RemotePe &rhs) const;
     216             : 
     217             :         bool esi_valid;
     218             :         bool single_active;
     219             :         const IPeer *peer;
     220             :         BgpAttrPtr attr;
     221             :         uint32_t flags;
     222             :         BgpPath::PathSource src;
     223             :     };
     224             : 
     225             :     typedef std::list<RemotePe> RemotePeList;
     226             :     typedef RemotePeList::const_iterator const_iterator;
     227             : 
     228         129 :     const_iterator begin() const { return pe_list_.begin(); }
     229         243 :     const_iterator end() const { return pe_list_.end(); }
     230             : 
     231             :     /// @brief Add the given MAC route as a dependent of this EvpnSegment.
     232             :     void AddMacRoute(size_t part_id, EvpnRoute *route);
     233             : 
     234             :     /// @brief Delete the given MAC route as a dependent of this EvpnSegment.
     235             :     /// Trigger deletion of the EvpnSegment if there are no dependent
     236             :     /// routes in the partition.
     237             :     void DeleteMacRoute(size_t part_id, EvpnRoute *route);
     238             : 
     239             :     /// @brief Trigger an update of all dependent MAC routes for this EvpnSegment.
     240             :     /// Note that the bgp::EvpnSegment task is mutually exclusive with the
     241             :     /// db::DBTable task.
     242             :     void TriggerMacRouteUpdate();
     243             : 
     244             :     /// @brief Update the PE list for this EvpnSegment. This should be called when
     245             :     /// the AutoDisocvery route is updated.
     246             :     /// Return true if there's a change in the PE list i.e. if an entry is
     247             :     /// added, deleted or updated.
     248             :     bool UpdatePeList();
     249             : 
     250             :     /// @brief Return true if it's safe to delete this EvpnSegment.
     251             :     bool MayDelete() const;
     252             : 
     253          67 :     const EthernetSegmentId &esi() const { return esi_; }
     254          63 :     EvpnRoute *esi_ad_route() { return esi_ad_route_; }
     255          22 :     void set_esi_ad_route(EvpnRoute *esi_ad_route) {
     256          22 :         esi_ad_route_ = esi_ad_route;
     257          22 :     }
     258          22 :     void clear_esi_ad_route() { esi_ad_route_ = NULL; }
     259         447 :     bool single_active() const { return single_active_; }
     260             : 
     261             : private:
     262             :     typedef std::set<EvpnRoute *> RouteList;
     263             :     typedef std::vector<RouteList> RouteListVector;
     264             : 
     265             :     EvpnManager *evpn_manager_;
     266             :     EthernetSegmentId esi_;
     267             :     EvpnRoute *esi_ad_route_;
     268             :     bool single_active_;
     269             :     RouteListVector route_lists_;
     270             :     RemotePeList pe_list_;
     271             : 
     272             :     DISALLOW_COPY_AND_ASSIGN(EvpnSegment);
     273             : };
     274             : 
     275             : 
     276             : /// @brief This class represents the EvpnManager state associated with a MAC route.
     277             : ///
     278             : /// In the steady state, a EvpnMacState should exist only for MAC routes that
     279             : /// have a non-zero ESI. The segment_ field is a pointer to the EvpnSegment for
     280             : /// the ESI in question. A EvpnMacState is created from the route listener when
     281             : /// we see a MAC route with a non-zero ESI. It is deleted after processing the
     282             : /// MAC route if the route has been deleted or if it has a zero ESI.
     283             : //
     284             : /// The AliasedPathList keeps track of the aliased BgpPaths that we've added.
     285             : /// An aliased BgpPath is added for each remote PE for all-active EvpnSegment.
     286             : /// The contents of the AliasedPathList are updated when the ESI for the MAC
     287             : /// route changes or when the list of remote PEs for the EvpnSegment changes.
     288             : class EvpnMacState : public DBState {
     289             : public:
     290             :     EvpnMacState(EvpnManager *evpn_manager, EvpnRoute *route);
     291             :     ~EvpnMacState();
     292             : 
     293             :     /// @brief Update aliased BgpPaths for the EvpnRoute based on the remote PEs
     294             :     /// for the EvpnSegment.
     295             :     /// Return true if the list of aliased paths is modified.
     296             :     bool ProcessMacRouteAliasing();
     297             : 
     298         217 :     EvpnSegment *segment() { return segment_; }
     299             :     const EvpnSegment *segment() const { return segment_; }
     300          54 :     void set_segment(EvpnSegment *segment) { segment_ = segment; }
     301          54 :     void clear_segment() { segment_ = NULL; }
     302             : 
     303             : private:
     304             :     typedef std::set<BgpPath *> AliasedPathList;
     305             : 
     306             :     /// @brief Add the BgpPath specified by the iterator to the aliased path list.
     307             :     /// Also inserts the BgpPath to the BgpRoute.
     308             :     void AddAliasedPath(AliasedPathList::const_iterator it);
     309             : 
     310             :     /// @brief Delete the BgpPath specified by the iterator from the aliased path list.
     311             :     /// Also deletes the BgpPath from the BgpRoute.
     312             :     void DeleteAliasedPath(AliasedPathList::const_iterator it);
     313             : 
     314             :     /// @brief Find or create the matching aliased BgpPath.
     315             :     BgpPath *LocateAliasedPath(const EvpnSegment::RemotePe *remote_pe,
     316             :         uint32_t label);
     317             : 
     318             :     EvpnManager *evpn_manager_;
     319             :     EvpnRoute *route_;
     320             :     EvpnSegment *segment_;
     321             :     AliasedPathList aliased_path_list_;
     322             : 
     323             :     DISALLOW_COPY_AND_ASSIGN(EvpnMacState);
     324             : };
     325             : 
     326             : /// @brief This class holds Evpn state for a particular <S,G> at any given time.
     327             : ///
     328             : /// In Evpn state machinery, different types of routes are sent and received at
     329             : /// different phases of processing. This class holds all relevant information
     330             : /// associated with an <S,G>.
     331             : ///
     332             : /// This is a refcounted class which is referred by DB States of different
     333             : /// routes. When the refcount reaches 0, (last referring db state is deleted),
     334             : /// this object is deleted from the container map and then destroyed.
     335             : ///
     336             : /// global_ermvpn_tree_rt_
     337             : ///     This is a reference to GlobalErmVpnRoute associated with the ErmVpnTree
     338             : ///     used in the data plane for this <S,G>. This route is created/updated
     339             : ///     when ErmVpn notifies changes to ermvpn routes.
     340             : ///
     341             : /// states_
     342             : ///     This is the parent map that holds 'this' EvpnState pointer as the value
     343             : ///     for the associated SG key. When the refcount reaches zero, it indicates
     344             : ///     that there is no reference to this state from of the DB States associated
     345             : ///     with any Evpn route. Hence at that time, this state is removed this map
     346             : ///     states_ and destroyed. This map actually sits inside the associated
     347             : ///     EvpnProjectManagerParitition object.
     348             : class EvpnState {
     349             : public:
     350             :     typedef std::set<EvpnRoute *> RoutesSet;
     351             :     typedef std::map<EvpnRoute *, BgpAttrPtr> RoutesMap;
     352             : 
     353             :     /// @brief Simple structure to hold <S,G>. Source as "0.0.0.0" can be used to encode
     354             :     /// <*,G> as well.
     355             :     struct SG {
     356             :         SG(const Ip4Address &source, const Ip4Address &group);
     357             :         SG(const IpAddress &source, const IpAddress &group);
     358             :         explicit SG(const ErmVpnRoute *route);
     359             :         explicit SG(const EvpnRoute *route);
     360             :         bool operator<(const SG &other) const;
     361             : 
     362             :         IpAddress source;
     363             :         IpAddress group;
     364             :     };
     365             : 
     366             :     typedef std::map<SG, EvpnState *> StatesMap;
     367             : 
     368             :     /// @brief A global MVPN state for a given <S.G> within a EvpnProjectManager.
     369             :     EvpnState(const SG &sg, StatesMap *states, EvpnManager* manager);
     370             : 
     371             :     virtual ~EvpnState();
     372             :     const SG &sg() const;
     373             :     ErmVpnRoute *global_ermvpn_tree_rt();
     374             :     const ErmVpnRoute *global_ermvpn_tree_rt() const;
     375             :     void set_global_ermvpn_tree_rt(ErmVpnRoute *global_ermvpn_tree_rt);
     376        9245 :     RoutesSet &smet_routes() { return smet_routes_; }
     377             :     const RoutesSet &smet_routes() const { return smet_routes_; }
     378             :     const StatesMap *states() const { return states_; }
     379       10792 :     StatesMap *states() { return states_; }
     380        2698 :     EvpnManager *manager() { return manager_; }
     381             :     const EvpnManager *manager() const { return manager_; }
     382             :     int refcount() const { return refcount_; }
     383             : 
     384             : private:
     385             :     friend class EvpnMcastNode;
     386             :     friend class EvpnManagerPartition;
     387             : 
     388             :     /// @brief Increment refcont atomically.
     389             :     friend void intrusive_ptr_add_ref(EvpnState *evpn_state);
     390             : 
     391             :     /// @brief Decrement refcount of an evpn_state. If the refcount falls to 1, it implies
     392             :     /// that there is no more reference to this particular state from any other data
     393             :     /// structure. Hence, it can be deleted from the container map and destroyed as
     394             :     /// well.
     395             :     friend void intrusive_ptr_release(EvpnState *evpn_state);
     396             : 
     397             :     const ErmVpnTable *table() const;
     398             : 
     399             :     SG sg_;
     400             :     ErmVpnRoute *global_ermvpn_tree_rt_;
     401             :     RoutesSet smet_routes_;
     402             :     StatesMap *states_;
     403             :     EvpnManager *manager_;
     404             :     std::atomic<int> refcount_;
     405             : 
     406             :     DISALLOW_COPY_AND_ASSIGN(EvpnState);
     407             : };
     408             : 
     409             : 
     410             : /// @brief This class represents a partition in the EvpnManager.
     411             : ///
     412             : /// It is used to keep track of local and remote EvpnMcastNodes that belong to
     413             : /// the partition. The partition is determined on the ethernet tag in the IM
     414             : /// route.
     415             : ///
     416             : /// An EvpnManagerPartition contains a set of MAC routes whose alias paths need
     417             : /// to be updated. Entries are added to the list using the TriggerMacRouteUpdate
     418             : /// method.
     419             : class EvpnManagerPartition {
     420             : public:
     421             :     typedef EvpnState::SG SG;
     422             :     typedef std::map<SG, std::set<EvpnMcastNode *> > EvpnMcastNodeList;
     423             : 
     424             :     EvpnManagerPartition(EvpnManager *evpn_manager, size_t part_id);
     425             :     ~EvpnManagerPartition();
     426             : 
     427             :     /// @brief Get the DBTablePartition for the EvpnTable for our partition id.
     428             :     DBTablePartition *GetTablePartition();
     429             : 
     430             :     /// @brief Notify the Broadcast MAC route for the given EvpnMcastNode.
     431             :     void NotifyNodeRoute(EvpnMcastNode *node);
     432             : 
     433             :     /// @brief Go through all replicator EvpnMcastNodes and notify associated Broadcast
     434             :     /// MAC route.
     435             :     void NotifyReplicatorNodeRoutes();
     436             : 
     437             :     /// @brief Go through all ingress replication client EvpnMcastNodes and notify the
     438             :     /// associated Broadcast MAC route.
     439             :     void NotifyIrClientNodeRoutes(bool exclude_edge_replication_supported);
     440             : 
     441             :     /// @brief Add an EvpnMcastNode to the EvpnManagerPartition.
     442             :     void AddMcastNode(EvpnMcastNode *node, EvpnRoute *route);
     443             : 
     444             :     /// @brief Delete an EvpnMcastNode from the EvpnManagerPartition.
     445             :     void DeleteMcastNode(EvpnMcastNode *node, EvpnRoute *route);
     446             : 
     447             :     /// @brief Update an EvpnMcastNode in the EvpnManagerPartition.
     448             :     /// Need to remove/add EvpnMcastNode from the replicator, leaf and ir client
     449             :     /// lists as appropriate.
     450             :     void UpdateMcastNode(EvpnMcastNode *node, EvpnRoute *route);
     451             : 
     452             :     /// @brief Delete an EvpnMcastNode from the EvpnManagerPartition.
     453             :     bool RemoveMcastNodeFromList(EvpnState::SG &sg, EvpnMcastNode *node,
     454             :                                  EvpnMcastNodeList *list);
     455             : 
     456             :     /// @brief Add the given MAC route to the update list.
     457             :     /// This method gets called either when the MAC route itself changes or when
     458             :     /// the remote PE list for the EvpnSegment of the MAC route gets updated.                             
     459             :     void TriggerMacRouteUpdate(EvpnRoute *route);
     460             : 
     461             :     /// @brief Return true if the EvpnManagerPartition is empty i.e. it has no local
     462             :     /// or remote EvpnMcastNodes and no MAC routes that need to be updated.
     463             :     bool empty() const;
     464             : 
     465             :     const EvpnMcastNodeList &remote_mcast_node_list() const {
     466             :         return remote_mcast_node_list_;
     467             :     }
     468             :     const EvpnMcastNodeList &local_mcast_node_list() const {
     469             :         return local_mcast_node_list_;
     470             :     }
     471             :     const EvpnMcastNodeList &leaf_node_list() const {
     472             :         return leaf_node_list_;
     473             :     }
     474       16122 :     EvpnMcastNodeList *remote_mcast_node_list() {
     475       16122 :         return &remote_mcast_node_list_;
     476             :     }
     477         850 :     EvpnMcastNodeList *local_mcast_node_list() {
     478         850 :         return &local_mcast_node_list_;
     479             :     }
     480         632 :     EvpnMcastNodeList *leaf_node_list() {
     481         632 :         return &leaf_node_list_;
     482             :     }
     483             : 
     484             :     /// @brief Return the BgpServer for the EvpnManagerPartition.
     485             :     BgpServer *server();
     486             : 
     487             :     /// @brief Return the EvpnTable for the EvpnManagerPartition.
     488             :     const EvpnTable *table() const;
     489             : 
     490         108 :     size_t part_id() const { return part_id_; }
     491             : 
     492             : private:
     493             :     friend class EvpnManager;
     494             :     friend class BgpEvpnManagerTest;
     495             : 
     496             :     typedef std::set<EvpnRoute *> EvpnRouteList;
     497             : 
     498             :     /// @brief Process the MAC route update list for this EvpnManagerPartition.
     499             :     bool ProcessMacUpdateList();
     500             : 
     501             :     /// @brief Disable processing of the update list.
     502             :     /// For testing only.
     503             :     void DisableMacUpdateProcessing();
     504             : 
     505             :     /// @brief Enable processing of the update list.
     506             :     /// For testing only.
     507             :     void EnableMacUpdateProcessing();
     508             : 
     509             :     EvpnStatePtr GetState(const SG &sg);
     510             :     EvpnStatePtr GetState(const SG &sg) const;
     511             :     EvpnStatePtr GetState(EvpnRoute *route);
     512             :     EvpnStatePtr LocateState(EvpnRoute *route);
     513             :     EvpnStatePtr LocateState(const SG &sg);
     514             :     EvpnStatePtr CreateState(const SG &sg);
     515      170333 :     const EvpnState::StatesMap &states() const { return states_; }
     516             :     EvpnState::StatesMap &states() { return states_; }
     517             :     bool GetForestNodeAddress(ErmVpnRoute *rt, Ip4Address *address) const;
     518             :     void NotifyForestNode(EvpnRoute *route, ErmVpnTable *table);
     519             : 
     520             :     EvpnManager *evpn_manager_;
     521             :     size_t part_id_;
     522             :     EvpnState::StatesMap states_;;
     523             :     DBTablePartition *table_partition_;
     524             :     EvpnMcastNodeList local_mcast_node_list_;
     525             :     EvpnMcastNodeList remote_mcast_node_list_;
     526             :     EvpnMcastNodeList replicator_node_list_;
     527             :     EvpnMcastNodeList leaf_node_list_;
     528             :     EvpnMcastNodeList regular_node_list_;
     529             :     EvpnMcastNodeList ir_client_node_list_;
     530             :     EvpnRouteList mac_update_list_;
     531             :     boost::scoped_ptr<TaskTrigger> mac_update_trigger_;
     532             : 
     533             :     DISALLOW_COPY_AND_ASSIGN(EvpnManagerPartition);
     534             : };
     535             : 
     536             : 
     537             : /// @brief This class represents the EVPN manager for an EvpnTable in a VRF.
     538             : ///
     539             : /// It is responsible for listening to route notifications on the associated
     540             : /// EvpnTable and implementing glue logic to massage routes so that vRouters
     541             : /// can communicate properly with EVPN PEs.
     542             : ///
     543             : /// It currently implements glue logic for multicast connectivity between the
     544             : /// vRouters and EVPN PEs.  This is achieved by keeping track of local/remote
     545             : /// EvpnMcastNodes and constructing ingress replication OList for any given
     546             : /// EvpnLocalMcastNode when requested.
     547             : ///
     548             : /// It also provides the EvpnTable class with an API to get the UpdateInfo for
     549             : /// a route in EvpnTable.  This is used by the table's Export method to build
     550             : /// the RibOutAttr for the broadcast MAC routes.  This is how we send ingress
     551             : /// replication OList information for an EVPN instance to the XMPP peers.
     552             : ///
     553             : /// An EvpnManager keeps a vector of pointers to EvpnManagerPartitions.  The
     554             : /// number of partitions is the same as the DB partition count.  A partition
     555             : /// contains a subset of EvpnMcastNodes that are created based on EvpnRoutes
     556             : /// in the EvpnTable.
     557             : ///
     558             : /// The concurrency model is that each EvpnManagerPartition can be updated and
     559             : /// can build the ingress replication OLists independently of other partitions.
     560             : ///
     561             : /// The EvpnManager is also used to implement glue logic for EVPN aliasing when
     562             : /// remote PEs have multi-homed segments.
     563             : ///
     564             : /// An EvpnManager maintains a map of EvpnSegments keyed by EthernetSegmentId.
     565             : /// It also keeps sets of EvpnSegments that need to be updated or evaluated for
     566             : /// deletion.
     567             : ///
     568             : /// An EvpnSegment gets added to the segment update list in the EvpnManager when
     569             : /// there's a change in the AD route for the EvpnSegment. The update list gets
     570             : /// processed in the context of the bgp::EvpnSegment task.
     571             : ///
     572             : /// An EvpnSegment gets added to the segment delete list in the EvpnManager when
     573             : /// the PE list becomes empty (bgp::EvpnSegment task) or when the MAC route list
     574             : /// for a given partition becomes empty (db::DBTable task).  The actual call to
     575             : /// MayDelete and subsequent destroy, if appropriate, happens in in the context
     576             : /// of bgp::EvpnSegment task.
     577             : ///
     578             : /// The bgp::EvpnSegment task is mutually exclusive with the db::DBTable task.
     579             : class EvpnManager {
     580             : public:
     581             :     explicit EvpnManager(EvpnTable *table);
     582             :     virtual ~EvpnManager();
     583             : 
     584             :     /// @brief Initialize the EvpnManager. We allocate the EvpnManagerPartitions
     585             :     /// and register a DBListener for the EvpnTable. 
     586             :     virtual void Initialize();
     587             : 
     588             :     /// @brief Terminate the EvpnManager. We free the EvpnManagerPartitions
     589             :     /// and unregister from the EvpnTable.
     590             :     virtual void Terminate();
     591             : 
     592             :     /// @brief Construct export state for the given EvpnRoute. Note that the route
     593             :     /// only needs to be exported to the IPeer from which it was learnt.
     594             :     virtual UpdateInfo *GetUpdateInfo(EvpnRoute *route);
     595             : 
     596             :     /// @brief Get the EvpnManagerPartition for the given partition id.
     597             :     EvpnManagerPartition *GetPartition(size_t part_id);
     598             : 
     599             :     /// @brief Get the DBTablePartition for the EvpnTable for given partition id.
     600             :     DBTablePartition *GetTablePartition(size_t part_id);
     601             : 
     602             :     /// @brief Fill information for introspect command.
     603             :     /// Note that all IM routes are always in partition 0.
     604             :     void FillShowInfo(ShowEvpnTable *sevt) const;
     605             : 
     606             :     BgpServer *server();
     607       71605 :     EvpnTable *table() { return table_; }
     608             :     const EvpnTable *table() const { return table_; }
     609       34818 :     ErmVpnTable *ermvpn_table() { return ermvpn_table_; }
     610       26499 :     const ErmVpnTable *ermvpn_table() const { return ermvpn_table_; }
     611         157 :     int listener_id() const { return listener_id_; }
     612       15593 :     int ermvpn_listener_id() const { return ermvpn_listener_id_; }
     613             : 
     614             :     /// @brief Find or create the EvpnSegment for the given EthernetSegmentId.
     615             :     EvpnSegment *LocateSegment(const EthernetSegmentId &esi);
     616             : 
     617             :     /// @brief Find the EvpnSegment for the given EthernetSegmentId.
     618             :     EvpnSegment *FindSegment(const EthernetSegmentId &esi);
     619             : 
     620             :     /// @brief Trigger deletion of the given EvpnSegment.
     621             :     /// The EvpnSegment is added to a set of EvpnSegments that can potentially
     622             :     /// be deleted. This method can be invoked from multiple db::DBTable tasks
     623             :     /// in parallel when a MAC routes are removed from the dependency list in an
     624             :     /// EvpnSegment. Hence we ensure exclusive access using a write lock.
     625             :     ///
     626             :     /// The list is processed from the context of bgp::EvpnSegment task which is
     627             :     /// mutually exclusive with db::DBTable task.
     628             :     void TriggerSegmentDelete(EvpnSegment *segment);
     629             : 
     630             :     /// @brief Trigger update of the given EvpnSegment.
     631             :     /// The EvpnSegment is added to a set of EvpnSegments for which updates
     632             :     /// need triggered. This method is called in the context of db::DBTable
     633             :     /// task and a task instance of 0 since all AutoDisocvery routes always
     634             :     /// get sharded to partition 0.
     635             :     ///
     636             :     /// The set is processed in the context of bgp::EvpnSegment task, which
     637             :     /// is mutually exclusive with db::DBTable task.
     638             :     void TriggerSegmentUpdate(EvpnSegment *segment);
     639             : 
     640             :     /// @brief Trigger deletion of the EvpnManager and propagate the delete to any
     641             :     /// dependents.
     642             :     void ManagedDelete();
     643             : 
     644             :     /// @brief Initiate shutdown for the EvpnManager.
     645             :     void Shutdown();
     646             : 
     647             :     /// @brief Trigger deletion of the EvpnManager and propagate the delete to any
     648             :     /// dependents.
     649             :     bool MayDelete() const;
     650             : 
     651             :     /// @brief Attempt to enqueue a delete for the EvpnManager.
     652             :     void RetryDelete();
     653             : 
     654             :     /// @brief Return the LifetimeActor for the EvpnManager.
     655             :     LifetimeActor *deleter();
     656             : 
     657             : private:
     658             :     friend class BgpEvpnManagerTest;
     659             :     friend class BgpEvpnAliasingTest;
     660             : 
     661             :     class DeleteActor;
     662             :     typedef std::vector<EvpnManagerPartition *> PartitionList;
     663             :     typedef boost::ptr_map<const EthernetSegmentId, EvpnSegment> SegmentMap;
     664             :     typedef std::set<EvpnSegment *> SegmentSet;
     665             : 
     666             :     /// @brief Allocate the EvpnManagerPartitions.
     667             :     void AllocPartitions();
     668             : 
     669             :     /// @brief Free the EvpnManagerPartitions.
     670             :     void FreePartitions();
     671             : 
     672             :     /// @brief DBListener callback handler for AutoDisocvery routes in the EvpnTable.
     673             :     void AutoDiscoveryRouteListener(EvpnRoute *route);
     674             : 
     675             :     /// @brief DBListener callback handler for MacAdvertisement routes in the EvpnTable.
     676             :     void MacAdvertisementRouteListener(EvpnManagerPartition *partition,
     677             :         EvpnRoute *route);
     678             : 
     679             :     /// @brief DBListener callback handler for InclusiveMulticast routes in the EvpnTable.
     680             :     void InclusiveMulticastRouteListener(EvpnManagerPartition *partition,
     681             :         EvpnRoute *route);
     682             :         
     683             :     /// @brief DBListener callback handler for SelectiveMulticast routes in the EvpnTable.
     684             :     void SelectiveMulticastRouteListener(EvpnManagerPartition *partition,
     685             :         EvpnRoute *route);
     686             : 
     687             :     /// @brief DBListener callback handler for the EvpnTable.
     688             :     void RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry);
     689             : 
     690             :     /// @brief ErmVpnTable route listener callback function.
     691             :     ///
     692             :     /// Process changes (create/update/delete) to GlobalErmVpnRoute in vrf.ermvpn.0
     693             :     void ErmVpnRouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry);
     694             : 
     695             :     /// @brief Process the set of EvpnSegments that can potentially be deleted.
     696             :     /// Remove the EvpnSegment from the map and destroy if it's fine to
     697             :     /// to delete the EvpnSegment.
     698             :     bool ProcessSegmentDeleteSet();
     699             : 
     700             :     /// @brief Process the set of EvpnSegments that need to be updated.
     701             :     ///
     702             :     /// Go through each EvpnSegment and update it's PE list. Trigger updates
     703             :     /// of all it's dependent MAC routes if there's a change in the PE list.
     704             :     bool ProcessSegmentUpdateSet();
     705             : 
     706             :     /// @brief Check whether an ErmVpnRoute is locally originated GlobalTreeRoute.
     707             :     bool IsUsableGlobalTreeRootRoute(ErmVpnRoute *ermvpn_route) const;
     708             : 
     709             :     /// @brief Disable processing of the update list.
     710             :     /// For testing only.
     711             :     void DisableSegmentUpdateProcessing();
     712             : 
     713             :     /// @brief Enable processing of the update list.
     714             :     /// For testing only.
     715             :     void EnableSegmentUpdateProcessing();
     716             : 
     717             :     /// @brief Disable processing of the delete list.
     718             :     /// For testing only.
     719             :     void DisableSegmentDeleteProcessing();
     720             : 
     721             :     /// @brief Enable processing of the delete list.
     722             :     /// For testing only.
     723             :     void EnableSegmentDeleteProcessing();
     724             : 
     725             :     /// @brief Disable processing of the update lists in all partitions.
     726             :     /// For testing only.
     727             :     void DisableMacUpdateProcessing();
     728             : 
     729             :     /// @brief Enable processing of the update lists in all partitions.
     730             :     /// For testing only.    
     731             :     void EnableMacUpdateProcessing();
     732             : 
     733             :     /// @brief Set DB State and update count.
     734             :     void SetDBState(EvpnRoute *route, EvpnMcastNode *dbstate);
     735             : 
     736             :     /// @brief Create DB State and update count. If there is no DB State associated in the
     737             :     /// table, resume table deletion if the deletion was pending.
     738             :     void ClearDBState(EvpnRoute *route);
     739             : 
     740             :     EvpnTable *table_;
     741             :     ErmVpnTable *ermvpn_table_;
     742             :     int listener_id_;
     743             :     int ermvpn_listener_id_;
     744             :     std::atomic<int> db_states_count_;
     745             :     PartitionList partitions_;
     746             :     tbb::spin_rw_mutex segment_rw_mutex_;
     747             :     SegmentMap segment_map_;
     748             :     SegmentSet segment_delete_set_;
     749             :     SegmentSet segment_update_set_;
     750             :     boost::scoped_ptr<TaskTrigger> segment_delete_trigger_;
     751             :     boost::scoped_ptr<TaskTrigger> segment_update_trigger_;
     752             : 
     753             :     boost::scoped_ptr<DeleteActor> deleter_;
     754             :     LifetimeRef<EvpnManager> table_delete_ref_;
     755             : 
     756             :     DISALLOW_COPY_AND_ASSIGN(EvpnManager);
     757             : };
     758             : 
     759             : /// @brief Increment refcont atomically.
     760       23388 : inline void intrusive_ptr_add_ref(EvpnState *evpn_state) {
     761       23388 :     evpn_state->refcount_.fetch_add(1);
     762       23388 : }
     763             : 
     764             : /// @brief Decrement refcount of an evpn_state. If the refcount falls to 1, it implies
     765             : /// that there is no more reference to this particular state from any other data
     766             : /// structure. Hence, it can be deleted from the container map and destroyed as
     767             : /// well.
     768       23388 : inline void intrusive_ptr_release(EvpnState *evpn_state) {
     769       23388 :     int prev = evpn_state->refcount_.fetch_sub(1);
     770       23388 :     if (prev > 1)
     771       20690 :         return;
     772        2698 :     if (evpn_state->states()) {
     773             :         EvpnState::StatesMap::iterator iter =
     774        2698 :             evpn_state->states()->find(evpn_state->sg());
     775        2698 :         if (iter != evpn_state->states()->end()) {
     776        2698 :             assert(iter->second == evpn_state);
     777        2698 :             evpn_state->states()->erase(iter);
     778             : 
     779             :             // Attempt project manager deletion as it could be held up due to
     780             :             // this map being non-empty so far..
     781        2698 :             if (evpn_state->manager()->deleter()->IsDeleted())
     782           0 :                 evpn_state->manager()->deleter()->RetryDelete();
     783             :         }
     784             :     }
     785        2698 :     delete evpn_state;
     786             : }
     787             : 
     788             : #define EVPN_RT_LOG(rt, ...) \
     789             :     RTINSTANCE_LOG(EvpnRoute, this->table()->routing_instance(), \
     790             :                    SandeshLevel::UT_DEBUG, \
     791             :                    RTINSTANCE_LOG_FLAG_ALL, \
     792             :                    (rt)->GetPrefix().source().to_string(), \
     793             :                    (rt)->GetPrefix().group().to_string(), \
     794             :                    (rt)->ToString(), ##__VA_ARGS__)
     795             : 
     796             : #define EVPN_ERMVPN_RT_LOG(rt, ...) \
     797             :     RTINSTANCE_LOG(EvpnErmVpnRoute, this->table()->routing_instance(), \
     798             :                    SandeshLevel::UT_DEBUG, \
     799             :                    RTINSTANCE_LOG_FLAG_ALL, \
     800             :                    (rt)->GetPrefix().source().to_string(), \
     801             :                    (rt)->GetPrefix().group().to_string(), \
     802             :                    (rt)->ToString(), ##__VA_ARGS__)
     803             : 
     804             : #define EVPN_TRACE(type, ...) \
     805             :     RTINSTANCE_LOG(type, this->table()->routing_instance(), \
     806             :         SandeshLevel::UT_DEBUG, RTINSTANCE_LOG_FLAG_ALL, ##__VA_ARGS__)
     807             : 
     808             : #endif  // SRC_BGP_BGP_EVPN_H_

Generated by: LCOV version 1.14