LCOV - code coverage report
Current view: top level - bgp/mvpn - mvpn_table.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 185 403 45.9 %
Date: 2026-09-21 02:11:39 Functions: 27 42 64.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/mvpn/mvpn_table.h"
       6             : 
       7             : #include <utility>
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include "base/task_annotations.h"
      11             : #include "bgp/ermvpn/ermvpn_table.h"
      12             : #include "bgp/extended-community/source_as.h"
      13             : #include "bgp/ipeer.h"
      14             : #include "bgp/bgp_factory.h"
      15             : #include "bgp/bgp_log.h"
      16             : #include "bgp/bgp_multicast.h"
      17             : #include "bgp/bgp_mvpn.h"
      18             : #include "bgp/bgp_server.h"
      19             : #include "bgp/bgp_update.h"
      20             : #include "bgp/inet/inet_table.h"
      21             : #include "bgp/origin-vn/origin_vn.h"
      22             : #include "bgp/routing-instance/path_resolver.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::unique_ptr;
      28             : using std::pair;
      29             : using std::string;
      30             : using std::set;
      31             : 
      32        5260 : size_t MvpnTable::HashFunction(const MvpnPrefix &prefix) const {
      33        5260 :     if ((prefix.type() == MvpnPrefix::IntraASPMSIADRoute) ||
      34           0 :            (prefix.type() == MvpnPrefix::LeafADRoute)) {
      35        5260 :         uint32_t data = prefix.originator().to_ulong();
      36        5260 :         return boost::hash_value(data);
      37             :     }
      38           0 :     if (prefix.type() == MvpnPrefix::InterASPMSIADRoute) {
      39           0 :         uint32_t data = prefix.asn();
      40           0 :         return boost::hash_value(data);
      41             :     }
      42           0 :     return boost::hash_value(prefix.group().to_ulong());
      43             : }
      44             : 
      45         128 : MvpnTable::MvpnTable(DB *db, const string &name)
      46         128 :     : BgpTable(db, name), manager_(NULL) {
      47         128 : }
      48             : 
      49          96 : PathResolver *MvpnTable::CreatePathResolver() {
      50          96 :     if (routing_instance()->IsMasterRoutingInstance())
      51           0 :         return NULL;
      52          96 :     PathResolver * path_resolver = new PathResolver(this);
      53          96 :     path_resolver->set_nexthop_longest_match(true);
      54          96 :     return path_resolver;
      55             : }
      56             : 
      57         243 : unique_ptr<DBEntry> MvpnTable::AllocEntry(
      58             :     const DBRequestKey *key) const {
      59         243 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      60         243 :     return unique_ptr<DBEntry> (new MvpnRoute(pfxkey->prefix));
      61             : }
      62             : 
      63           0 : unique_ptr<DBEntry> MvpnTable::AllocEntryStr(
      64             :     const string &key_str) const {
      65           0 :     MvpnPrefix prefix = MvpnPrefix::FromString(key_str);
      66           0 :     return unique_ptr<DBEntry> (new MvpnRoute(prefix));
      67           0 : }
      68             : 
      69        5260 : size_t MvpnTable::Hash(const DBEntry *entry) const {
      70        5260 :     const MvpnRoute *rt_entry = static_cast<const MvpnRoute *>(entry);
      71        5260 :     const MvpnPrefix &mvpnprefix = rt_entry->GetPrefix();
      72        5260 :     size_t value = MvpnTable::HashFunction(mvpnprefix);
      73        5260 :     return value % kPartitionCount;
      74             : }
      75             : 
      76         137 : size_t MvpnTable::Hash(const DBRequestKey *key) const {
      77         137 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
      78         137 :     Ip4Prefix prefix(rkey->prefix.group(), 32);
      79         137 :     size_t value = InetTable::HashFunction(prefix);
      80         137 :     return value % kPartitionCount;
      81             : }
      82             : 
      83         137 : BgpRoute *MvpnTable::TableFind(DBTablePartition *rtp,
      84             :     const DBRequestKey *prefix) {
      85         137 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
      86         137 :     MvpnRoute rt_key(pfxkey->prefix);
      87         274 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
      88         137 : }
      89             : 
      90         128 : DBTableBase *MvpnTable::CreateTable(DB *db, const string &name) {
      91         128 :     MvpnTable *table = new MvpnTable(db, name);
      92         128 :     table->Init();
      93         128 :     return table;
      94             : }
      95             : 
      96         152 : void MvpnTable::CreateManager() {
      97         152 :     if (manager_)
      98          33 :         return;
      99             : 
     100             :     // Don't create the MvpnManager if ProjectManager is not present.
     101         119 :     MvpnProjectManager *pm = GetProjectManager();
     102         119 :     if (!pm)
     103          23 :         return;
     104          96 :     manager_ = BgpStaticObjectFactory::Create<MvpnManager>(this, pm->table());
     105          96 :     manager_->Initialize();
     106             : 
     107             :     // Notify all routes in the table for further evaluation.
     108          96 :     NotifyAllEntries();
     109             : 
     110             :     // TODO(Ananth): Should we also notify routes in the bgp.mvpn.0 table ?
     111             : }
     112             : 
     113          96 : void MvpnTable::DestroyManager() {
     114          96 :     if (!manager_)
     115           0 :         return;
     116          96 :     if (IsDeleted())
     117          96 :         DeleteMvpnManager();
     118          96 :     manager_->Terminate();
     119          96 :     delete manager_;
     120          96 :     manager_ = NULL;
     121             : }
     122             : 
     123         128 : void MvpnTable::CreateMvpnManagers() {
     124         128 :     if (!server()->mvpn_ipv4_enable())
     125          96 :         return;
     126          96 :     RoutingInstance *rtinstance = routing_instance();
     127          96 :     std::scoped_lock lock(rtinstance->manager()->mutex());
     128             : 
     129             :     // Don't create the MvpnManager for the VPN table.
     130         192 :     if (!rtinstance->IsMasterRoutingInstance() &&
     131          96 :             !rtinstance->mvpn_project_manager_network().empty()) {
     132             :         pair<MvpnProjectManagerNetworks::iterator, bool> ret =
     133         192 :             rtinstance->manager()->mvpn_project_managers().insert(make_pair(
     134         192 :                 rtinstance->mvpn_project_manager_network(), set<string>()));
     135          96 :         ret.first->second.insert(rtinstance->name());
     136             : 
     137             :         // Initialize MVPN Manager.
     138          96 :         CreateManager();
     139             :     }
     140             : 
     141             :     MvpnProjectManagerNetworks::iterator iter =
     142         192 :         rtinstance->manager()->mvpn_project_managers().find(
     143          96 :             rtinstance->name());
     144          96 :     if (iter == rtinstance->manager()->mvpn_project_managers().end())
     145          64 :         return;
     146             : 
     147         144 :     BOOST_FOREACH(const string &mvpn_network, iter->second) {
     148             :         RoutingInstance *rti =
     149          56 :             rtinstance->manager()->GetRoutingInstance(mvpn_network);
     150          56 :         if (!rti || rti->deleted())
     151           0 :             continue;
     152             :         MvpnTable *table =
     153          56 :             dynamic_cast<MvpnTable *>(rti->GetTable(Address::MVPN));
     154          56 :         if (!table || table->IsDeleted())
     155           0 :             continue;
     156          56 :         table->CreateManager();
     157             :     }
     158          96 : }
     159             : 
     160          96 : void MvpnTable::DeleteMvpnManager() {
     161          96 :     if (!server()->mvpn_ipv4_enable())
     162           0 :         return;
     163          96 :     if (routing_instance()->mvpn_project_manager_network().empty())
     164           0 :         return;
     165          96 :     std::scoped_lock lock(routing_instance()->manager()->mutex());
     166             :     MvpnProjectManagerNetworks::iterator iter =
     167         192 :         routing_instance()->manager()->mvpn_project_managers().find(
     168          96 :             routing_instance()->mvpn_project_manager_network());
     169          96 :     if (iter != routing_instance()->manager()->mvpn_project_managers().end()) {
     170          96 :         iter->second.erase(routing_instance()->name());
     171          96 :         if (iter->second.empty())
     172          32 :             routing_instance()->manager()->mvpn_project_managers().erase(iter);
     173             :     }
     174          96 : }
     175             : 
     176             : // Call the const version to avoid code duplication.
     177         119 : MvpnProjectManager *MvpnTable::GetProjectManager() {
     178             :     return const_cast<MvpnProjectManager *>(
     179         119 :         static_cast<const MvpnTable *>(this)->GetProjectManager());
     180             : }
     181             : 
     182             : // Get MvpnProjectManager object for this Mvpn. Each MVPN network is associated
     183             : // with a parent project maanger network via configuration. MvpnProjectManager
     184             : // is retrieved from this parent network RoutingInstance's ErmVpnTable.
     185         119 : const MvpnProjectManager *MvpnTable::GetProjectManager() const {
     186         119 :     std::string pm_network = routing_instance()->mvpn_project_manager_network();
     187         119 :     if (pm_network.empty())
     188           0 :         return NULL;
     189             :     const RoutingInstance *rtinstance =
     190         119 :         routing_instance()->manager()->GetRoutingInstance(pm_network);
     191         119 :     if (!rtinstance)
     192          23 :         return NULL;
     193          96 :     const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
     194          96 :         rtinstance->GetTable(Address::ERMVPN));
     195          96 :     if (!table)
     196           0 :         return NULL;
     197          96 :     return table->mvpn_project_manager();
     198         119 : }
     199             : 
     200           0 : bool MvpnTable::IsProjectManagerUsable() const {
     201           0 :     std::string pm_network = routing_instance()->mvpn_project_manager_network();
     202           0 :     if (pm_network.empty())
     203           0 :         return false;
     204             :     const RoutingInstance *rtinstance =
     205           0 :         routing_instance()->manager()->GetRoutingInstance(pm_network);
     206           0 :     if (!rtinstance || rtinstance->deleted())
     207           0 :         return false;
     208           0 :     const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
     209           0 :         rtinstance->GetTable(Address::ERMVPN));
     210           0 :     if (!table || table->IsDeleted())
     211           0 :         return false;
     212             : 
     213           0 :     if (!table->mvpn_project_manager() ||
     214           0 :             table->mvpn_project_manager()->deleter()->IsDeleted()) {
     215           0 :         return false;
     216             :     }
     217           0 :     return true;
     218           0 : }
     219             : 
     220             : // Return the MvpnProjectManagerPartition for this route using the same DB
     221             : // partition index as of the route.
     222           0 : const MvpnProjectManagerPartition *MvpnTable::GetProjectManagerPartition(
     223             :         BgpRoute *route) const {
     224           0 :     const MvpnProjectManager *manager = GetProjectManager();
     225           0 :     if (!manager)
     226           0 :         return NULL;
     227           0 :     int part_id = route->get_table_partition()->index();
     228           0 :     return manager->GetPartition(part_id);
     229             : }
     230             : 
     231             : // Override virtual method to retrive target table for MVPN routes. For now,
     232             : // only Type-4 LeafAD routes require special treatment, as they always come
     233             : // with the same route target <router-id>:0. Hence, if normal rtf selection
     234             : // mode is used, every table with MVPN enalbled would have to be notified for
     235             : // replication. Instead, find the table based on the correspondong S-PMSI route.
     236             : // This route can be retrieved from the MVPN state of the <S-G> maintained in
     237             : // the MvpnProjectManagerPartition object.
     238         432 : void MvpnTable::UpdateSecondaryTablesForReplication(BgpRoute *rt,
     239             :         TableSet *secondary_tables) {
     240         432 :     MvpnRoute *mvpn_rt = dynamic_cast<MvpnRoute *>(rt);
     241         432 :     assert(mvpn_rt);
     242             : 
     243             :     // Special table lookup is required only for the Type4 LeafAD routes.
     244         432 :     if (mvpn_rt->GetPrefix().type() != MvpnPrefix::LeafADRoute)
     245         432 :         return;
     246             : 
     247             :     // Find Type-3 S-PMSI route from the Type-4 prefix route.
     248           0 :     MvpnPrefix spmsi_prefix;
     249           0 :     spmsi_prefix.SetSPMSIPrefixFromLeafADPrefix(mvpn_rt->GetPrefix());
     250           0 :     const MvpnRoute *spmsi_rt = FindRoute(spmsi_prefix);
     251           0 :     if (!spmsi_rt || !spmsi_rt->IsUsable())
     252           0 :         return;
     253           0 :     if (!spmsi_rt->BestPath()->IsReplicated())
     254           0 :         return;
     255             : 
     256           0 :     const BgpTable *table = dynamic_cast<const BgpSecondaryPath *>(
     257           0 :                                 spmsi_rt->BestPath())->src_table();
     258           0 :     const MvpnTable *mvpn_table = dynamic_cast<const MvpnTable *>(table);
     259           0 :     if (!mvpn_table || mvpn_table->IsMaster() || !mvpn_table->manager())
     260           0 :         return;
     261           0 :     mvpn_table->manager()->UpdateSecondaryTablesForReplication(
     262             :                               mvpn_rt, secondary_tables);
     263           0 : }
     264             : 
     265             : // Find or create the route.
     266          96 : MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) {
     267          96 :     MvpnRoute rt_key(prefix);
     268             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     269          96 :         GetTablePartition(&rt_key));
     270         192 :     return dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
     271          96 : }
     272             : 
     273           0 : const MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) const {
     274           0 :     MvpnRoute rt_key(prefix);
     275             :     const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
     276           0 :         GetTablePartition(&rt_key));
     277           0 :     return dynamic_cast<const MvpnRoute *>(rtp->Find(&rt_key));
     278           0 : }
     279             : 
     280             : // Find or create the route.
     281          96 : MvpnRoute *MvpnTable::LocateRoute(const MvpnPrefix &prefix) {
     282          96 :     MvpnRoute rt_key(prefix);
     283             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     284          96 :         GetTablePartition(&rt_key));
     285          96 :     MvpnRoute *dest_route = dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
     286          96 :     if (dest_route == NULL) {
     287          96 :         dest_route = new MvpnRoute(prefix);
     288          96 :         rtp->Add(dest_route);
     289             :     } else {
     290           0 :         dest_route->ClearDelete();
     291             :     }
     292          96 :     return dest_route;
     293          96 : }
     294             : 
     295           0 : MvpnPrefix MvpnTable::CreateType4LeafADRoutePrefix(const MvpnRoute *type3_rt) {
     296           0 :     assert(type3_rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute);
     297           0 :     const Ip4Address originator_ip(server()->bgp_identifier());
     298           0 :     MvpnPrefix prefix(MvpnPrefix::LeafADRoute, originator_ip);
     299           0 :     prefix.SetLeafADPrefixFromSPMSIPrefix(type3_rt->GetPrefix());
     300           0 :     return prefix;
     301           0 : }
     302             : 
     303           0 : MvpnRoute *MvpnTable::LocateType4LeafADRoute(const MvpnRoute *type3_spmsi_rt) {
     304           0 :     MvpnPrefix prefix = CreateType4LeafADRoutePrefix(type3_spmsi_rt);
     305           0 :     return LocateRoute(prefix);
     306           0 : }
     307             : 
     308           0 : MvpnPrefix MvpnTable::CreateType3SPMSIRoutePrefix(const MvpnRoute *type7_rt) {
     309           0 :     assert(type7_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute);
     310           0 :     const RouteDistinguisher rd = type7_rt->GetPrefix().route_distinguisher();
     311           0 :     Ip4Address source = type7_rt->GetPrefix().source();
     312           0 :     Ip4Address group = type7_rt->GetPrefix().group();
     313           0 :     const Ip4Address originator_ip(server()->bgp_identifier());
     314             :     MvpnPrefix prefix(MvpnPrefix::SPMSIADRoute, rd, originator_ip,
     315           0 :             group, source);
     316           0 :     return prefix;
     317             : }
     318             : 
     319           0 : MvpnPrefix MvpnTable::CreateLocalType7Prefix(MvpnRoute *rt) const {
     320           0 :     const RouteDistinguisher rd =  RouteDistinguisher::kZeroRd;
     321           0 :     Ip4Address source = rt->GetPrefix().source();
     322           0 :     Ip4Address group = rt->GetPrefix().group();
     323             :     MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
     324           0 :                       0, group, source);
     325           0 :     return prefix;
     326             : }
     327             : 
     328           0 : MvpnPrefix MvpnTable::CreateType7SourceTreeJoinRoutePrefix(
     329             :         MvpnRoute *rt) const {
     330             :     // get the source-rd from attributes as we store type-5 route with zero-rd
     331           0 :     const BgpAttr *attr = rt->BestPath()->GetAttr();
     332           0 :     assert(attr);
     333           0 :     assert(!attr->source_rd().IsZero());
     334           0 :     const RouteDistinguisher rd =  attr->source_rd();
     335           0 :     Ip4Address source = rt->GetPrefix().source();
     336           0 :     Ip4Address group = rt->GetPrefix().group();
     337             :     MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
     338           0 :                       server()->autonomous_system(), group, source);
     339           0 :     return prefix;
     340             : }
     341             : 
     342           0 : MvpnRoute *MvpnTable::LocateType3SPMSIRoute(const MvpnRoute *type7_rt) {
     343           0 :     MvpnPrefix prefix = CreateType3SPMSIRoutePrefix(type7_rt);
     344           0 :     return LocateRoute(prefix);
     345           0 : }
     346             : 
     347           0 : MvpnPrefix MvpnTable::CreateType2ADRoutePrefix() {
     348           0 :     const RouteDistinguisher *rd = routing_instance()->GetRD();
     349             :     MvpnPrefix prefix(MvpnPrefix::InterASPMSIADRoute, *rd,
     350           0 :             server()->autonomous_system());
     351           0 :     return prefix;
     352             : }
     353             : 
     354         192 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix(
     355             :         const Ip4Address &originator_ip) {
     356         192 :     const RouteDistinguisher rd(originator_ip.to_ulong(),
     357         192 :                                 routing_instance()->index());
     358         192 :     MvpnPrefix prefix(MvpnPrefix::IntraASPMSIADRoute, rd, originator_ip);
     359         384 :     return prefix;
     360             : }
     361             : 
     362          96 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix() {
     363         192 :     return CreateType1ADRoutePrefix(Ip4Address(server()->bgp_identifier()));
     364             : }
     365             : 
     366          96 : MvpnRoute *MvpnTable::LocateType1ADRoute() {
     367          96 :     MvpnPrefix prefix = CreateType1ADRoutePrefix();
     368         192 :     return LocateRoute(prefix);
     369          96 : }
     370             : 
     371          96 : MvpnRoute *MvpnTable::FindType1ADRoute(const Ip4Address &originator_ip) {
     372          96 :     MvpnPrefix prefix = CreateType1ADRoutePrefix(originator_ip);
     373         192 :     return FindRoute(prefix);
     374          96 : }
     375             : 
     376          96 : MvpnRoute *MvpnTable::FindType1ADRoute() {
     377          96 :     Ip4Address originator_ip(server()->bgp_identifier());
     378          96 :     return FindType1ADRoute(Ip4Address(server()->bgp_identifier()));
     379             : }
     380             : 
     381           0 : const MvpnRoute *MvpnTable::FindType7SourceTreeJoinRoute(MvpnRoute *rt) const {
     382           0 :     MvpnPrefix prefix;
     383           0 :     if (rt->GetPrefix().type() == MvpnPrefix::SourceActiveADRoute)
     384           0 :         prefix = CreateType7SourceTreeJoinRoutePrefix(rt);
     385           0 :     if (rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute) {
     386           0 :         prefix = CreateLocalType7Prefix(rt);
     387             :     }
     388           0 :     return FindRoute(prefix);
     389           0 : }
     390             : 
     391         288 : BgpRoute *MvpnTable::RouteReplicate(BgpServer *server, BgpTable *stable,
     392             :         BgpRoute *rt, const BgpPath *src_path, ExtCommunityPtr community) {
     393         288 :     MvpnTable *src_table = dynamic_cast<MvpnTable *>(stable);
     394         288 :     assert(src_table);
     395         288 :     MvpnRoute *src_rt = dynamic_cast<MvpnRoute *>(rt);
     396         288 :     assert(src_rt);
     397             : 
     398         288 :     if (!server->mvpn_ipv4_enable()) {
     399           0 :         return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     400           0 :                              src_path, community);
     401             :     }
     402             : 
     403             :     // Replicate Type7 C-Join route.
     404         288 :     if (src_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute) {
     405           0 :         return ReplicateType7SourceTreeJoin(server, src_table, src_rt,
     406           0 :                                             src_path, community);
     407             :     }
     408             : 
     409         288 :     if (!IsMaster()) {
     410             :         // For type-4 paths, only replicate if there is a type-3 primary path
     411             :         // present in the table.
     412          96 :         if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
     413           0 :             MvpnProjectManager *pm = GetProjectManager();
     414           0 :             if (!pm)
     415           0 :                 return NULL;
     416           0 :             MvpnStatePtr mvpn_state = pm->GetState(src_rt);
     417           0 :             if (!mvpn_state || !mvpn_state->spmsi_rt() ||
     418           0 :                     !mvpn_state->spmsi_rt()->IsUsable()) {
     419           0 :                 return NULL;
     420             :             }
     421           0 :             if (mvpn_state->spmsi_rt()->table() != this)
     422           0 :                 return NULL;
     423           0 :         }
     424             :     }
     425             : 
     426             :     // Replicate all other types.
     427         576 :     return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     428         288 :                          src_path, community);
     429             : }
     430             : 
     431           0 : BgpRoute *MvpnTable::ReplicateType7SourceTreeJoin(BgpServer *server,
     432             :     MvpnTable *src_table, MvpnRoute *src_rt, const BgpPath *src_path,
     433             :     ExtCommunityPtr ext_community) {
     434             : 
     435             :     // Only replicate if route has a target that matches this table's auto
     436             :     // created route target (vit).
     437           0 :     if (!IsMaster()) {
     438           0 :         RouteTarget vit(Ip4Address(server->bgp_identifier()),
     439           0 :                                    routing_instance()->index());
     440           0 :         bool vit_found = false;
     441           0 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     442             :                       ext_community->communities()) {
     443           0 :             if (ExtCommunity::is_route_target(comm)) {
     444           0 :                 RouteTarget rtarget(comm);
     445           0 :                 if (rtarget == vit) {
     446           0 :                     vit_found = true;
     447           0 :                     break;
     448             :                 }
     449             :             }
     450             :         }
     451             : 
     452           0 :         if (!vit_found) {
     453           0 :             MVPN_RT_LOG(src_rt, "Route was not replicated as rt-import "
     454             :                         "extended-community was not found");
     455           0 :             return NULL;
     456             :         }
     457             :     }
     458             : 
     459             :     // If replicating from Master table, no special checks are required.
     460           0 :     if (src_table->IsMaster()) {
     461           0 :         return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     462           0 :                              src_path, ext_community);
     463             :     }
     464             : 
     465             :     // This is the case when routes are replicated either to Master or to other
     466             :     // vrf.mvpn.0 as identified the route targets. In either case, basic idea
     467             :     // is to target the replicated path directly to vrf where sender resides.
     468             :     //
     469             :     // Route-target of the target vrf is derived from the Vrf Import Target of
     470             :     // the route the source resolves to. Resolver code would have already
     471             :     // computed this and encoded inside source-rd. Also source-as to encode in
     472             :     // the RD is also encoded as part of the SourceAS extended community.
     473           0 :     const BgpAttr *attr = src_path->GetAttr();
     474           0 :     if (!attr)
     475           0 :         return NULL;
     476             : 
     477             :     // Do not resplicate if the source is not resolvable.
     478           0 :     if (attr->source_rd().IsZero()) {
     479           0 :         MVPN_RT_LOG(src_rt, "Route was not replicated as source_rd is zero");
     480           0 :         return NULL;
     481             :     }
     482             : 
     483             :     // Find source-as extended-community. If not present, do not replicate
     484           0 :     bool source_as_found = false;
     485           0 :     SourceAs source_as;
     486           0 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     487             :                   attr->ext_community()->communities()) {
     488           0 :         if (ExtCommunity::is_source_as(value)) {
     489           0 :             source_as_found = true;
     490           0 :             source_as = SourceAs(value);
     491           0 :             break;
     492             :         }
     493             :     }
     494             : 
     495           0 :     if (!source_as_found) {
     496           0 :         MVPN_RT_LOG(src_rt, "Route was not replicated as source_as is zero");
     497           0 :         return NULL;
     498             :     }
     499             : 
     500             :     // No need to send SourceAS with this mvpn route. This is only sent along
     501             :     // with the unicast routes.
     502             :     ext_community =
     503           0 :         server->extcomm_db()->RemoveSourceASAndLocate(ext_community.get());
     504             : 
     505             :     // Replicate path using source route's<C-S,G>, source_rd and asn as encoded
     506             :     // in the source-as attribute.
     507             :     MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, attr->source_rd(),
     508           0 :                       source_as.GetAsn(), src_rt->GetPrefix().group(),
     509           0 :                       src_rt->GetPrefix().source());
     510             : 
     511             :     // Replicate the path with the computed prefix and attributes.
     512           0 :     return ReplicatePath(server, prefix, src_table, src_rt, src_path,
     513           0 :                          ext_community);
     514           0 : }
     515             : 
     516         288 : BgpRoute *MvpnTable::ReplicatePath(BgpServer *server, const MvpnPrefix &mprefix,
     517             :         MvpnTable *src_table, MvpnRoute *src_rt, const BgpPath *src_path,
     518             :         ExtCommunityPtr comm) {
     519         288 :     MvpnRoute rt_key(mprefix);
     520             : 
     521             :     // Find or create the route.
     522             :     DBTablePartition *rtp =
     523         288 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     524         288 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     525         288 :     if (dest_route == NULL) {
     526         192 :         dest_route = new MvpnRoute(mprefix);
     527         192 :         rtp->Add(dest_route);
     528             :     } else {
     529          96 :         dest_route->ClearDelete();
     530             :     }
     531             : 
     532             :     BgpAttrPtr new_attr =
     533             :         server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(),
     534         288 :                                                         comm.get());
     535             :     // Replace Nexthop with controller address, MX rejects the route if
     536             :     // nexthop is same as neighbor address, needed for Type-7 routes
     537         864 :     new_attr = server->attr_db()->ReplaceNexthopAndLocate(new_attr.get(),
     538         576 :                                   Ip4Address(server->bgp_identifier()));
     539             :     // Need to strip off route targets other than sender-ip:0
     540         288 :     if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
     541           0 :         ExtCommunity::ExtCommunityList rtarget;
     542           0 :         Ip4Address ip = src_rt->GetPrefix().GetType3OriginatorFromType4Route();
     543           0 :         RouteTarget leaf_ad_rtarget(ip, 0);
     544           0 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     545             :                       comm->communities()) {
     546           0 :             if (ExtCommunity::is_route_target(value)) {
     547           0 :                 if (leaf_ad_rtarget == RouteTarget(value)) {
     548           0 :                     rtarget.push_back(value);
     549           0 :                     break;
     550             :                 }
     551             :             }
     552             :         }
     553             : 
     554           0 :         if (rtarget.size() == 1) {
     555             :             ExtCommunityPtr ext_community = server->extcomm_db()->
     556           0 :                 ReplaceRTargetAndLocate(new_attr->ext_community(), rtarget);
     557           0 :             new_attr = server->attr_db()->ReplaceExtCommunityAndLocate(
     558           0 :                 src_path->GetAttr(), ext_community.get());
     559           0 :         } else {
     560           0 :             MVPN_RT_LOG(src_rt,
     561             :                         "Could not find <originator>:0 route-target community");
     562             :         }
     563           0 :     }
     564             : 
     565             :     // Check whether peer already has a path.
     566         288 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     567             :             src_path->GetSource(), src_path->GetPeer(),
     568             :             src_path->GetPathId());
     569         288 :     if (dest_path != NULL) {
     570         192 :         if (new_attr != dest_path->GetOriginalAttr() ||
     571          96 :             src_path->GetFlags() != dest_path->GetFlags()) {
     572           0 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     573             :                 src_path->GetSource(), src_path->GetPeer(),
     574             :                 src_path->GetPathId());
     575           0 :             assert(success);
     576             :         } else {
     577          96 :             return dest_route;
     578             :         }
     579             :     }
     580             : 
     581             :     // Create replicated path and insert it on the route.
     582             :     BgpSecondaryPath *replicated_path =
     583         192 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     584         192 :                              src_path->GetSource(), new_attr,
     585         192 :                              src_path->GetFlags(), src_path->GetLabel());
     586         192 :     replicated_path->SetReplicateInfo(src_table, src_rt);
     587         192 :     dest_route->InsertPath(replicated_path);
     588         192 :     rtp->Notify(dest_route);
     589         192 :     MVPN_RT_LOG(src_rt, "Route was successfully replicated");
     590         192 :     return dest_route;
     591         288 : }
     592             : 
     593         300 : bool MvpnTable::Export(RibOut *ribout, Route *route,
     594             :     const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     595         300 :     MvpnRoute *mvpn_route = dynamic_cast<MvpnRoute *>(route);
     596             : 
     597         300 :     if (ribout->IsEncodingXmpp()) {
     598           0 :         UpdateInfo *uinfo = GetMvpnUpdateInfo(ribout, mvpn_route, peerset);
     599           0 :         if (!uinfo)
     600           0 :             return false;
     601           0 :         uinfo_slist->push_front(*uinfo);
     602           0 :         return true;
     603             :     }
     604         300 :     BgpRoute *bgp_route = static_cast<BgpRoute *> (route);
     605             : 
     606         300 :     UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset);
     607         300 :     if (!uinfo) {
     608         156 :         MVPN_RT_LOG(mvpn_route, "Route was exported as update_info could not "
     609             :                     "be computed");
     610         156 :         return false;
     611             :     }
     612         144 :     uinfo_slist->push_front(*uinfo);
     613         144 :     return true;
     614             : }
     615             : 
     616           0 : void MvpnTable::GetPeerSet(RibOut *ribout, MvpnRoute *route,
     617             :         const RibPeerSet &peerset, RibPeerSet *new_peerset) {
     618           0 :     RibOut::PeerIterator iter(ribout, peerset);
     619           0 :     while (iter.HasNext()) {
     620           0 :         int current_index = iter.index();
     621           0 :         IPeer *peer = dynamic_cast<IPeer *>(iter.Next());
     622           0 :         assert(peer);
     623           0 :         for (Route::PathList::const_iterator it = route->GetPathList().begin();
     624           0 :              it != route->GetPathList().end(); ++it) {
     625           0 :             const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
     626           0 :             if (path->IsFeasible() && peer == path->GetPeer()) {
     627           0 :                 new_peerset->set(current_index);
     628           0 :                 break;
     629             :             }
     630             :         }
     631             :     }
     632           0 : }
     633             : 
     634           0 : UpdateInfo *MvpnTable::GetMvpnUpdateInfo(RibOut *ribout, MvpnRoute *route,
     635             :     const RibPeerSet &peerset) {
     636           0 :     if ((route->GetPrefix().type() != MvpnPrefix::SourceActiveADRoute) &&
     637           0 :         (route->GetPrefix().type() != MvpnPrefix::SourceTreeJoinRoute))
     638           0 :         return NULL;
     639           0 :     if (!route->IsUsable())
     640           0 :         return NULL;
     641             : 
     642           0 :     if (route->BestPath()->IsReplicated())
     643           0 :         return NULL;
     644             : 
     645           0 :     MvpnProjectManager *pm = GetProjectManager();
     646           0 :     if (!pm) {
     647           0 :         MVPN_RT_LOG(route, "Route was exported as ProjectManager was "
     648             :                     "not found");
     649           0 :         return NULL;
     650             :     }
     651             : 
     652           0 :     RibPeerSet new_peerset;
     653           0 :     GetPeerSet(ribout, route, peerset, &new_peerset);
     654             : 
     655           0 :     if (new_peerset.empty())
     656           0 :         return NULL;
     657             : 
     658           0 :     UpdateInfo *uinfo = pm->GetUpdateInfo(route);
     659           0 :     if (uinfo)
     660           0 :         uinfo->target = new_peerset;
     661           0 :     return uinfo;
     662           0 : }
     663             : 
     664        2465 : bool MvpnTable::IsMaster() const {
     665        2465 :     return routing_instance()->IsMasterRoutingInstance();
     666             : }
     667             : 
     668           1 : static void RegisterFactory() {
     669           1 :     DB::RegisterFactory("mvpn.0", &MvpnTable::CreateTable);
     670           1 : }
     671             : 
     672             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14