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

Generated by: LCOV version 1.14