LCOV - code coverage report
Current view: top level - bgp - bgp_evpn.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 980 0.0 %
Date: 2026-09-28 02:13:17 Functions: 0 117 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/bgp_evpn.h"
       6             : 
       7             : #include <boost/foreach.hpp>
       8             : 
       9             : #include <algorithm>
      10             : #include <string>
      11             : 
      12             : #include "base/set_util.h"
      13             : #include "base/task_annotations.h"
      14             : #include "bgp/bgp_log.h"
      15             : #include "bgp/bgp_multicast.h"
      16             : #include "bgp/bgp_peer_types.h"
      17             : #include "bgp/bgp_server.h"
      18             : #include "bgp/bgp_update.h"
      19             : #include "bgp/ermvpn/ermvpn_route.h"
      20             : #include "bgp/ermvpn/ermvpn_table.h"
      21             : #include "bgp/evpn/evpn_table.h"
      22             : #include "bgp/extended-community/multicast_flags.h"
      23             : #include "bgp/routing-instance/routing_instance.h"
      24             : #include "bgp/routing-instance/routing_instance_analytics_types.h"
      25             : #include "bgp/routing-instance/routing_instance_log.h"
      26             : 
      27             : using std::pair;
      28             : using std::set;
      29             : using std::sort;
      30             : using std::string;
      31             : using std::vector;
      32             : 
      33             : // A global MVPN state for a given <S.G> within a EvpnProjectManager.
      34           0 : EvpnState::EvpnState(const SG &sg, StatesMap *states, EvpnManager *manager) :
      35           0 :         sg_(sg), global_ermvpn_tree_rt_(NULL), states_(states),
      36           0 :         manager_(manager) {
      37           0 :     refcount_ = 0;
      38           0 : }
      39             : 
      40           0 : EvpnState::~EvpnState() {
      41           0 :     assert(!global_ermvpn_tree_rt_);
      42           0 :     EVPN_TRACE(EvpnStateCreate, sg_.source.to_string(), sg_.group.to_string());
      43           0 : }
      44             : 
      45           0 : const ErmVpnTable *EvpnState::table() const {
      46           0 :     return manager_ ? manager_->ermvpn_table() : NULL;
      47             : }
      48             : 
      49             : class EvpnManager::DeleteActor : public LifetimeActor {
      50             : public:
      51           0 :     explicit DeleteActor(EvpnManager *evpn_manager)
      52           0 :         : LifetimeActor(evpn_manager->server()->lifetime_manager()),
      53           0 :           evpn_manager_(evpn_manager) {
      54           0 :     }
      55           0 :     virtual ~DeleteActor() {
      56           0 :     }
      57             : 
      58           0 :     virtual bool MayDelete() const {
      59           0 :         CHECK_CONCURRENCY("bgp::Config");
      60           0 :         return evpn_manager_->MayDelete();
      61             :     }
      62             : 
      63           0 :     virtual void Shutdown() {
      64           0 :         evpn_manager_->Shutdown();
      65           0 :     }
      66             : 
      67           0 :     virtual void Destroy() {
      68           0 :         evpn_manager_->table_->DestroyEvpnManager();
      69           0 :     }
      70             : 
      71             : private:
      72             :     EvpnManager *evpn_manager_;
      73             : };
      74             : 
      75             : //
      76             : // Constructor for EvpnMcastNode. The type indicates whether this is a local
      77             : // or remote EvpnMcastNode.
      78             : //
      79           0 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
      80           0 :     EvpnRoute *route, uint8_t type)
      81           0 :     : partition_(partition),
      82           0 :       state_(NULL),
      83           0 :       route_(route),
      84           0 :       type_(type),
      85           0 :       label_(0),
      86           0 :       edge_replication_not_supported_(false),
      87           0 :       assisted_replication_supported_(false),
      88           0 :       assisted_replication_leaf_(false) {
      89           0 :     UpdateAttributes(route);
      90           0 : }
      91             : 
      92           0 : EvpnMcastNode::EvpnMcastNode(EvpnManagerPartition *partition,
      93           0 :     EvpnRoute *route, uint8_t type, EvpnStatePtr state)
      94           0 :     : partition_(partition),
      95           0 :       state_(state),
      96           0 :       route_(route),
      97           0 :       type_(type),
      98           0 :       label_(0),
      99           0 :       edge_replication_not_supported_(false),
     100           0 :       assisted_replication_supported_(false),
     101           0 :       assisted_replication_leaf_(false) {
     102           0 :     if (route)
     103           0 :         UpdateAttributes(route);
     104           0 : }
     105             : 
     106             : //
     107             : // Destructor for EvpnMcastNode.
     108             : //
     109           0 : EvpnMcastNode::~EvpnMcastNode() {
     110           0 :     set_state(NULL);
     111           0 : }
     112             : 
     113             : //
     114             : // Update the label and attributes for a EvpnMcastNode.
     115             : // Return true if either of them changed.
     116             : //
     117           0 : bool EvpnMcastNode::UpdateAttributes(EvpnRoute *route) {
     118           0 :     bool changed = false;
     119           0 :     const BgpPath *path = route->BestPath();
     120           0 :     if (path->GetLabel() != label_) {
     121           0 :         label_ = path->GetLabel();
     122           0 :         changed = true;
     123             :     }
     124           0 :     if (path->GetAttr() != attr_) {
     125           0 :         attr_ = path->GetAttr();
     126           0 :         changed = true;
     127             :     }
     128             : 
     129           0 :     const PmsiTunnel *pmsi_tunnel = attr_->pmsi_tunnel();
     130           0 :     uint8_t ar_type = 0;
     131           0 :     bool edge_replication_not_supported = false;
     132           0 :     if (pmsi_tunnel) {
     133           0 :         ar_type = pmsi_tunnel->tunnel_flags() &
     134             :                   PmsiTunnelSpec::AssistedReplicationType;
     135           0 :         if ((pmsi_tunnel->tunnel_flags() &
     136           0 :              PmsiTunnelSpec::EdgeReplicationSupported) == 0) {
     137           0 :             edge_replication_not_supported = true;
     138             :         }
     139           0 :         if (replicator_address_ != pmsi_tunnel->identifier()) {
     140           0 :             replicator_address_ = pmsi_tunnel->identifier();
     141           0 :             changed = true;
     142             :         }
     143             :     }
     144             : 
     145           0 :     if (edge_replication_not_supported != edge_replication_not_supported_) {
     146           0 :         edge_replication_not_supported_ = edge_replication_not_supported;
     147           0 :         changed = true;
     148             :     }
     149             : 
     150           0 :     bool assisted_replication_supported = false;
     151           0 :     if (ar_type == PmsiTunnelSpec::ARReplicator)
     152           0 :         assisted_replication_supported = true;
     153           0 :     if (assisted_replication_supported != assisted_replication_supported_) {
     154           0 :         assisted_replication_supported_ = assisted_replication_supported;
     155           0 :         changed = true;
     156             :     }
     157             : 
     158           0 :     bool assisted_replication_leaf = false;
     159           0 :     if (ar_type == PmsiTunnelSpec::ARLeaf)
     160           0 :         assisted_replication_leaf = true;
     161           0 :     if (assisted_replication_leaf != assisted_replication_leaf_) {
     162           0 :         assisted_replication_leaf_ = assisted_replication_leaf;
     163           0 :         changed = true;
     164             :     }
     165             : 
     166           0 :     if (address_ != path->GetAttr()->nexthop().to_v4()) {
     167           0 :         address_ = path->GetAttr()->nexthop().to_v4();
     168           0 :         changed = true;
     169             :     }
     170             : 
     171           0 :     return changed;
     172             : }
     173             : 
     174             : //
     175             : // Constructor for EvpnLocalMcastNode.
     176             : //
     177             : // Add an Inclusive Multicast route corresponding to Broadcast MAC route.
     178             : //
     179             : // Need to Notify the Broadcast MAC route so that the table Export method
     180             : // can run and build the OList. OList is not built till EvpnLocalMcastNode
     181             : // has been created.
     182             : //
     183           0 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
     184           0 :     EvpnRoute *route)
     185             :     : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode),
     186           0 :       inclusive_mcast_route_(NULL) {
     187           0 :     AddInclusiveMulticastRoute();
     188           0 :     DBTablePartition *tbl_partition = partition_->GetTablePartition();
     189           0 :     tbl_partition->Notify(route_);
     190           0 : }
     191             : 
     192           0 : EvpnLocalMcastNode::EvpnLocalMcastNode(EvpnManagerPartition *partition,
     193           0 :     EvpnRoute *route, EvpnStatePtr state)
     194             :     : EvpnMcastNode(partition, route, EvpnMcastNode::LocalNode, state),
     195           0 :       inclusive_mcast_route_(NULL) {
     196           0 :     if (!route)
     197           0 :         return;
     198           0 :     AddInclusiveMulticastRoute();
     199           0 :     DBTablePartition *tbl_partition = partition_->GetTablePartition();
     200           0 :     tbl_partition->Notify(route_);
     201           0 : }
     202             : 
     203             : //
     204             : // Destructor for EvpnLocalMcastNode.
     205             : //
     206           0 : EvpnLocalMcastNode::~EvpnLocalMcastNode() {
     207           0 :     DeleteInclusiveMulticastRoute();
     208           0 : }
     209             : 
     210             : //
     211             : // Add Inclusive Multicast route for this EvpnLocalMcastNode.
     212             : // The attributes are based on the Broadcast MAC route.
     213             : //
     214           0 : void EvpnLocalMcastNode::AddInclusiveMulticastRoute() {
     215             :     // No need to create IMET route if group is specified
     216           0 :     if (!route_->GetPrefix().group().is_unspecified())
     217           0 :         return;
     218           0 :     assert(!inclusive_mcast_route_);
     219           0 :     if (label_ == 0)
     220           0 :         return;
     221             : 
     222             :     // Construct the prefix and route key.
     223             :     // Build the RD using the TOR IP address, not the TOR agent IP address.
     224             :     // This ensures that the MAC broadcast route from the primary and backup
     225             :     // TOR Agents results in the same Inclusive Multicast prefix.
     226           0 :     const EvpnPrefix &mac_prefix = route_->GetPrefix();
     227             :     RouteDistinguisher rd(
     228           0 :         address_.to_ulong(), mac_prefix.route_distinguisher().GetVrfId());
     229           0 :     EvpnPrefix prefix(rd, mac_prefix.tag(), address_);
     230           0 :     EvpnRoute rt_key(prefix);
     231             : 
     232             :     // Find or create the route.
     233           0 :     DBTablePartition *tbl_partition = partition_->GetTablePartition();
     234           0 :     EvpnRoute *route = static_cast<EvpnRoute *>(tbl_partition->Find(&rt_key));
     235           0 :     if (!route) {
     236           0 :         route = new EvpnRoute(prefix);
     237           0 :         tbl_partition->Add(route);
     238             :     } else {
     239           0 :         route->ClearDelete();
     240             :     }
     241             :     // Add MulticastFlags community to specify that it supports SMET route
     242           0 :     ExtCommunity::ExtCommunityList mcastFlags;
     243           0 :     mcastFlags.push_back(MulticastFlags().GetExtCommunity());
     244           0 :     ExtCommunityPtr ext_community = partition_->server()->extcomm_db()->
     245           0 :             ReplaceMFlagsAndLocate(attr_->ext_community(), mcastFlags);
     246           0 :     attr_ = partition_->server()->attr_db()->ReplaceExtCommunityAndLocate(
     247           0 :         attr_.get(), ext_community);
     248             : 
     249             :     // Add a path with source BgpPath::Local and the peer address as path_id.
     250           0 :     uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
     251           0 :     BgpPath *path = new BgpPath(path_id, BgpPath::Local, attr_, 0, label_);
     252           0 :     route->InsertPath(path);
     253           0 :     inclusive_mcast_route_ = route;
     254           0 :     tbl_partition->Notify(inclusive_mcast_route_);
     255           0 :     BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
     256             :         route, "Insert new Local path");
     257           0 : }
     258             : 
     259             : //
     260             : // Delete Inclusive Multicast route for this EvpnLocalMcastNode.
     261             : //
     262           0 : void EvpnLocalMcastNode::DeleteInclusiveMulticastRoute() {
     263           0 :     if (!inclusive_mcast_route_)
     264           0 :         return;
     265             : 
     266           0 :     const EvpnPrefix &mac_prefix = route_->GetPrefix();
     267           0 :     uint32_t path_id = mac_prefix.route_distinguisher().GetAddress();
     268           0 :     DBTablePartition *tbl_partition = partition_->GetTablePartition();
     269           0 :     inclusive_mcast_route_->RemovePath(BgpPath::Local, path_id);
     270           0 :     BGP_LOG_ROUTE(partition_->table(), static_cast<IPeer *>(NULL),
     271             :         inclusive_mcast_route_, "Delete Local path");
     272             : 
     273           0 :     if (!inclusive_mcast_route_->HasPaths()) {
     274           0 :         tbl_partition->Delete(inclusive_mcast_route_);
     275             :     } else {
     276           0 :         tbl_partition->Notify(inclusive_mcast_route_);
     277             :     }
     278           0 :     inclusive_mcast_route_ = NULL;
     279             : }
     280             : 
     281             : //
     282             : // Handle update of EvpnLocalMcastNode.
     283             : //
     284             : // We delete and add the Inclusive Multicast route to ensure that all the
     285             : // attributes are updated. An in-place update is not always possible since
     286             : // the vRouter address is part of the key for the Inclusive Multicast route.
     287             : //
     288           0 : void EvpnLocalMcastNode::TriggerUpdate() {
     289           0 :     DeleteInclusiveMulticastRoute();
     290           0 :     AddInclusiveMulticastRoute();
     291           0 : }
     292             : 
     293             : //
     294             : // Construct an UpdateInfo with the RibOutAttr that needs to be advertised to
     295             : // the IPeer for the EvpnRoute associated with this EvpnLocalMcastNode. This
     296             : // is used the Export method of the EvpnTable. It is expected that the caller
     297             : // fills in the target RibPeerSet in the UpdateInfo.
     298             : //
     299             : // The main functionality here is to build a per-IPeer BgpOList from the list
     300             : // of EvpnRemoteMcastNodes.
     301             : //
     302           0 : UpdateInfo *EvpnLocalMcastNode::GetUpdateInfo(EvpnRoute *route) {
     303           0 :     CHECK_CONCURRENCY("db::DBTable");
     304             : 
     305             :     // Nothing to send for a leaf as it already knows the replicator-address.
     306           0 :     if (assisted_replication_leaf_)
     307           0 :         return NULL;
     308             : 
     309           0 :     const RoutingInstance *rti = partition_->table()->routing_instance();
     310           0 :     bool pbb_evpn_enable = rti->virtual_network_pbb_evpn_enable();
     311           0 :     uint32_t local_ethernet_tag = route_->GetPrefix().tag();
     312             : 
     313           0 :     EvpnState::SG sg = EvpnState::SG(route->GetPrefix().source(),
     314           0 :                                      route->GetPrefix().group());
     315             :     // Go through list of EvpnRemoteMcastNodes and build the BgpOList.
     316           0 :     BgpOListSpec olist_spec(BgpAttribute::OList);
     317           0 :     if (partition_->remote_mcast_node_list()->count(sg)) {
     318           0 :         set<EvpnMcastNode*> nodes = (*partition_->remote_mcast_node_list())[sg];
     319           0 :         BOOST_FOREACH(EvpnMcastNode *node, nodes) {
     320           0 :             if (node->address() == address_)
     321           0 :                 continue;
     322           0 :             if (node->assisted_replication_leaf())
     323           0 :                 continue;
     324           0 :             if (!edge_replication_not_supported_ &&
     325           0 :                 !node->edge_replication_not_supported())
     326           0 :                 continue;
     327           0 :             uint32_t remote_ethernet_tag = node->route()->GetPrefix().tag();
     328             : 
     329           0 :             if (pbb_evpn_enable && remote_ethernet_tag &&
     330             :                 (local_ethernet_tag != remote_ethernet_tag))
     331           0 :                 continue;
     332             : 
     333           0 :             const ExtCommunity *extcomm = node->attr()->ext_community();
     334           0 :             BgpOListElem elem(node->address(), node->label(),
     335           0 :                     extcomm ? extcomm->GetTunnelEncap() : vector<string>());
     336           0 :             olist_spec.elements.push_back(elem);
     337           0 :         }
     338           0 :     }
     339             : 
     340             :     // Go through list of leaf EvpnMcastNodes and build the leaf BgpOList.
     341           0 :     BgpOListSpec leaf_olist_spec(BgpAttribute::LeafOList);
     342           0 :     if (assisted_replication_supported_) {
     343           0 :         if (partition_->leaf_node_list()->count(sg)) {
     344           0 :             set<EvpnMcastNode*> nodes = (*partition_->leaf_node_list())[sg];
     345           0 :             BOOST_FOREACH(EvpnMcastNode *node, nodes) {
     346           0 :                 if (node->replicator_address() != address_)
     347           0 :                     continue;
     348             : 
     349           0 :                 const ExtCommunity *extcomm = node->attr()->ext_community();
     350           0 :                 BgpOListElem elem(node->address(), node->label(),
     351           0 :                         extcomm ? extcomm->GetTunnelEncap() : vector<string>());
     352           0 :                 leaf_olist_spec.elements.push_back(elem);
     353           0 :             }
     354           0 :         }
     355             :     }
     356             : 
     357             :     // Bail if both BgpOLists are empty.
     358           0 :     if (olist_spec.elements.empty() && leaf_olist_spec.elements.empty())
     359           0 :         return NULL;
     360             : 
     361             :     // Add BgpOList and leaf BgpOList to RibOutAttr for broadcast MAC route.
     362           0 :     BgpAttrDB *attr_db = partition_->server()->attr_db();
     363           0 :     BgpAttrPtr attr = attr_db->ReplaceOListAndLocate(attr_.get(), &olist_spec);
     364           0 :     attr = attr_db->ReplaceLeafOListAndLocate(attr.get(), &leaf_olist_spec);
     365             : 
     366           0 :     UpdateInfo *uinfo = new UpdateInfo;
     367             :     uinfo->roattr =
     368           0 :         RibOutAttr(partition_->table(), route_, attr.get(), 0, false, true);
     369           0 :     return uinfo;
     370           0 : }
     371             : 
     372             : //
     373             : // Constructor for EvpnRemoteMcastNode.
     374             : //
     375           0 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
     376           0 :     EvpnRoute *route)
     377           0 :     : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode) {
     378           0 : }
     379             : 
     380           0 : EvpnRemoteMcastNode::EvpnRemoteMcastNode(EvpnManagerPartition *partition,
     381           0 :     EvpnRoute *route, EvpnStatePtr state)
     382           0 :     : EvpnMcastNode(partition, route, EvpnMcastNode::RemoteNode, state) {
     383           0 : }
     384             : 
     385             : //
     386             : // Destructor for EvpnRemoteMcastNode.
     387             : //
     388           0 : EvpnRemoteMcastNode::~EvpnRemoteMcastNode() {
     389           0 : }
     390             : 
     391             : //
     392             : // Handle update of EvpnRemoteMcastNode.
     393             : //
     394           0 : void EvpnRemoteMcastNode::TriggerUpdate() {
     395           0 : }
     396             : 
     397             : //
     398             : // Constructor for EvpnSegment.
     399             : //
     400           0 : EvpnSegment::EvpnSegment(EvpnManager *manager, const EthernetSegmentId &esi)
     401           0 :   : evpn_manager_(manager),
     402           0 :     esi_(esi),
     403           0 :     esi_ad_route_(NULL),
     404           0 :     single_active_(true),
     405           0 :     route_lists_(DB::PartitionCount()) {
     406           0 : }
     407             : 
     408             : //
     409             : // Destructor for EvpnSegment.
     410             : //
     411           0 : EvpnSegment::~EvpnSegment() {
     412           0 :     assert(!esi_ad_route_);
     413           0 :     assert(pe_list_.empty());
     414           0 : }
     415             : 
     416             : //
     417             : // Add the given MAC route as a dependent of this EvpnSegment.
     418             : //
     419           0 : void EvpnSegment::AddMacRoute(size_t part_id, EvpnRoute *route) {
     420           0 :     pair<RouteList::iterator, bool> ret = route_lists_[part_id].insert(route);
     421           0 :     assert(ret.second);
     422           0 : }
     423             : 
     424             : //
     425             : // Delete the given MAC route as a dependent of this EvpnSegment.
     426             : // Trigger deletion of the EvpnSegment if there are no dependent
     427             : // routes in the partition.
     428             : //
     429           0 : void EvpnSegment::DeleteMacRoute(size_t part_id, EvpnRoute *route) {
     430           0 :     size_t count = route_lists_[part_id].erase(route);
     431           0 :     assert(count == 1);
     432           0 :     if (route_lists_[part_id].empty())
     433           0 :         evpn_manager_->TriggerSegmentDelete(this);
     434           0 : }
     435             : 
     436             : //
     437             : // Trigger an update of all dependent MAC routes for this EvpnSegment.
     438             : // Note that the bgp::EvpnSegment task is mutually exclusive with the
     439             : // db::DBTable task.
     440             : //
     441           0 : void EvpnSegment::TriggerMacRouteUpdate() {
     442           0 :     CHECK_CONCURRENCY("bgp::EvpnSegment");
     443             : 
     444           0 :     for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
     445           0 :         EvpnManagerPartition *partition = evpn_manager_->GetPartition(part_id);
     446           0 :         BOOST_FOREACH(EvpnRoute *route, route_lists_[part_id]) {
     447           0 :             partition->TriggerMacRouteUpdate(route);
     448             :         }
     449             :     }
     450           0 : }
     451             : 
     452             : //
     453             : // Update the PE list for this EvpnSegment. This should be called when
     454             : // the AutoDisocvery route is updated.
     455             : // Return true if there's a change in the PE list i.e. if an entry is
     456             : // added, deleted or updated.
     457             : //
     458           0 : bool EvpnSegment::UpdatePeList() {
     459           0 :     CHECK_CONCURRENCY("bgp::EvpnSegment");
     460             : 
     461             :     // Mark all entries as invalid.
     462           0 :     for (RemotePeList::iterator it = pe_list_.begin();
     463           0 :         it != pe_list_.end(); ++it) {
     464           0 :         it->esi_valid = false;
     465             :     }
     466             : 
     467             :     // Go through all paths for the route and refresh/update existing entries
     468             :     // or add new ones as necessary. Remember that there was a change in the
     469             :     // list if any element changed or is added/deleted.
     470           0 :     bool changed = false;
     471           0 :     for (Route::PathList::const_iterator path_it =
     472           0 :          esi_ad_route_->GetPathList().begin();
     473           0 :          path_it != esi_ad_route_->GetPathList().end(); ++path_it) {
     474             :         const BgpPath *path =
     475           0 :             static_cast<const BgpPath *>(path_it.operator->());
     476           0 :         const BgpAttr *attr = path->GetAttr();
     477             : 
     478             :         // Skip non-VXLAN paths for now.
     479           0 :         const ExtCommunity *extcomm = attr->ext_community();
     480           0 :         if (!extcomm || !extcomm->ContainsTunnelEncapVxlan())
     481           0 :             continue;
     482             : 
     483             :         // Go through existing pe list and try to find the RemotePe.
     484           0 :         bool found = false;
     485           0 :         RemotePe remote_pe(path);
     486           0 :         for (RemotePeList::iterator it = pe_list_.begin();
     487           0 :             it != pe_list_.end(); ++it) {
     488             :             // Skip if the nexthop doesn't match.
     489           0 :             if (it->attr->nexthop() != remote_pe.attr->nexthop())
     490           0 :                 continue;
     491             : 
     492             :             // We're done if there are multiple paths for the same remote PE
     493             :             // e.g. when a pair of route reflectors is being used.
     494           0 :             if (it->esi_valid) {
     495           0 :                 found = true;
     496           0 :                 break;
     497             :             }
     498             : 
     499             :             // Check if we have a match.
     500           0 :             if (*it == remote_pe) {
     501           0 :                 it->esi_valid = true;
     502           0 :                 found = true;
     503           0 :                 break;
     504             :             }
     505             :         }
     506             : 
     507             :         // Add a new entry to the pe list if we didn't find the RemotePe.
     508           0 :         if (!found) {
     509           0 :             pe_list_.push_back(remote_pe);
     510           0 :             changed = true;
     511             :         }
     512           0 :     }
     513             : 
     514             :     // Erase invalid entries from the list.
     515           0 :     for (RemotePeList::iterator it = pe_list_.begin(), next = it;
     516           0 :         it != pe_list_.end(); it = next) {
     517           0 :         ++next;
     518           0 :         if (!it->esi_valid) {
     519           0 :             pe_list_.erase(it);
     520           0 :             changed = true;
     521             :         }
     522             :     }
     523             : 
     524             :     // Update the single active status of the EvpnSegment itself.
     525           0 :     single_active_ = false;
     526           0 :     for (RemotePeList::iterator it = pe_list_.begin();
     527           0 :         it != pe_list_.end(); ++it) {
     528           0 :         if (it->single_active) {
     529           0 :             single_active_ = true;
     530           0 :             break;
     531             :         }
     532             :     }
     533             : 
     534           0 :     return changed;
     535             : }
     536             : 
     537             : //
     538             : // Return true if it's safe to delete this EvpnSegment.
     539             : //
     540           0 : bool EvpnSegment::MayDelete() const {
     541           0 :     CHECK_CONCURRENCY("bgp::EvpnSegment");
     542             : 
     543             :     // Bail if we have state set on the per-ESI AD route.
     544           0 :     if (esi_ad_route_)
     545           0 :         return false;
     546             : 
     547             :     // Bail if the dependent route list for any partition is not empty.
     548           0 :     for (size_t part_id = 0; part_id < route_lists_.size(); ++part_id) {
     549           0 :         if (!route_lists_[part_id].empty())
     550           0 :             return false;
     551             :     }
     552             : 
     553           0 :     return true;
     554             : }
     555             : 
     556             : //
     557             : // Constructor for EvpnSegment::RemotePe.
     558             : //
     559           0 : EvpnSegment::RemotePe::RemotePe(const BgpPath *path)
     560           0 :   : esi_valid(true),
     561           0 :     single_active(path->GetAttr()->evpn_single_active()),
     562           0 :     peer(path->GetPeer()),
     563           0 :     attr(path->GetAttr()),
     564           0 :     flags(path->GetFlags()),
     565           0 :     src(path->GetSource()) {
     566           0 : }
     567             : 
     568             : //
     569             : // Equality operator for EvpnSegment::RemotePe.
     570             : // Do not compare esi_valid and single_active fields since they are
     571             : // derived.
     572             : //
     573           0 : bool EvpnSegment::RemotePe::operator==(const RemotePe &rhs) const {
     574           0 :     if (peer != rhs.peer)
     575           0 :         return false;
     576           0 :     if (attr != rhs.attr)
     577           0 :         return false;
     578           0 :     if (flags != rhs.flags)
     579           0 :         return false;
     580           0 :     if (src != rhs.src)
     581           0 :         return false;
     582           0 :     return true;
     583             : }
     584             : 
     585             : //
     586             : // Constructor for EvpnMacState.
     587             : //
     588           0 : EvpnMacState::EvpnMacState(EvpnManager *evpn_manager, EvpnRoute *route)
     589           0 :   : evpn_manager_(evpn_manager), route_(route), segment_(NULL) {
     590           0 : }
     591             : 
     592             : //
     593             : // Destructor for EvpnMacState.
     594             : //
     595           0 : EvpnMacState::~EvpnMacState() {
     596           0 :     assert(segment_ == NULL);
     597           0 :     assert(aliased_path_list_.empty());
     598           0 : }
     599             : 
     600             : //
     601             : // Add the BgpPath specified by the iterator to the aliased path list.
     602             : // Also inserts the BgpPath to the BgpRoute.
     603             : //
     604           0 : void EvpnMacState::AddAliasedPath(AliasedPathList::const_iterator it) {
     605           0 :     BgpPath *path = *it;
     606           0 :     const IPeer *peer = path->GetPeer();
     607           0 :     aliased_path_list_.insert(path);
     608           0 :     route_->InsertPath(path);
     609           0 :     BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     610             :         "Added aliased path " << route_->ToString() <<
     611             :         " peer " << (peer ? peer->ToString() : "None") <<
     612             :         " nexthop " << path->GetAttr()->nexthop().to_string() <<
     613             :         " label " << path->GetLabel() <<
     614             :         " in table " << evpn_manager_->table()->name());
     615           0 : }
     616             : 
     617             : //
     618             : // Delete the BgpPath specified by the iterator from the aliased path list.
     619             : // Also deletes the BgpPath from the BgpRoute.
     620             : //
     621           0 : void EvpnMacState::DeleteAliasedPath(AliasedPathList::const_iterator it) {
     622           0 :     BgpPath *path = *it;
     623           0 :     const IPeer *peer = path->GetPeer();
     624           0 :     BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     625             :         "Deleted aliased path " << route_->ToString() <<
     626             :         " peer " << (peer ? peer->ToString() : "None") <<
     627             :         " nexthop " << path->GetAttr()->nexthop().to_string() <<
     628             :         " label " << path->GetLabel() <<
     629             :         " in table " << evpn_manager_->table()->name());
     630           0 :     route_->DeletePath(path);
     631           0 :     aliased_path_list_.erase(it);
     632           0 : }
     633             : 
     634             : //
     635             : // Find or create the matching aliased BgpPath.
     636             : //
     637           0 : BgpPath *EvpnMacState::LocateAliasedPath(
     638             :     const EvpnSegment::RemotePe *remote_pe, uint32_t label) {
     639           0 :     const IPeer *peer = remote_pe->peer;
     640           0 :     const BgpAttr *attr = remote_pe->attr.get();
     641           0 :     uint32_t flags = remote_pe->flags | BgpPath::AliasedPath;
     642           0 :     BgpPath::PathSource src = remote_pe->src;
     643           0 :     for (AliasedPathList::iterator it = aliased_path_list_.begin();
     644           0 :         it != aliased_path_list_.end(); ++it) {
     645           0 :         BgpPath *path = *it;
     646           0 :         if (path->GetPeer() == peer &&
     647           0 :             path->GetAttr() == attr &&
     648           0 :             path->GetFlags() == flags &&
     649           0 :             path->GetLabel() == label) {
     650           0 :             return path;
     651             :         }
     652             :     }
     653             : 
     654           0 :     return (new BgpPath(peer, src, attr, flags, label));
     655             : }
     656             : 
     657             : //
     658             : // Update aliased BgpPaths for the EvpnRoute based on the remote PEs
     659             : // for the EvpnSegment.
     660             : // Return true if the list of aliased paths is modified.
     661             : //
     662           0 : bool EvpnMacState::ProcessMacRouteAliasing() {
     663           0 :     CHECK_CONCURRENCY("db::DBTable");
     664             : 
     665           0 :     const BgpPath *path = route_->BestPath();
     666             : 
     667             :     // Find the remote PE entry that corresponds to the primary path.
     668           0 :     bool found_primary_pe = false;
     669           0 :     EvpnSegment::const_iterator it;
     670           0 :     if (path && segment_ && !segment_->single_active())
     671           0 :         it = segment_->begin();
     672           0 :     for (; path && segment_ && !segment_->single_active() &&
     673           0 :          it != segment_->end(); ++it) {
     674           0 :         if (path->GetAttr()->nexthop() != it->attr->nexthop())
     675           0 :             continue;
     676           0 :         found_primary_pe = true;
     677           0 :         break;
     678             :     }
     679             : 
     680             :     // Go through the remote PE list for the EvpnSegment and build the
     681             :     // list of future aliased paths.
     682           0 :     AliasedPathList future_aliased_path_list;
     683           0 :     if (found_primary_pe && path && segment_ && !segment_->single_active())
     684           0 :         it = segment_->begin();
     685           0 :     for (; found_primary_pe && path && segment_ &&
     686           0 :          !segment_->single_active() && it != segment_->end(); ++it) {
     687             :         // Skip if there's a BGP_XMPP path with the remote PE as nexthop.
     688           0 :         if (route_->FindPath(it->attr->nexthop()))
     689           0 :             continue;
     690             : 
     691             :         // Locate the aliased path using attributes for the remote PE and
     692             :         // label from the primary path.
     693             :         BgpPath *aliased_path =
     694           0 :             LocateAliasedPath(it.operator->(), path->GetLabel());
     695           0 :         future_aliased_path_list.insert(aliased_path);
     696             :     }
     697             : 
     698             :     // Reconcile the current and future aliased paths and notify/delete the
     699             :     // route as appropriate.
     700           0 :     bool modified = set_synchronize(&aliased_path_list_,
     701             :         &future_aliased_path_list,
     702             :         boost::bind(&EvpnMacState::AddAliasedPath, this, _1),
     703             :         boost::bind(&EvpnMacState::DeleteAliasedPath, this, _1));
     704           0 :     return modified;
     705           0 : }
     706             : 
     707             : //
     708             : // Constructor for EvpnManagerPartition.
     709             : //
     710           0 : EvpnManagerPartition::EvpnManagerPartition(EvpnManager *evpn_manager,
     711           0 :     size_t part_id)
     712           0 :     : evpn_manager_(evpn_manager),
     713           0 :       part_id_(part_id),
     714           0 :       mac_update_trigger_(new TaskTrigger(
     715             :           boost::bind(&EvpnManagerPartition::ProcessMacUpdateList, this),
     716           0 :           TaskScheduler::GetInstance()->GetTaskId("db::DBTable"),
     717           0 :           part_id)) {
     718           0 :     table_partition_ = evpn_manager_->GetTablePartition(part_id);
     719           0 : }
     720             : 
     721             : //
     722             : // Destructor for EvpnManagerPartition.
     723             : //
     724           0 : EvpnManagerPartition::~EvpnManagerPartition() {
     725           0 :     assert(local_mcast_node_list_.empty());
     726           0 :     assert(remote_mcast_node_list_.empty());
     727           0 :     assert(mac_update_list_.empty());
     728           0 : }
     729             : 
     730             : //
     731             : // Get the DBTablePartition for the EvpnTable for our partition id.
     732             : //
     733           0 : DBTablePartition *EvpnManagerPartition::GetTablePartition() {
     734           0 :     return evpn_manager_->GetTablePartition(part_id_);
     735             : }
     736             : 
     737             : //
     738             : // Notify the Broadcast MAC route for the given EvpnMcastNode.
     739             : //
     740           0 : void EvpnManagerPartition::NotifyNodeRoute(EvpnMcastNode *node) {
     741           0 :     DBTablePartition *tbl_partition = GetTablePartition();
     742           0 :     tbl_partition->Notify(node->route());
     743           0 : }
     744             : 
     745             : //
     746             : // Go through all replicator EvpnMcastNodes and notify associated Broadcast
     747             : // MAC route.
     748             : //
     749           0 : void EvpnManagerPartition::NotifyReplicatorNodeRoutes() {
     750           0 :     DBTablePartition *tbl_partition = GetTablePartition();
     751           0 :     EvpnMcastNodeList::const_iterator it = replicator_node_list_.begin();
     752           0 :     for (; it != replicator_node_list_.end(); it++) {
     753           0 :         BOOST_FOREACH(EvpnMcastNode *node, it->second)
     754           0 :             tbl_partition->Notify(node->route());
     755             :     }
     756           0 : }
     757             : 
     758             : //
     759             : // Go through all ingress replication client EvpnMcastNodes and notify the
     760             : // associated Broadcast MAC route.
     761             : //
     762           0 : void EvpnManagerPartition::NotifyIrClientNodeRoutes(
     763             :     bool exclude_edge_replication_supported) {
     764           0 :     DBTablePartition *tbl_partition = GetTablePartition();
     765           0 :     EvpnMcastNodeList::const_iterator it = ir_client_node_list_.begin();
     766           0 :     for (; it != ir_client_node_list_.end(); it++) {
     767           0 :         BOOST_FOREACH(EvpnMcastNode *node, it->second) {
     768           0 :             if (exclude_edge_replication_supported &&
     769           0 :                 !node->edge_replication_not_supported()) {
     770           0 :                 continue;
     771             :             }
     772           0 :             tbl_partition->Notify(node->route());
     773             :         }
     774             :     }
     775           0 : }
     776             : 
     777             : //
     778             : // Add an EvpnMcastNode to the EvpnManagerPartition.
     779             : //
     780           0 : void EvpnManagerPartition::AddMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
     781           0 :     EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
     782           0 :                                      rt->GetPrefix().group());
     783           0 :     if (node->type() == EvpnMcastNode::LocalNode) {
     784           0 :         local_mcast_node_list_[sg].insert(node);
     785           0 :         if (node->assisted_replication_supported())
     786           0 :             replicator_node_list_[sg].insert(node);
     787           0 :         if (!node->assisted_replication_leaf())
     788           0 :             ir_client_node_list_[sg].insert(node);
     789           0 :         NotifyNodeRoute(node);
     790             :     } else {
     791           0 :         remote_mcast_node_list_[sg].insert(node);
     792           0 :         if (node->assisted_replication_leaf()) {
     793           0 :             leaf_node_list_[sg].insert(node);
     794           0 :             NotifyReplicatorNodeRoutes();
     795           0 :         } else if (node->edge_replication_not_supported()) {
     796           0 :             regular_node_list_[sg].insert(node);
     797           0 :             NotifyIrClientNodeRoutes(false);
     798           0 :         } else if (!node->assisted_replication_leaf()) {
     799           0 :             NotifyIrClientNodeRoutes(true);
     800             :         }
     801             :     }
     802           0 : }
     803             : 
     804             : //
     805             : // Delete an EvpnMcastNode from the EvpnManagerPartition.
     806             : //
     807           0 : bool EvpnManagerPartition::RemoveMcastNodeFromList(EvpnState::SG &sg,
     808             :                                                    EvpnMcastNode *node,
     809             :                                                    EvpnMcastNodeList *list) {
     810           0 :     size_t deleted = 0;
     811           0 :     if (list->count(sg)) {
     812           0 :         deleted = (*list)[sg].erase(node);
     813           0 :         if ((*list)[sg].size() == 0)
     814           0 :             list->erase(sg);
     815             :     }
     816           0 :     return (deleted > 0);
     817             : }
     818             : 
     819             : //
     820             : // Delete an EvpnMcastNode from the EvpnManagerPartition.
     821             : //
     822           0 : void EvpnManagerPartition::DeleteMcastNode(EvpnMcastNode *node,
     823             :                                            EvpnRoute * rt) {
     824           0 :     EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
     825           0 :                                      rt->GetPrefix().group());
     826           0 :     if (node->type() == EvpnMcastNode::LocalNode) {
     827           0 :         RemoveMcastNodeFromList(sg, node, &local_mcast_node_list_);
     828           0 :         RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
     829           0 :         RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
     830             :     } else {
     831           0 :         RemoveMcastNodeFromList(sg, node, &remote_mcast_node_list_);
     832           0 :         if (RemoveMcastNodeFromList(sg, node, &leaf_node_list_)) {
     833           0 :             NotifyReplicatorNodeRoutes();
     834             :         } else {
     835           0 :             NotifyIrClientNodeRoutes(true);
     836             :         }
     837           0 :         if (RemoveMcastNodeFromList(sg, node, &regular_node_list_)) {
     838           0 :             NotifyIrClientNodeRoutes(false);
     839             :         }
     840             :     }
     841           0 :     if (empty())
     842           0 :         evpn_manager_->RetryDelete();
     843           0 : }
     844             : 
     845             : //
     846             : // Update an EvpnMcastNode in the EvpnManagerPartition.
     847             : // Need to remove/add EvpnMcastNode from the replicator, leaf and ir client
     848             : // lists as appropriate.
     849             : //
     850           0 : void EvpnManagerPartition::UpdateMcastNode(EvpnMcastNode *node, EvpnRoute *rt) {
     851           0 :     node->TriggerUpdate();
     852           0 :     EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
     853           0 :                                      rt->GetPrefix().group());
     854           0 :     if (node->type() == EvpnMcastNode::LocalNode) {
     855           0 :         RemoveMcastNodeFromList(sg, node, &replicator_node_list_);
     856           0 :         if (node->assisted_replication_supported())
     857           0 :             replicator_node_list_[sg].insert(node);
     858           0 :         RemoveMcastNodeFromList(sg, node, &ir_client_node_list_);
     859           0 :         if (!node->assisted_replication_leaf())
     860           0 :             ir_client_node_list_[sg].insert(node);
     861           0 :         NotifyNodeRoute(node);
     862             :     } else {
     863           0 :         bool was_leaf = RemoveMcastNodeFromList(sg, node, &leaf_node_list_);
     864           0 :         if (node->assisted_replication_leaf())
     865           0 :             leaf_node_list_[sg].insert(node);
     866           0 :         if (was_leaf || node->assisted_replication_leaf())
     867           0 :             NotifyReplicatorNodeRoutes();
     868           0 :         if (!was_leaf || !node->assisted_replication_leaf())
     869           0 :             NotifyIrClientNodeRoutes(true);
     870           0 :         bool was_regular = RemoveMcastNodeFromList(
     871             :                                    sg, node, &regular_node_list_);
     872           0 :         if (node->edge_replication_not_supported())
     873           0 :             regular_node_list_[sg].insert(node);
     874           0 :         if (was_regular || node->edge_replication_not_supported())
     875           0 :             NotifyIrClientNodeRoutes(false);
     876             :     }
     877           0 : }
     878             : 
     879             : //
     880             : // Add the given MAC route to the update list.
     881             : // This method gets called either when the MAC route itself changes or when
     882             : // the remote PE list for the EvpnSegment of the MAC route gets updated.
     883             : //
     884           0 : void EvpnManagerPartition::TriggerMacRouteUpdate(EvpnRoute *route) {
     885           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
     886             : 
     887           0 :     mac_update_list_.insert(route);
     888           0 :     mac_update_trigger_->Set();
     889           0 : }
     890             : 
     891             : //
     892             : // Process the MAC route update list for this EvpnManagerPartition.
     893             : //
     894           0 : bool EvpnManagerPartition::ProcessMacUpdateList() {
     895           0 :     CHECK_CONCURRENCY("db::DBTable");
     896             : 
     897           0 :     BgpTable *table = evpn_manager_->table();
     898           0 :     int listener_id = evpn_manager_->listener_id();
     899             : 
     900           0 :     BOOST_FOREACH(EvpnRoute *route, mac_update_list_) {
     901             :         // Skip if the route is on the change list. We will get another
     902             :         // chance to process it after the MacAdvertisement listener sees
     903             :         // it and changes the EvpnMacState to point to the updated value
     904             :         // of EvpnSegment.
     905           0 :         if (route->is_onlist())
     906           0 :             continue;
     907             : 
     908             :         EvpnMacState *mac_state =
     909           0 :             dynamic_cast<EvpnMacState *>(route->GetState(table, listener_id));
     910           0 :         assert(mac_state);
     911           0 :         bool modified = mac_state->ProcessMacRouteAliasing();
     912           0 :         if (route->HasPaths()) {
     913           0 :             if (!mac_state->segment()) {
     914           0 :                 route->ClearState(table, listener_id);
     915           0 :                 delete mac_state;
     916             :             }
     917           0 :             if (modified) {
     918           0 :                 table_partition_->Notify(route);
     919             :             }
     920             :         } else {
     921           0 :             route->ClearState(table, listener_id);
     922           0 :             table_partition_->Delete(route);
     923           0 :             delete mac_state;
     924             :         }
     925             :     }
     926             : 
     927           0 :     mac_update_list_.clear();
     928           0 :     evpn_manager_->RetryDelete();
     929           0 :     return true;
     930             : }
     931             : 
     932           0 : bool EvpnManagerPartition::GetForestNodeAddress(ErmVpnRoute *rt,
     933             :                                                  Ip4Address *address) const {
     934           0 :     if (!evpn_manager_->ermvpn_table()->tree_manager())
     935           0 :         return false;
     936             :     uint32_t label;
     937           0 :     vector<string> te;
     938           0 :     return evpn_manager_->ermvpn_table()->tree_manager()->GetForestNodePMSI(
     939           0 :                                            rt, &label, address, &te);
     940           0 : }
     941             : 
     942           0 : EvpnStatePtr EvpnManagerPartition::GetState(const SG &sg) const {
     943           0 :     EvpnState::StatesMap::const_iterator iter = states_.find(sg);
     944           0 :     return iter != states_.end() ?  iter->second : NULL;
     945             : }
     946             : 
     947           0 : EvpnStatePtr EvpnManagerPartition::GetState(const SG &sg) {
     948           0 :     EvpnState::StatesMap::iterator iter = states_.find(sg);
     949           0 :     return iter != states_.end() ?  iter->second : NULL;
     950             : }
     951             : 
     952           0 : EvpnStatePtr EvpnManagerPartition::GetState(EvpnRoute *rt) {
     953           0 :     EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
     954           0 :                                      rt->GetPrefix().group());
     955           0 :     return GetState(sg);
     956             : }
     957             : 
     958           0 : EvpnStatePtr EvpnManagerPartition::CreateState(const SG &sg) {
     959           0 :     EvpnStatePtr state(new EvpnState(sg, &states_, evpn_manager_));
     960           0 :     assert(states_.insert(make_pair(sg, state.get())).second);
     961           0 :     EVPN_TRACE(EvpnStateCreate, sg.source.to_string(), sg.group.to_string());
     962           0 :     return state;
     963           0 : }
     964             : 
     965           0 : EvpnStatePtr EvpnManagerPartition::LocateState(const SG &sg) {
     966           0 :     EvpnStatePtr evpn_state = GetState(sg);
     967           0 :     if (evpn_state)
     968           0 :         return evpn_state;
     969           0 :     evpn_state = CreateState(sg);
     970           0 :     assert(evpn_state);
     971           0 :     return evpn_state;
     972           0 : }
     973             : 
     974           0 : EvpnStatePtr EvpnManagerPartition::LocateState(EvpnRoute *rt) {
     975           0 :     EvpnState::SG sg = EvpnState::SG(rt->GetPrefix().source(),
     976           0 :                                      rt->GetPrefix().group());
     977           0 :     return LocateState(sg);
     978             : }
     979             : 
     980             : //
     981             : // Disable processing of the update list.
     982             : // For testing only.
     983             : //
     984           0 : void EvpnManagerPartition::DisableMacUpdateProcessing() {
     985           0 :     mac_update_trigger_->set_disable();
     986           0 : }
     987             : 
     988             : //
     989             : // Enable processing of the update list.
     990             : // For testing only.
     991             : //
     992           0 : void EvpnManagerPartition::EnableMacUpdateProcessing() {
     993           0 :     mac_update_trigger_->set_enable();
     994           0 : }
     995             : 
     996             : //
     997             : // Return true if the EvpnManagerPartition is empty i.e. it has no local
     998             : // or remote EvpnMcastNodes and no MAC routes that need to be updated.
     999             : //
    1000           0 : bool EvpnManagerPartition::empty() const {
    1001           0 :     if (!local_mcast_node_list_.empty())
    1002           0 :         return false;
    1003           0 :     if (!remote_mcast_node_list_.empty())
    1004           0 :         return false;
    1005           0 :     if (!mac_update_list_.empty())
    1006           0 :         return false;
    1007           0 :     assert(leaf_node_list_.empty());
    1008           0 :     assert(replicator_node_list_.empty());
    1009           0 :     assert(regular_node_list_.empty());
    1010           0 :     assert(ir_client_node_list_.empty());
    1011           0 :     return true;
    1012             : }
    1013             : 
    1014             : //
    1015             : // Return the BgpServer for the EvpnManagerPartition.
    1016             : //
    1017           0 : BgpServer *EvpnManagerPartition::server() {
    1018           0 :     return evpn_manager_->server();
    1019             : }
    1020             : 
    1021             : //
    1022             : // Return the EvpnTable for the EvpnManagerPartition.
    1023             : //
    1024           0 : const EvpnTable *EvpnManagerPartition::table() const {
    1025           0 :     return evpn_manager_->table();
    1026             : }
    1027             : 
    1028             : //
    1029             : // Constructor for EvpnManager.
    1030             : //
    1031           0 : EvpnManager::EvpnManager(EvpnTable *table)
    1032           0 :     : table_(table),
    1033           0 :       listener_id_(DBTable::kInvalidId),
    1034           0 :       segment_delete_trigger_(new TaskTrigger(
    1035             :           boost::bind(&EvpnManager::ProcessSegmentDeleteSet, this),
    1036           0 :           TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
    1037           0 :       segment_update_trigger_(new TaskTrigger(
    1038             :           boost::bind(&EvpnManager::ProcessSegmentUpdateSet, this),
    1039           0 :           TaskScheduler::GetInstance()->GetTaskId("bgp::EvpnSegment"), 0)),
    1040           0 :       table_delete_ref_(this, table->deleter()) {
    1041           0 :     deleter_.reset(new DeleteActor(this));
    1042           0 :     db_states_count_ = 0;
    1043           0 : }
    1044             : 
    1045             : //
    1046             : // Destructor for EvpnManager.
    1047             : //
    1048           0 : EvpnManager::~EvpnManager() {
    1049           0 :     assert(segment_map_.empty());
    1050           0 :     assert(segment_delete_set_.empty());
    1051           0 :     assert(segment_update_set_.empty());
    1052           0 : }
    1053             : 
    1054             : //
    1055             : // Initialize the EvpnManager. We allocate the EvpnManagerPartitions
    1056             : // and register a DBListener for the EvpnTable.
    1057             : //
    1058           0 : void EvpnManager::Initialize() {
    1059           0 :     AllocPartitions();
    1060           0 :     listener_id_ = table_->Register(
    1061             :         boost::bind(&EvpnManager::RouteListener, this, _1, _2),
    1062             :         "EvpnManager");
    1063           0 :     ermvpn_table_ = dynamic_cast<ErmVpnTable *>(
    1064           0 :         table_->routing_instance()->GetTable(Address::ERMVPN));
    1065           0 :     if (ermvpn_table_)
    1066           0 :         ermvpn_listener_id_ = ermvpn_table_->Register(
    1067             :             boost::bind(&EvpnManager::ErmVpnRouteListener, this, _1, _2),
    1068             :             "EvpnManager");
    1069           0 : }
    1070             : 
    1071             : //
    1072             : // Terminate the EvpnManager. We free the EvpnManagerPartitions
    1073             : // and unregister from the EvpnTable.
    1074             : //
    1075           0 : void EvpnManager::Terminate() {
    1076           0 :     CHECK_CONCURRENCY("bgp::Config");
    1077           0 :     table_->Unregister(listener_id_);
    1078           0 :     listener_id_ = DBTable::kInvalidId;
    1079           0 :     if (ermvpn_listener_id_ != DBTable::kInvalidId) {
    1080           0 :         ermvpn_table_->Unregister(ermvpn_listener_id_);
    1081           0 :         ermvpn_listener_id_ = DBTable::kInvalidId;
    1082             :     }
    1083           0 :     FreePartitions();
    1084           0 : }
    1085             : 
    1086             : //
    1087             : // Allocate the EvpnManagerPartitions.
    1088             : //
    1089           0 : void EvpnManager::AllocPartitions() {
    1090           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
    1091           0 :         partitions_.push_back(new EvpnManagerPartition(this, part_id));
    1092             :     }
    1093           0 : }
    1094             : 
    1095             : //
    1096             : // Free the EvpnManagerPartitions.
    1097             : //
    1098           0 : void EvpnManager::FreePartitions() {
    1099           0 :     STLDeleteValues(&partitions_);
    1100           0 : }
    1101             : 
    1102             : //
    1103             : // Disable processing of the update lists in all partitions.
    1104             : // For testing only.
    1105             : //
    1106           0 : void EvpnManager::DisableMacUpdateProcessing() {
    1107           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
    1108           0 :         partitions_[part_id]->DisableMacUpdateProcessing();
    1109             :     }
    1110           0 : }
    1111             : 
    1112             : //
    1113             : // Enable processing of the update lists in all partitions.
    1114             : // For testing only.
    1115             : //
    1116           0 : void EvpnManager::EnableMacUpdateProcessing() {
    1117           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); part_id++) {
    1118           0 :         partitions_[part_id]->EnableMacUpdateProcessing();
    1119             :     }
    1120           0 : }
    1121             : 
    1122             : //
    1123             : // Get the EvpnManagerPartition for the given partition id.
    1124             : //
    1125           0 : EvpnManagerPartition *EvpnManager::GetPartition(size_t part_id) {
    1126           0 :     return partitions_[part_id];
    1127             : }
    1128             : 
    1129             : //
    1130             : // Get the DBTablePartition for the EvpnTable for given partition id.
    1131             : //
    1132           0 : DBTablePartition *EvpnManager::GetTablePartition(size_t part_id) {
    1133           0 :     return static_cast<DBTablePartition *>(table_->GetTablePartition(part_id));
    1134             : }
    1135             : 
    1136             : //
    1137             : // Construct export state for the given EvpnRoute. Note that the route
    1138             : // only needs to be exported to the IPeer from which it was learnt.
    1139             : //
    1140           0 : UpdateInfo *EvpnManager::GetUpdateInfo(EvpnRoute *route) {
    1141           0 :     CHECK_CONCURRENCY("db::DBTable");
    1142             : 
    1143           0 :     DBState *dbstate = route->GetState(table_, listener_id_);
    1144             :     EvpnLocalMcastNode *local_node =
    1145           0 :         dynamic_cast<EvpnLocalMcastNode *>(dbstate);
    1146             : 
    1147           0 :     if (!local_node)
    1148           0 :         return NULL;
    1149             : 
    1150           0 :     return local_node->GetUpdateInfo(route);
    1151             : }
    1152             : 
    1153           0 : BgpServer *EvpnManager::server() {
    1154           0 :     return table_->server();
    1155             : }
    1156             : 
    1157             : //
    1158             : // Find or create the EvpnSegment for the given EthernetSegmentId.
    1159             : //
    1160           0 : EvpnSegment *EvpnManager::LocateSegment(const EthernetSegmentId &esi) {
    1161           0 :     assert(!esi.IsZero());
    1162           0 :     tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
    1163           0 :     SegmentMap::iterator loc = segment_map_.find(esi);
    1164           0 :     EvpnSegment *segment = (loc != segment_map_.end()) ? loc->second : NULL;
    1165           0 :     if (!segment) {
    1166           0 :         segment = new EvpnSegment(this, esi);
    1167           0 :         segment_map_.insert(esi, segment);
    1168             :     }
    1169           0 :     return segment;
    1170           0 : }
    1171             : 
    1172             : //
    1173             : // Find the EvpnSegment for the given EthernetSegmentId.
    1174             : //
    1175           0 : EvpnSegment *EvpnManager::FindSegment(const EthernetSegmentId &esi) {
    1176           0 :     assert(!esi.IsZero());
    1177           0 :     tbb::spin_rw_mutex::scoped_lock read_lock(segment_rw_mutex_, false);
    1178           0 :     SegmentMap::iterator loc = segment_map_.find(esi);
    1179           0 :     return (loc != segment_map_.end()) ? loc->second : NULL;
    1180           0 : }
    1181             : 
    1182             : //
    1183             : // Trigger deletion of the given EvpnSegment.
    1184             : // The EvpnSegment is added to a set of EvpnSegments that can potentially
    1185             : // be deleted. This method can be invoked from multiple db::DBTable tasks
    1186             : // in parallel when a MAC routes are removed from the dependency list in an
    1187             : // EvpnSegment. Hence we ensure exclusive access using a write lock.
    1188             : //
    1189             : // The list is processed from the context of bgp::EvpnSegment task which is
    1190             : // mutually exclusive with db::DBTable task.
    1191             : //
    1192           0 : void EvpnManager::TriggerSegmentDelete(EvpnSegment *segment) {
    1193           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::EvpnSegment");
    1194             : 
    1195           0 :     tbb::spin_rw_mutex::scoped_lock write_lock(segment_rw_mutex_, true);
    1196           0 :     segment_delete_set_.insert(segment);
    1197           0 :     segment_delete_trigger_->Set();
    1198           0 : }
    1199             : 
    1200             : //
    1201             : // Process the set of EvpnSegments that can potentially be deleted.
    1202             : // Remove the EvpnSegment from the map and destroy if it's fine to
    1203             : // to delete the EvpnSegment.
    1204             : //
    1205           0 : bool EvpnManager::ProcessSegmentDeleteSet() {
    1206           0 :     CHECK_CONCURRENCY("bgp::EvpnSegment");
    1207             : 
    1208           0 :     BOOST_FOREACH(EvpnSegment *segment, segment_delete_set_) {
    1209           0 :         if (segment->MayDelete()) {
    1210           0 :             segment_update_set_.erase(segment);
    1211           0 :             EthernetSegmentId esi = segment->esi();
    1212           0 :             segment_map_.erase(esi);
    1213             :         }
    1214             :     }
    1215           0 :     segment_delete_set_.clear();
    1216           0 :     RetryDelete();
    1217           0 :     return true;
    1218             : }
    1219             : 
    1220             : //
    1221             : // Disable processing of the delete list.
    1222             : // For testing only.
    1223             : //
    1224           0 : void EvpnManager::DisableSegmentDeleteProcessing() {
    1225           0 :     segment_delete_trigger_->set_disable();
    1226           0 : }
    1227             : 
    1228             : //
    1229             : // Enable processing of the delete list.
    1230             : // For testing only.
    1231             : //
    1232           0 : void EvpnManager::EnableSegmentDeleteProcessing() {
    1233           0 :     segment_delete_trigger_->set_enable();
    1234           0 : }
    1235             : 
    1236             : //
    1237             : // Trigger update of the given EvpnSegment.
    1238             : // The EvpnSegment is added to a set of EvpnSegments for which updates
    1239             : // need triggered. This method is called in the context of db::DBTable
    1240             : // task and a task instance of 0 since all AutoDisocvery routes always
    1241             : // get sharded to partition 0.
    1242             : //
    1243             : // The set is processed in the context of bgp::EvpnSegment task, which
    1244             : // is mutually exclusive with db::DBTable task.
    1245             : //
    1246           0 : void EvpnManager::TriggerSegmentUpdate(EvpnSegment *segment) {
    1247           0 :     CHECK_CONCURRENCY("db::DBTable");
    1248             : 
    1249           0 :     segment_update_set_.insert(segment);
    1250           0 :     segment_update_trigger_->Set();
    1251           0 : }
    1252             : 
    1253             : //
    1254             : // Process the set of EvpnSegments that need to be updated.
    1255             : //
    1256             : // Go through each EvpnSegment and update it's PE list. Trigger updates
    1257             : // of all it's dependent MAC routes if there's a change in the PE list.
    1258             : //
    1259           0 : bool EvpnManager::ProcessSegmentUpdateSet() {
    1260           0 :     CHECK_CONCURRENCY("bgp::EvpnSegment");
    1261             : 
    1262           0 :     BOOST_FOREACH(EvpnSegment *segment, segment_update_set_) {
    1263           0 :         EvpnRoute *esi_ad_route = segment->esi_ad_route();
    1264           0 :         bool changed = segment->UpdatePeList();
    1265           0 :         if (changed)
    1266           0 :             segment->TriggerMacRouteUpdate();
    1267           0 :         if (!esi_ad_route->IsValid()) {
    1268           0 :             segment->clear_esi_ad_route();
    1269           0 :             esi_ad_route->ClearState(table_, listener_id_);
    1270           0 :             TriggerSegmentDelete(segment);
    1271             :         }
    1272             :     }
    1273           0 :     segment_update_set_.clear();
    1274           0 :     RetryDelete();
    1275           0 :     return true;
    1276             : }
    1277             : 
    1278             : //
    1279             : // Disable processing of the update list.
    1280             : // For testing only.
    1281             : //
    1282           0 : void EvpnManager::DisableSegmentUpdateProcessing() {
    1283           0 :     segment_update_trigger_->set_disable();
    1284           0 : }
    1285             : 
    1286             : //
    1287             : // Enable processing of the update list.
    1288             : // For testing only.
    1289             : //
    1290           0 : void EvpnManager::EnableSegmentUpdateProcessing() {
    1291           0 :     segment_update_trigger_->set_enable();
    1292           0 : }
    1293             : 
    1294             : //
    1295             : // DBListener callback handler for AutoDisocvery routes in the EvpnTable.
    1296             : //
    1297           0 : void EvpnManager::AutoDiscoveryRouteListener(EvpnRoute *route) {
    1298           0 :     CHECK_CONCURRENCY("db::DBTable");
    1299             : 
    1300           0 :     DBState *dbstate = route->GetState(table_, listener_id_);
    1301           0 :     if (!dbstate) {
    1302             :         // We have no previous DBState for this route.
    1303             :         // Bail if the route is not valid.
    1304           0 :         if (!route->IsValid())
    1305           0 :             return;
    1306             : 
    1307             :         // Locate the EvpnSegment and associate it with the route.
    1308             :         // Trigger an update of EvpnSegment so that it's PE list
    1309             :         // gets updated.
    1310           0 :         EvpnSegment *segment = LocateSegment(route->GetPrefix().esi());
    1311           0 :         segment->set_esi_ad_route(route);
    1312           0 :         route->SetState(table_, listener_id_, segment);
    1313           0 :         TriggerSegmentUpdate(segment);
    1314             :     } else {
    1315             :         // Trigger an update of EvpnSegment so that it's PE list
    1316             :         // gets updated.
    1317           0 :         EvpnSegment *segment = dynamic_cast<EvpnSegment *>(dbstate);
    1318           0 :         assert(segment);
    1319           0 :         TriggerSegmentUpdate(segment);
    1320             :     }
    1321             : }
    1322             : 
    1323             : //
    1324             : // DBListener callback handler for MacAdvertisement routes in the EvpnTable.
    1325             : //
    1326           0 : void EvpnManager::MacAdvertisementRouteListener(
    1327             :     EvpnManagerPartition *partition, EvpnRoute *route) {
    1328           0 :     CHECK_CONCURRENCY("db::DBTable");
    1329             : 
    1330           0 :     DBState *dbstate = route->GetState(table_, listener_id_);
    1331           0 :     if (!dbstate) {
    1332             :         // We have no previous DBState for this route.
    1333             :         // Bail if the route is not valid or if it doesn't have an ESI.
    1334           0 :         if (!route->IsValid())
    1335           0 :             return;
    1336           0 :         const BgpPath *path = route->BestPath();
    1337           0 :         if (path->GetAttr()->esi().IsZero())
    1338           0 :             return;
    1339             : 
    1340             :         // Create a new EvpnMacState and associate it with the route.
    1341           0 :         EvpnMacState *mac_state = new EvpnMacState(this, route);
    1342           0 :         route->SetState(table_, listener_id_, mac_state);
    1343             : 
    1344             :         // Locate the EvpnSegment and add the MAC route as a dependent
    1345             :         // of the EvpnSegment.
    1346           0 :         EvpnSegment *segment = LocateSegment(path->GetAttr()->esi());
    1347           0 :         mac_state->set_segment(segment);
    1348           0 :         segment->AddMacRoute(partition->part_id(), route);
    1349           0 :         partition->TriggerMacRouteUpdate(route);
    1350             :     } else {
    1351           0 :         EvpnMacState *mac_state = dynamic_cast<EvpnMacState *>(dbstate);
    1352           0 :         assert(mac_state);
    1353           0 :         EvpnSegment *segment = mac_state->segment();
    1354             : 
    1355             :         // Handle change in the ESI and update the dependency on the
    1356             :         // EvpnSegment as appropriate.
    1357             :         // Note that the DBState on the EvpnRoute doesn't get cleared
    1358             :         // here. That only happens when aliasing for the route is being
    1359             :         // processed.
    1360           0 :         const BgpPath *path = route->BestPath();
    1361           0 :         if (!route->IsValid() || (path && path->GetAttr()->esi().IsZero())) {
    1362           0 :             if (segment) {
    1363           0 :                 segment->DeleteMacRoute(partition->part_id(), route);
    1364           0 :                 mac_state->clear_segment();
    1365             :             }
    1366           0 :         } else if (!segment && !path->GetAttr()->esi().IsZero()) {
    1367           0 :             segment = LocateSegment(path->GetAttr()->esi());
    1368           0 :             mac_state->set_segment(segment);
    1369           0 :             segment->AddMacRoute(partition->part_id(), route);
    1370           0 :         } else if (segment && segment->esi() != path->GetAttr()->esi()) {
    1371           0 :             segment->DeleteMacRoute(partition->part_id(), route);
    1372           0 :             mac_state->clear_segment();
    1373           0 :             segment = LocateSegment(path->GetAttr()->esi());
    1374           0 :             mac_state->set_segment(segment);
    1375           0 :             segment->AddMacRoute(partition->part_id(), route);
    1376             :         }
    1377           0 :         partition->TriggerMacRouteUpdate(route);
    1378             :     }
    1379             : }
    1380             : 
    1381             : //
    1382             : // DBListener callback handler for InclusiveMulticast routes in the EvpnTable.
    1383             : //
    1384           0 : void EvpnManager::InclusiveMulticastRouteListener(
    1385             :     EvpnManagerPartition *partition, EvpnRoute *route) {
    1386           0 :     CHECK_CONCURRENCY("db::DBTable");
    1387             : 
    1388           0 :     DBState *dbstate = route->GetState(table_, listener_id_);
    1389           0 :     if (!dbstate) {
    1390             :         // We have no previous DBState for this route.
    1391             :         // Bail if the route is not valid.
    1392           0 :         if (!route->IsValid())
    1393           0 :             return;
    1394             : 
    1395             :         // Create a new EvpnMcastNode and associate it with the route.
    1396             :         EvpnMcastNode *node;
    1397           0 :         if (route->GetPrefix().type() == EvpnPrefix::MacAdvertisementRoute) {
    1398           0 :             node = new EvpnLocalMcastNode(partition, route);
    1399             :         } else {
    1400           0 :             node = new EvpnRemoteMcastNode(partition, route);
    1401             :         }
    1402           0 :         partition->AddMcastNode(node, route);
    1403           0 :         route->SetState(table_, listener_id_, node);
    1404             :     } else {
    1405           0 :         EvpnMcastNode *node = dynamic_cast<EvpnMcastNode *>(dbstate);
    1406           0 :         assert(node);
    1407             : 
    1408           0 :         if (!route->IsValid()) {
    1409             :             // Delete the EvpnMcastNode associated with the route.
    1410           0 :             route->ClearState(table_, listener_id_);
    1411           0 :             partition->DeleteMcastNode(node, route);
    1412           0 :             delete node;
    1413           0 :         } else if (node->UpdateAttributes(route)) {
    1414             :             // Update the EvpnMcastNode associated with the route.
    1415           0 :             partition->UpdateMcastNode(node, route);
    1416             :         }
    1417             :     }
    1418             : }
    1419             : 
    1420             : //
    1421             : // DBListener callback handler for SelectiveMulticast routes in the EvpnTable.
    1422             : //
    1423           0 : void EvpnManager::SelectiveMulticastRouteListener(
    1424             :     EvpnManagerPartition *partition, EvpnRoute *route) {
    1425             : 
    1426           0 :     CHECK_CONCURRENCY("db::DBTable");
    1427           0 :     EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
    1428           0 :             route->GetState(table_, listener_id_));
    1429           0 :     bool is_usable = route->IsUsable();
    1430           0 :     bool is_deleted = route->IsDeleted();
    1431           0 :     bool checkErmvpnRoute = false;
    1432           0 :     if (route->BestPath()) {
    1433           0 :         checkErmvpnRoute = route->BestPath()->GetFlags() &
    1434             :             BgpPath::CheckGlobalErmVpnRoute;
    1435             :     }
    1436           0 :     if ((!is_usable && !checkErmvpnRoute) || is_deleted) {
    1437           0 :         if (!dbstate)
    1438           0 :             return;
    1439             : 
    1440           0 :         EvpnStatePtr evpn_state = partition->GetState(route);
    1441           0 :         if (evpn_state)
    1442           0 :             evpn_state->smet_routes().erase(route);
    1443           0 :         EVPN_RT_LOG(route, "Processed Smet route deletion");
    1444           0 :         ClearDBState(route);
    1445           0 :         partition->NotifyForestNode(route, ermvpn_table());
    1446           0 :         partition->DeleteMcastNode(dbstate, route);
    1447           0 :         delete dbstate;
    1448           0 :         return;
    1449           0 :     }
    1450             : 
    1451           0 :     EvpnStatePtr evpn_state = partition->LocateState(route);
    1452           0 :     assert(evpn_state);
    1453           0 :     evpn_state->smet_routes().insert(route);
    1454           0 :     BgpPath *path = const_cast<BgpPath *>(route->BestPath());
    1455           0 :     if (path && path->CheckErmVpn()) {
    1456           0 :         ErmVpnRoute *global_rt = evpn_state->global_ermvpn_tree_rt();
    1457           0 :         Ip4Address address;
    1458           0 :         bool nh_found = partition->GetForestNodeAddress(global_rt, &address);
    1459           0 :         if (nh_found) {
    1460           0 :             BgpAttrPtr attr = path->GetAttr();
    1461             :             BgpAttrPtr new_attr = partition->server()->attr_db()->
    1462           0 :                                   ReplaceNexthopAndLocate(attr.get(), address);
    1463           0 :             path->SetAttr(new_attr, attr);
    1464           0 :             path->ResetCheckErmVpn();
    1465           0 :             partition->NotifyForestNode(route, ermvpn_table());
    1466           0 :         }
    1467             :     }
    1468             : 
    1469           0 :     if (!dbstate) {
    1470             :         // Create a new DBState and associate it with the route.
    1471             :         EvpnMcastNode *node;
    1472           0 :         if (route->GetPrefix().ip_address() ==
    1473           0 :                 Ip4Address(table_->server()->bgp_identifier())) {
    1474           0 :             node = new EvpnLocalMcastNode(partition, route, evpn_state);
    1475             :         } else {
    1476           0 :             node = new EvpnRemoteMcastNode(partition, route, evpn_state);
    1477             :         }
    1478           0 :         SetDBState(route, node);
    1479           0 :         partition->AddMcastNode(node, route);
    1480           0 :         EVPN_RT_LOG(route, "Processed Smet route creation");
    1481             :     }
    1482           0 : }
    1483             : 
    1484           0 : void EvpnManagerPartition::NotifyForestNode(EvpnRoute *route,
    1485             :                                             ErmVpnTable *table) {
    1486           0 :     const Ip4Address &source = route->GetPrefix().source().to_v4();
    1487           0 :     const Ip4Address &group = route->GetPrefix().group().to_v4();
    1488           0 :     if (table->tree_manager())
    1489           0 :         table->tree_manager()->NotifyForestNode(part_id_, source, group);
    1490           0 : }
    1491             : 
    1492             : // Set DB State and update count.
    1493           0 : void EvpnManager::SetDBState(EvpnRoute *route, EvpnMcastNode *dbstate) {
    1494           0 :     route->SetState(table_, listener_id_, dbstate);
    1495           0 :     db_states_count_++;
    1496           0 : }
    1497             : 
    1498             : // Create DB State and update count. If there is no DB State associated in the
    1499             : // table, resume table deletion if the deletion was pending.
    1500           0 : void EvpnManager::ClearDBState(EvpnRoute *route) {
    1501           0 :     route->ClearState(table_, listener_id_);
    1502           0 :     assert(db_states_count_);
    1503           0 :     db_states_count_--;
    1504             : 
    1505             :     // Retry deletion now as there is no more attached db state in the table.
    1506           0 :     if (!db_states_count_ && deleter_->IsDeleted())
    1507           0 :         deleter_->RetryDelete();
    1508           0 : }
    1509             : 
    1510             : // Check whether an ErmVpnRoute is locally originated GlobalTreeRoute.
    1511           0 : bool EvpnManager::IsUsableGlobalTreeRootRoute(
    1512             :         ErmVpnRoute *ermvpn_route) const {
    1513           0 :     if (!ermvpn_route || !ermvpn_route->IsUsable())
    1514           0 :         return false;
    1515           0 :     if (!ermvpn_table()->tree_manager())
    1516           0 :         return false;
    1517           0 :     if (ermvpn_table()->tree_manager()->begin() ==
    1518           0 :             ermvpn_table()->tree_manager()->end())
    1519           0 :         return false;
    1520           0 :     ErmVpnRoute *global_rt = ermvpn_table()->tree_manager()->
    1521           0 :                                GetGlobalTreeRootRoute(
    1522           0 :                                ermvpn_route->GetPrefix().source(),
    1523           0 :                                ermvpn_route->GetPrefix().group());
    1524           0 :     return (global_rt && global_rt == ermvpn_route);
    1525             : }
    1526             : 
    1527             : // ErmVpnTable route listener callback function.
    1528             : //
    1529             : // Process changes (create/update/delete) to GlobalErmVpnRoute in vrf.ermvpn.0
    1530           0 : void EvpnManager::ErmVpnRouteListener(DBTablePartBase *tpart,
    1531             :                                       DBEntryBase *db_entry) {
    1532           0 :     CHECK_CONCURRENCY("db::DBTable");
    1533             : 
    1534           0 :     ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(db_entry);
    1535           0 :     assert(ermvpn_route);
    1536             : 
    1537             :     // We only care about global tree routes for evpn stitching.
    1538           0 :     if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute) {
    1539           0 :         return;
    1540             :     }
    1541             : 
    1542           0 :     EvpnMcastNode *dbstate = dynamic_cast<EvpnMcastNode *>(
    1543           0 :         ermvpn_route->GetState(ermvpn_table(), ermvpn_listener_id()));
    1544             : 
    1545             :     // Handle GlobalTreeRoute route deletion.
    1546           0 :     if (!IsUsableGlobalTreeRootRoute(ermvpn_route)) {
    1547             :         // Ignore if there is no DB State associated with route.
    1548           0 :         if (!dbstate)
    1549           0 :             return;
    1550           0 :         EvpnStatePtr evpn_state = dbstate->state();
    1551           0 :         evpn_state->set_global_ermvpn_tree_rt(NULL);
    1552             : 
    1553             :         // Notify all received smet routes for PMSI re-computation.
    1554             :         // Since usable global ermvpn is no longer available, any advertised
    1555             :         // smet routes must now be withdrawn.
    1556           0 :         BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
    1557           0 :             BgpPath *path = const_cast<BgpPath *>(route->BestPath());
    1558           0 :             if (path && (path->GetPathId() == 0)) {
    1559           0 :                 path->SetCheckErmVpn();
    1560             :             }
    1561           0 :             route->Notify();
    1562             :         }
    1563           0 :         ermvpn_route->ClearState(ermvpn_table(), ermvpn_listener_id());
    1564           0 :         EVPN_ERMVPN_RT_LOG(ermvpn_route,
    1565             :                            "Processed EVPN GlobalErmVpnRoute deletion");
    1566           0 :         delete dbstate;
    1567           0 :         return;
    1568           0 :     }
    1569             : 
    1570             :     // Set DB State in the route if not already done so before.
    1571           0 :     EvpnManagerPartition *partition = GetPartition(tpart->index());
    1572           0 :     EvpnStatePtr evpn_state;
    1573           0 :     if (!dbstate) {
    1574           0 :         EvpnState::SG sg(ermvpn_route);
    1575           0 :         evpn_state = partition->LocateState(sg);
    1576           0 :         dbstate = new EvpnLocalMcastNode(partition, NULL, evpn_state);
    1577           0 :         ermvpn_route->SetState(ermvpn_table(), ermvpn_listener_id(), dbstate);
    1578             :     } else {
    1579           0 :         evpn_state = dbstate->state();
    1580             :     }
    1581             : 
    1582             :     // Note down current usable ermvpn route for stitching to evpn.
    1583           0 :     dbstate->state()->set_global_ermvpn_tree_rt(ermvpn_route);
    1584             : 
    1585             :     // Notify all originated Type6 routes.
    1586           0 :     BOOST_FOREACH(EvpnRoute *route, evpn_state->smet_routes()) {
    1587           0 :         route->Notify();
    1588             :     }
    1589           0 :     EVPN_ERMVPN_RT_LOG(ermvpn_route,
    1590             :                        "Processed EVPN GlobalErmVpnRoute creation");
    1591           0 : }
    1592             : 
    1593             : //
    1594             : // DBListener callback handler for the EvpnTable.
    1595             : //
    1596           0 : void EvpnManager::RouteListener(DBTablePartBase *tpart, DBEntryBase *db_entry) {
    1597           0 :     CHECK_CONCURRENCY("db::DBTable");
    1598             : 
    1599           0 :     EvpnManagerPartition *partition = GetPartition(tpart->index());
    1600           0 :     EvpnRoute *route = dynamic_cast<EvpnRoute *>(db_entry);
    1601           0 :     assert(route);
    1602             : 
    1603           0 :     switch (route->GetPrefix().type()) {
    1604           0 :     case EvpnPrefix::AutoDiscoveryRoute:
    1605           0 :         AutoDiscoveryRouteListener(route);
    1606           0 :         break;
    1607           0 :     case EvpnPrefix::MacAdvertisementRoute:
    1608           0 :         if (route->GetPrefix().mac_addr().IsBroadcast()) {
    1609           0 :             InclusiveMulticastRouteListener(partition, route);
    1610             :         } else {
    1611           0 :             MacAdvertisementRouteListener(partition, route);
    1612             :         }
    1613           0 :         break;
    1614           0 :     case EvpnPrefix::InclusiveMulticastRoute:
    1615           0 :         InclusiveMulticastRouteListener(partition, route);
    1616           0 :         break;
    1617           0 :     case EvpnPrefix::SelectiveMulticastRoute:
    1618           0 :         SelectiveMulticastRouteListener(partition, route);
    1619           0 :         break;
    1620           0 :     default:
    1621           0 :         break;
    1622             :     }
    1623           0 : }
    1624             : 
    1625             : //
    1626             : // Fill information for introspect command.
    1627             : // Note that all IM routes are always in partition 0.
    1628             : //
    1629           0 : void EvpnManager::FillShowInfo(ShowEvpnTable *sevt) const {
    1630           0 :     CHECK_CONCURRENCY("db::DBTable");
    1631             : 
    1632           0 :     vector<string> regular_nves;
    1633           0 :     vector<string> ar_replicators;
    1634           0 :     vector<ShowEvpnMcastLeaf> ar_leafs;
    1635             :     EvpnManagerPartition::EvpnMcastNodeList::const_iterator it =
    1636           0 :                       partitions_[0]->remote_mcast_node_list()->begin();
    1637           0 :     for (; it != partitions_[0]->remote_mcast_node_list()->end(); it++) {
    1638           0 :         BOOST_FOREACH(const EvpnMcastNode *node, it->second) {
    1639           0 :             if (node->assisted_replication_leaf()) {
    1640           0 :                 ShowEvpnMcastLeaf leaf;
    1641           0 :                 leaf.set_address(node->address().to_string());
    1642           0 :                 leaf.set_replicator(node->replicator_address().to_string());
    1643           0 :                 ar_leafs.push_back(leaf);
    1644           0 :             } else if (node->assisted_replication_supported()) {
    1645           0 :                 ar_replicators.push_back(node->address().to_string());
    1646           0 :             } else if (node->edge_replication_not_supported()) {
    1647           0 :                 regular_nves.push_back(node->address().to_string());
    1648             :             }
    1649             :         }
    1650             :     }
    1651             : 
    1652           0 :     sort(regular_nves.begin(), regular_nves.end());
    1653           0 :     sort(ar_replicators.begin(), ar_replicators.end());
    1654           0 :     sort(ar_leafs.begin(), ar_leafs.end());
    1655           0 :     sevt->set_regular_nves(regular_nves);
    1656           0 :     sevt->set_ar_replicators(ar_replicators);
    1657           0 :     sevt->set_ar_leafs(ar_leafs);
    1658           0 : }
    1659             : 
    1660             : //
    1661             : // Check if the EvpnManager can be deleted. This can happen only if all the
    1662             : // EvpnManagerPartitions are empty.
    1663             : //
    1664           0 : bool EvpnManager::MayDelete() const {
    1665           0 :     CHECK_CONCURRENCY("bgp::Config");
    1666             : 
    1667           0 :     if (!segment_map_.empty())
    1668           0 :         return false;
    1669             : 
    1670           0 :     if (!segment_update_set_.empty())
    1671           0 :         return false;
    1672           0 :     if (segment_update_trigger_->IsSet())
    1673           0 :         return false;
    1674             : 
    1675           0 :     if (!segment_delete_set_.empty())
    1676           0 :         return false;
    1677           0 :     if (segment_delete_trigger_->IsSet())
    1678           0 :         return false;
    1679             : 
    1680           0 :     BOOST_FOREACH(const EvpnManagerPartition *partition, partitions_) {
    1681           0 :         if (!partition->empty())
    1682           0 :             return false;
    1683           0 :         if (!partition->states().empty())
    1684           0 :             return false;
    1685             :     }
    1686           0 :     if (db_states_count_)
    1687           0 :         return false;
    1688           0 :     return true;
    1689             : }
    1690             : 
    1691             : //
    1692             : // Initiate shutdown for the EvpnManager.
    1693             : //
    1694           0 : void EvpnManager::Shutdown() {
    1695           0 :     CHECK_CONCURRENCY("bgp::Config");
    1696           0 : }
    1697             : 
    1698             : //
    1699             : // Trigger deletion of the EvpnManager and propagate the delete to any
    1700             : // dependents.
    1701             : //
    1702           0 : void EvpnManager::ManagedDelete() {
    1703           0 :     deleter_->Delete();
    1704           0 : }
    1705             : 
    1706             : //
    1707             : // Attempt to enqueue a delete for the EvpnManager.
    1708             : //
    1709           0 : void EvpnManager::RetryDelete() {
    1710           0 :     if (!deleter()->IsDeleted())
    1711           0 :         return;
    1712           0 :     deleter()->RetryDelete();
    1713             : }
    1714             : 
    1715             : //
    1716             : // Return the LifetimeActor for the EvpnManager.
    1717             : //
    1718           0 : LifetimeActor *EvpnManager::deleter() {
    1719           0 :     return deleter_.get();
    1720             : }
    1721             : 
    1722           0 : EvpnState::SG::SG(const Ip4Address &source, const Ip4Address &group) :
    1723           0 :     source(IpAddress(source)), group(IpAddress(group)) {
    1724           0 : }
    1725             : 
    1726           0 : EvpnState::SG::SG(const ErmVpnRoute *route) :
    1727           0 :         source(route->GetPrefix().source()),
    1728           0 :         group(route->GetPrefix().group()) {
    1729           0 : }
    1730             : 
    1731           0 : EvpnState::SG::SG(const EvpnRoute *route) :
    1732           0 :         source(route->GetPrefix().source()), group(route->GetPrefix().group()) {
    1733           0 : }
    1734             : 
    1735           0 : EvpnState::SG::SG(const IpAddress &source, const IpAddress &group) :
    1736           0 :     source(source), group(group) {
    1737           0 : }
    1738             : 
    1739           0 : bool EvpnState::SG::operator<(const SG &other) const {
    1740           0 :     if (source < other.source)
    1741           0 :         return true;
    1742           0 :     if (source > other.source)
    1743           0 :         return false;
    1744           0 :     if (group < other.group)
    1745           0 :         return true;
    1746           0 :     if (group > other.group)
    1747           0 :         return false;
    1748           0 :     return false;
    1749             : }
    1750             : 
    1751           0 : const EvpnState::SG &EvpnState::sg() const {
    1752           0 :     return sg_;
    1753             : }
    1754             : 
    1755           0 : void EvpnState::set_global_ermvpn_tree_rt(ErmVpnRoute *global_ermvpn_tree_rt) {
    1756           0 :     global_ermvpn_tree_rt_ = global_ermvpn_tree_rt;
    1757           0 : }
    1758             : 
    1759           0 : ErmVpnRoute *EvpnState::global_ermvpn_tree_rt() {
    1760           0 :     return global_ermvpn_tree_rt_;
    1761             : }
    1762             : 
    1763           0 : const ErmVpnRoute *EvpnState::global_ermvpn_tree_rt() const {
    1764           0 :     return global_ermvpn_tree_rt_;
    1765             : }

Generated by: LCOV version 1.14