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: 383 403 95.0 %
Date: 2026-06-04 02:06:09 Functions: 42 42 100.0 %
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     1769475 : size_t MvpnTable::HashFunction(const MvpnPrefix &prefix) const {
      33     2324387 :     if ((prefix.type() == MvpnPrefix::IntraASPMSIADRoute) ||
      34      554912 :            (prefix.type() == MvpnPrefix::LeafADRoute)) {
      35     1269277 :         uint32_t data = prefix.originator().to_ulong();
      36     1269277 :         return boost::hash_value(data);
      37             :     }
      38      500198 :     if (prefix.type() == MvpnPrefix::InterASPMSIADRoute) {
      39          10 :         uint32_t data = prefix.asn();
      40          10 :         return boost::hash_value(data);
      41             :     }
      42      500188 :     return boost::hash_value(prefix.group().to_ulong());
      43             : }
      44             : 
      45       51136 : MvpnTable::MvpnTable(DB *db, const string &name)
      46       51136 :     : BgpTable(db, name), manager_(NULL) {
      47       51136 : }
      48             : 
      49       42908 : PathResolver *MvpnTable::CreatePathResolver() {
      50       42908 :     if (routing_instance()->IsMasterRoutingInstance())
      51           0 :         return NULL;
      52       42908 :     PathResolver * path_resolver = new PathResolver(this);
      53       42907 :     path_resolver->set_nexthop_longest_match(true);
      54       42908 :     return path_resolver;
      55             : }
      56             : 
      57       83582 : unique_ptr<DBEntry> MvpnTable::AllocEntry(
      58             :     const DBRequestKey *key) const {
      59       83582 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      60       83582 :     return unique_ptr<DBEntry> (new MvpnRoute(pfxkey->prefix));
      61             : }
      62             : 
      63          49 : unique_ptr<DBEntry> MvpnTable::AllocEntryStr(
      64             :     const string &key_str) const {
      65          49 :     MvpnPrefix prefix = MvpnPrefix::FromString(key_str);
      66          98 :     return unique_ptr<DBEntry> (new MvpnRoute(prefix));
      67          49 : }
      68             : 
      69     1769475 : size_t MvpnTable::Hash(const DBEntry *entry) const {
      70     1769475 :     const MvpnRoute *rt_entry = static_cast<const MvpnRoute *>(entry);
      71     1769475 :     const MvpnPrefix &mvpnprefix = rt_entry->GetPrefix();
      72     1769475 :     size_t value = MvpnTable::HashFunction(mvpnprefix);
      73     1769475 :     return value % kPartitionCount;
      74             : }
      75             : 
      76       40300 : size_t MvpnTable::Hash(const DBRequestKey *key) const {
      77       40300 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
      78       40300 :     Ip4Prefix prefix(rkey->prefix.group(), 32);
      79       40300 :     size_t value = InetTable::HashFunction(prefix);
      80       40300 :     return value % kPartitionCount;
      81             : }
      82             : 
      83       40132 : BgpRoute *MvpnTable::TableFind(DBTablePartition *rtp,
      84             :     const DBRequestKey *prefix) {
      85       40132 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
      86       40132 :     MvpnRoute rt_key(pfxkey->prefix);
      87       80264 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
      88       40132 : }
      89             : 
      90       51135 : DBTableBase *MvpnTable::CreateTable(DB *db, const string &name) {
      91       51135 :     MvpnTable *table = new MvpnTable(db, name);
      92       51136 :     table->Init();
      93       51136 :     return table;
      94             : }
      95             : 
      96       59243 : void MvpnTable::CreateManager() {
      97       59243 :     if (manager_)
      98       12594 :         return;
      99             : 
     100             :     // Don't create the MvpnManager if ProjectManager is not present.
     101       46649 :     MvpnProjectManager *pm = GetProjectManager();
     102       46649 :     if (!pm)
     103        4808 :         return;
     104       41841 :     manager_ = BgpStaticObjectFactory::Create<MvpnManager>(this, pm->table());
     105       41841 :     manager_->Initialize();
     106             : 
     107             :     // Notify all routes in the table for further evaluation.
     108       41841 :     NotifyAllEntries();
     109             : 
     110             :     // TODO(Ananth): Should we also notify routes in the bgp.mvpn.0 table ?
     111             : }
     112             : 
     113       41841 : void MvpnTable::DestroyManager() {
     114       41841 :     if (!manager_)
     115           0 :         return;
     116       41841 :     if (IsDeleted())
     117       22563 :         DeleteMvpnManager();
     118       41841 :     manager_->Terminate();
     119       41841 :     delete manager_;
     120       41841 :     manager_ = NULL;
     121             : }
     122             : 
     123       51136 : void MvpnTable::CreateMvpnManagers() {
     124       51136 :     if (!server()->mvpn_ipv4_enable())
     125       38547 :         return;
     126       22563 :     RoutingInstance *rtinstance = routing_instance();
     127       22563 :     std::scoped_lock lock(rtinstance->manager()->mutex());
     128             : 
     129             :     // Don't create the MvpnManager for the VPN table.
     130       45126 :     if (!rtinstance->IsMasterRoutingInstance() &&
     131       22563 :             !rtinstance->mvpn_project_manager_network().empty()) {
     132             :         pair<MvpnProjectManagerNetworks::iterator, bool> ret =
     133       45126 :             rtinstance->manager()->mvpn_project_managers().insert(make_pair(
     134       45126 :                 rtinstance->mvpn_project_manager_network(), set<string>()));
     135       22563 :         ret.first->second.insert(rtinstance->name());
     136             : 
     137             :         // Initialize MVPN Manager.
     138       22563 :         CreateManager();
     139             :     }
     140             : 
     141             :     MvpnProjectManagerNetworks::iterator iter =
     142       45126 :         rtinstance->manager()->mvpn_project_managers().find(
     143       22563 :             rtinstance->name());
     144       22563 :     if (iter == rtinstance->manager()->mvpn_project_managers().end())
     145        9974 :         return;
     146             : 
     147       85949 :     BOOST_FOREACH(const string &mvpn_network, iter->second) {
     148             :         RoutingInstance *rti =
     149       36680 :             rtinstance->manager()->GetRoutingInstance(mvpn_network);
     150       36680 :         if (!rti || rti->deleted())
     151           0 :             continue;
     152             :         MvpnTable *table =
     153       36680 :             dynamic_cast<MvpnTable *>(rti->GetTable(Address::MVPN));
     154       36680 :         if (!table || table->IsDeleted())
     155           0 :             continue;
     156       36680 :         table->CreateManager();
     157             :     }
     158       22563 : }
     159             : 
     160       22563 : void MvpnTable::DeleteMvpnManager() {
     161       22563 :     if (!server()->mvpn_ipv4_enable())
     162           0 :         return;
     163       22563 :     if (routing_instance()->mvpn_project_manager_network().empty())
     164           0 :         return;
     165       22563 :     std::scoped_lock lock(routing_instance()->manager()->mutex());
     166             :     MvpnProjectManagerNetworks::iterator iter =
     167       45126 :         routing_instance()->manager()->mvpn_project_managers().find(
     168       22563 :             routing_instance()->mvpn_project_manager_network());
     169       22563 :     if (iter != routing_instance()->manager()->mvpn_project_managers().end()) {
     170       22563 :         iter->second.erase(routing_instance()->name());
     171       22563 :         if (iter->second.empty())
     172        6163 :             routing_instance()->manager()->mvpn_project_managers().erase(iter);
     173             :     }
     174       22563 : }
     175             : 
     176             : // Call the const version to avoid code duplication.
     177       97433 : MvpnProjectManager *MvpnTable::GetProjectManager() {
     178             :     return const_cast<MvpnProjectManager *>(
     179       97433 :         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       97555 : const MvpnProjectManager *MvpnTable::GetProjectManager() const {
     186       97555 :     std::string pm_network = routing_instance()->mvpn_project_manager_network();
     187       97555 :     if (pm_network.empty())
     188           0 :         return NULL;
     189             :     const RoutingInstance *rtinstance =
     190       97555 :         routing_instance()->manager()->GetRoutingInstance(pm_network);
     191       97555 :     if (!rtinstance)
     192        4808 :         return NULL;
     193       92747 :     const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
     194       92747 :         rtinstance->GetTable(Address::ERMVPN));
     195       92747 :     if (!table)
     196           0 :         return NULL;
     197       92747 :     return table->mvpn_project_manager();
     198       97555 : }
     199             : 
     200       64886 : bool MvpnTable::IsProjectManagerUsable() const {
     201       64886 :     std::string pm_network = routing_instance()->mvpn_project_manager_network();
     202       64886 :     if (pm_network.empty())
     203           0 :         return false;
     204             :     const RoutingInstance *rtinstance =
     205       64886 :         routing_instance()->manager()->GetRoutingInstance(pm_network);
     206       64886 :     if (!rtinstance || rtinstance->deleted())
     207       18270 :         return false;
     208       46616 :     const ErmVpnTable *table = dynamic_cast<const ErmVpnTable *>(
     209       46616 :         rtinstance->GetTable(Address::ERMVPN));
     210       46616 :     if (!table || table->IsDeleted())
     211           0 :         return false;
     212             : 
     213       93232 :     if (!table->mvpn_project_manager() ||
     214       46616 :             table->mvpn_project_manager()->deleter()->IsDeleted()) {
     215           0 :         return false;
     216             :     }
     217       46616 :     return true;
     218       64886 : }
     219             : 
     220             : // Return the MvpnProjectManagerPartition for this route using the same DB
     221             : // partition index as of the route.
     222         122 : const MvpnProjectManagerPartition *MvpnTable::GetProjectManagerPartition(
     223             :         BgpRoute *route) const {
     224         122 :     const MvpnProjectManager *manager = GetProjectManager();
     225         122 :     if (!manager)
     226           0 :         return NULL;
     227         122 :     int part_id = route->get_table_partition()->index();
     228         122 :     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      196639 : void MvpnTable::UpdateSecondaryTablesForReplication(BgpRoute *rt,
     239             :         TableSet *secondary_tables) {
     240      196639 :     MvpnRoute *mvpn_rt = dynamic_cast<MvpnRoute *>(rt);
     241      196639 :     assert(mvpn_rt);
     242             : 
     243             :     // Special table lookup is required only for the Type4 LeafAD routes.
     244      196639 :     if (mvpn_rt->GetPrefix().type() != MvpnPrefix::LeafADRoute)
     245      196517 :         return;
     246             : 
     247             :     // Find Type-3 S-PMSI route from the Type-4 prefix route.
     248        3779 :     MvpnPrefix spmsi_prefix;
     249        3779 :     spmsi_prefix.SetSPMSIPrefixFromLeafADPrefix(mvpn_rt->GetPrefix());
     250        3779 :     const MvpnRoute *spmsi_rt = FindRoute(spmsi_prefix);
     251        3779 :     if (!spmsi_rt || !spmsi_rt->IsUsable())
     252           0 :         return;
     253        3779 :     if (!spmsi_rt->BestPath()->IsReplicated())
     254           1 :         return;
     255             : 
     256        3778 :     const BgpTable *table = dynamic_cast<const BgpSecondaryPath *>(
     257        7556 :                                 spmsi_rt->BestPath())->src_table();
     258        3778 :     const MvpnTable *mvpn_table = dynamic_cast<const MvpnTable *>(table);
     259        3778 :     if (!mvpn_table || mvpn_table->IsMaster() || !mvpn_table->manager())
     260        3656 :         return;
     261         122 :     mvpn_table->manager()->UpdateSecondaryTablesForReplication(
     262             :                               mvpn_rt, secondary_tables);
     263        3779 : }
     264             : 
     265             : // Find or create the route.
     266       82306 : MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) {
     267       82306 :     MvpnRoute rt_key(prefix);
     268             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     269       82306 :         GetTablePartition(&rt_key));
     270      164612 :     return dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
     271       82306 : }
     272             : 
     273       24094 : const MvpnRoute *MvpnTable::FindRoute(const MvpnPrefix &prefix) const {
     274       24094 :     MvpnRoute rt_key(prefix);
     275             :     const DBTablePartition *rtp = static_cast<const DBTablePartition *>(
     276       24094 :         GetTablePartition(&rt_key));
     277       48188 :     return dynamic_cast<const MvpnRoute *>(rtp->Find(&rt_key));
     278       24094 : }
     279             : 
     280             : // Find or create the route.
     281       50007 : MvpnRoute *MvpnTable::LocateRoute(const MvpnPrefix &prefix) {
     282       50007 :     MvpnRoute rt_key(prefix);
     283             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     284       50007 :         GetTablePartition(&rt_key));
     285       50007 :     MvpnRoute *dest_route = dynamic_cast<MvpnRoute *>(rtp->Find(&rt_key));
     286       50007 :     if (dest_route == NULL) {
     287       48080 :         dest_route = new MvpnRoute(prefix);
     288       48080 :         rtp->Add(dest_route);
     289             :     } else {
     290        1927 :         dest_route->ClearDelete();
     291             :     }
     292       50007 :     return dest_route;
     293       50007 : }
     294             : 
     295        3051 : MvpnPrefix MvpnTable::CreateType4LeafADRoutePrefix(const MvpnRoute *type3_rt) {
     296        3051 :     assert(type3_rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute);
     297        3051 :     const Ip4Address originator_ip(server()->bgp_identifier());
     298        3051 :     MvpnPrefix prefix(MvpnPrefix::LeafADRoute, originator_ip);
     299        3051 :     prefix.SetLeafADPrefixFromSPMSIPrefix(type3_rt->GetPrefix());
     300        6102 :     return prefix;
     301           0 : }
     302             : 
     303        3050 : MvpnRoute *MvpnTable::LocateType4LeafADRoute(const MvpnRoute *type3_spmsi_rt) {
     304        3050 :     MvpnPrefix prefix = CreateType4LeafADRoutePrefix(type3_spmsi_rt);
     305        6100 :     return LocateRoute(prefix);
     306        3050 : }
     307             : 
     308        4505 : MvpnPrefix MvpnTable::CreateType3SPMSIRoutePrefix(const MvpnRoute *type7_rt) {
     309        4505 :     assert(type7_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute);
     310        4505 :     const RouteDistinguisher rd = type7_rt->GetPrefix().route_distinguisher();
     311        4505 :     Ip4Address source = type7_rt->GetPrefix().source();
     312        4505 :     Ip4Address group = type7_rt->GetPrefix().group();
     313        4505 :     const Ip4Address originator_ip(server()->bgp_identifier());
     314             :     MvpnPrefix prefix(MvpnPrefix::SPMSIADRoute, rd, originator_ip,
     315        4505 :             group, source);
     316        9010 :     return prefix;
     317             : }
     318             : 
     319       17799 : MvpnPrefix MvpnTable::CreateLocalType7Prefix(MvpnRoute *rt) const {
     320       17799 :     const RouteDistinguisher rd =  RouteDistinguisher::kZeroRd;
     321       17799 :     Ip4Address source = rt->GetPrefix().source();
     322       17799 :     Ip4Address group = rt->GetPrefix().group();
     323             :     MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
     324       17799 :                       0, group, source);
     325       35598 :     return prefix;
     326             : }
     327             : 
     328        6295 : MvpnPrefix MvpnTable::CreateType7SourceTreeJoinRoutePrefix(
     329             :         MvpnRoute *rt) const {
     330             :     // get the source-rd from attributes as we store type-5 route with zero-rd
     331        6295 :     const BgpAttr *attr = rt->BestPath()->GetAttr();
     332        6295 :     assert(attr);
     333        6295 :     assert(!attr->source_rd().IsZero());
     334        6295 :     const RouteDistinguisher rd =  attr->source_rd();
     335        6295 :     Ip4Address source = rt->GetPrefix().source();
     336        6295 :     Ip4Address group = rt->GetPrefix().group();
     337             :     MvpnPrefix prefix(MvpnPrefix::SourceTreeJoinRoute, rd,
     338        6295 :                       server()->autonomous_system(), group, source);
     339       12590 :     return prefix;
     340             : }
     341             : 
     342        4504 : MvpnRoute *MvpnTable::LocateType3SPMSIRoute(const MvpnRoute *type7_rt) {
     343        4504 :     MvpnPrefix prefix = CreateType3SPMSIRoutePrefix(type7_rt);
     344        9008 :     return LocateRoute(prefix);
     345        4504 : }
     346             : 
     347           1 : MvpnPrefix MvpnTable::CreateType2ADRoutePrefix() {
     348           1 :     const RouteDistinguisher *rd = routing_instance()->GetRD();
     349             :     MvpnPrefix prefix(MvpnPrefix::InterASPMSIADRoute, *rd,
     350           1 :             server()->autonomous_system());
     351           1 :     return prefix;
     352             : }
     353             : 
     354      112749 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix(
     355             :         const Ip4Address &originator_ip) {
     356      112749 :     const RouteDistinguisher rd(originator_ip.to_ulong(),
     357      112749 :                                 routing_instance()->index());
     358      112749 :     MvpnPrefix prefix(MvpnPrefix::IntraASPMSIADRoute, rd, originator_ip);
     359      225498 :     return prefix;
     360             : }
     361             : 
     362       42454 : MvpnPrefix MvpnTable::CreateType1ADRoutePrefix() {
     363       84908 :     return CreateType1ADRoutePrefix(Ip4Address(server()->bgp_identifier()));
     364             : }
     365             : 
     366       42453 : MvpnRoute *MvpnTable::LocateType1ADRoute() {
     367       42453 :     MvpnPrefix prefix = CreateType1ADRoutePrefix();
     368       84906 :     return LocateRoute(prefix);
     369       42453 : }
     370             : 
     371       70295 : MvpnRoute *MvpnTable::FindType1ADRoute(const Ip4Address &originator_ip) {
     372       70295 :     MvpnPrefix prefix = CreateType1ADRoutePrefix(originator_ip);
     373      140590 :     return FindRoute(prefix);
     374       70295 : }
     375             : 
     376       69125 : MvpnRoute *MvpnTable::FindType1ADRoute() {
     377       69125 :     Ip4Address originator_ip(server()->bgp_identifier());
     378       69125 :     return FindType1ADRoute(Ip4Address(server()->bgp_identifier()));
     379             : }
     380             : 
     381       24094 : const MvpnRoute *MvpnTable::FindType7SourceTreeJoinRoute(MvpnRoute *rt) const {
     382       24094 :     MvpnPrefix prefix;
     383       24094 :     if (rt->GetPrefix().type() == MvpnPrefix::SourceActiveADRoute)
     384        6295 :         prefix = CreateType7SourceTreeJoinRoutePrefix(rt);
     385       24094 :     if (rt->GetPrefix().type() == MvpnPrefix::SPMSIADRoute) {
     386       17799 :         prefix = CreateLocalType7Prefix(rt);
     387             :     }
     388       48188 :     return FindRoute(prefix);
     389       24094 : }
     390             : 
     391      272619 : BgpRoute *MvpnTable::RouteReplicate(BgpServer *server, BgpTable *stable,
     392             :         BgpRoute *rt, const BgpPath *src_path, ExtCommunityPtr community) {
     393      272619 :     MvpnTable *src_table = dynamic_cast<MvpnTable *>(stable);
     394      272619 :     assert(src_table);
     395      272619 :     MvpnRoute *src_rt = dynamic_cast<MvpnRoute *>(rt);
     396      272619 :     assert(src_rt);
     397             : 
     398      272619 :     if (!server->mvpn_ipv4_enable()) {
     399         572 :         return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     400         286 :                              src_path, community);
     401             :     }
     402             : 
     403             :     // Replicate Type7 C-Join route.
     404      272333 :     if (src_rt->GetPrefix().type() == MvpnPrefix::SourceTreeJoinRoute) {
     405      100438 :         return ReplicateType7SourceTreeJoin(server, src_table, src_rt,
     406       50219 :                                             src_path, community);
     407             :     }
     408             : 
     409      222114 :     if (!IsMaster()) {
     410             :         // For type-4 paths, only replicate if there is a type-3 primary path
     411             :         // present in the table.
     412       88721 :         if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
     413        2003 :             MvpnProjectManager *pm = GetProjectManager();
     414        2003 :             if (!pm)
     415        1881 :                 return NULL;
     416        2003 :             MvpnStatePtr mvpn_state = pm->GetState(src_rt);
     417        2125 :             if (!mvpn_state || !mvpn_state->spmsi_rt() ||
     418         122 :                     !mvpn_state->spmsi_rt()->IsUsable()) {
     419        1881 :                 return NULL;
     420             :             }
     421         122 :             if (mvpn_state->spmsi_rt()->table() != this)
     422           0 :                 return NULL;
     423        2003 :         }
     424             :     }
     425             : 
     426             :     // Replicate all other types.
     427      440466 :     return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     428      220233 :                          src_path, community);
     429             : }
     430             : 
     431       50219 : 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       50219 :     if (!IsMaster()) {
     438       19209 :         RouteTarget vit(Ip4Address(server->bgp_identifier()),
     439       38418 :                                    routing_instance()->index());
     440       19209 :         bool vit_found = false;
     441       56324 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     442             :                       ext_community->communities()) {
     443       20336 :             if (ExtCommunity::is_route_target(comm)) {
     444       19553 :                 RouteTarget rtarget(comm);
     445       19553 :                 if (rtarget == vit) {
     446        3557 :                     vit_found = true;
     447        3557 :                     break;
     448             :                 }
     449             :             }
     450             :         }
     451             : 
     452       19209 :         if (!vit_found) {
     453       15652 :             MVPN_RT_LOG(src_rt, "Route was not replicated as rt-import "
     454             :                         "extended-community was not found");
     455       15652 :             return NULL;
     456             :         }
     457             :     }
     458             : 
     459             :     // If replicating from Master table, no special checks are required.
     460       34567 :     if (src_table->IsMaster()) {
     461        7070 :         return ReplicatePath(server, src_rt->GetPrefix(), src_table, src_rt,
     462        3535 :                              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       31032 :     const BgpAttr *attr = src_path->GetAttr();
     474       31032 :     if (!attr)
     475           0 :         return NULL;
     476             : 
     477             :     // Do not resplicate if the source is not resolvable.
     478       31032 :     if (attr->source_rd().IsZero()) {
     479       30870 :         MVPN_RT_LOG(src_rt, "Route was not replicated as source_rd is zero");
     480       30870 :         return NULL;
     481             :     }
     482             : 
     483             :     // Find source-as extended-community. If not present, do not replicate
     484         162 :     bool source_as_found = false;
     485         162 :     SourceAs source_as;
     486         324 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     487             :                   attr->ext_community()->communities()) {
     488         162 :         if (ExtCommunity::is_source_as(value)) {
     489         162 :             source_as_found = true;
     490         162 :             source_as = SourceAs(value);
     491         162 :             break;
     492             :         }
     493             :     }
     494             : 
     495         162 :     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         162 :         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         162 :                       source_as.GetAsn(), src_rt->GetPrefix().group(),
     509         324 :                       src_rt->GetPrefix().source());
     510             : 
     511             :     // Replicate the path with the computed prefix and attributes.
     512         324 :     return ReplicatePath(server, prefix, src_table, src_rt, src_path,
     513         162 :                          ext_community);
     514         162 : }
     515             : 
     516      224216 : BgpRoute *MvpnTable::ReplicatePath(BgpServer *server, const MvpnPrefix &mprefix,
     517             :         MvpnTable *src_table, MvpnRoute *src_rt, const BgpPath *src_path,
     518             :         ExtCommunityPtr comm) {
     519      224216 :     MvpnRoute rt_key(mprefix);
     520             : 
     521             :     // Find or create the route.
     522             :     DBTablePartition *rtp =
     523      224216 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     524      224216 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     525      224216 :     if (dest_route == NULL) {
     526       77735 :         dest_route = new MvpnRoute(mprefix);
     527       77735 :         rtp->Add(dest_route);
     528             :     } else {
     529      146481 :         dest_route->ClearDelete();
     530             :     }
     531             : 
     532             :     BgpAttrPtr new_attr =
     533             :         server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(),
     534      224216 :                                                         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      672648 :     new_attr = server->attr_db()->ReplaceNexthopAndLocate(new_attr.get(),
     538      448432 :                                   Ip4Address(server->bgp_identifier()));
     539             :     // Need to strip off route targets other than sender-ip:0
     540      224216 :     if (src_rt->GetPrefix().type() == MvpnPrefix::LeafADRoute) {
     541        3797 :         ExtCommunity::ExtCommunityList rtarget;
     542        3797 :         Ip4Address ip = src_rt->GetPrefix().GetType3OriginatorFromType4Route();
     543        3797 :         RouteTarget leaf_ad_rtarget(ip, 0);
     544       14981 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     545             :                       comm->communities()) {
     546        7490 :             if (ExtCommunity::is_route_target(value)) {
     547        7489 :                 if (leaf_ad_rtarget == RouteTarget(value)) {
     548        3796 :                     rtarget.push_back(value);
     549        3796 :                     break;
     550             :                 }
     551             :             }
     552             :         }
     553             : 
     554        3797 :         if (rtarget.size() == 1) {
     555             :             ExtCommunityPtr ext_community = server->extcomm_db()->
     556        3796 :                 ReplaceRTargetAndLocate(new_attr->ext_community(), rtarget);
     557        7592 :             new_attr = server->attr_db()->ReplaceExtCommunityAndLocate(
     558        3796 :                 src_path->GetAttr(), ext_community.get());
     559        3796 :         } else {
     560           1 :             MVPN_RT_LOG(src_rt,
     561             :                         "Could not find <originator>:0 route-target community");
     562             :         }
     563        3797 :     }
     564             : 
     565             :     // Check whether peer already has a path.
     566      224216 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     567             :             src_path->GetSource(), src_path->GetPeer(),
     568             :             src_path->GetPathId());
     569      224216 :     if (dest_path != NULL) {
     570      265823 :         if (new_attr != dest_path->GetOriginalAttr() ||
     571      132581 :             src_path->GetFlags() != dest_path->GetFlags()) {
     572         661 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     573             :                 src_path->GetSource(), src_path->GetPeer(),
     574             :                 src_path->GetPathId());
     575         661 :             assert(success);
     576             :         } else {
     577      132581 :             return dest_route;
     578             :         }
     579             :     }
     580             : 
     581             :     // Create replicated path and insert it on the route.
     582             :     BgpSecondaryPath *replicated_path =
     583       91635 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     584       91635 :                              src_path->GetSource(), new_attr,
     585       91635 :                              src_path->GetFlags(), src_path->GetLabel());
     586       91635 :     replicated_path->SetReplicateInfo(src_table, src_rt);
     587       91635 :     dest_route->InsertPath(replicated_path);
     588       91635 :     rtp->Notify(dest_route);
     589       91635 :     MVPN_RT_LOG(src_rt, "Route was successfully replicated");
     590       91635 :     return dest_route;
     591      224216 : }
     592             : 
     593       11904 : bool MvpnTable::Export(RibOut *ribout, Route *route,
     594             :     const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     595       11904 :     MvpnRoute *mvpn_route = dynamic_cast<MvpnRoute *>(route);
     596             : 
     597       11904 :     if (ribout->IsEncodingXmpp()) {
     598        7862 :         UpdateInfo *uinfo = GetMvpnUpdateInfo(ribout, mvpn_route, peerset);
     599        7862 :         if (!uinfo)
     600        7593 :             return false;
     601         269 :         uinfo_slist->push_front(*uinfo);
     602         269 :         return true;
     603             :     }
     604        4042 :     BgpRoute *bgp_route = static_cast<BgpRoute *> (route);
     605             : 
     606        4042 :     UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset);
     607        4042 :     if (!uinfo) {
     608        2923 :         MVPN_RT_LOG(mvpn_route, "Route was exported as update_info could not "
     609             :                     "be computed");
     610        2923 :         return false;
     611             :     }
     612        1119 :     uinfo_slist->push_front(*uinfo);
     613        1119 :     return true;
     614             : }
     615             : 
     616         432 : void MvpnTable::GetPeerSet(RibOut *ribout, MvpnRoute *route,
     617             :         const RibPeerSet &peerset, RibPeerSet *new_peerset) {
     618         432 :     RibOut::PeerIterator iter(ribout, peerset);
     619        1711 :     while (iter.HasNext()) {
     620        1279 :         int current_index = iter.index();
     621        1279 :         IPeer *peer = dynamic_cast<IPeer *>(iter.Next());
     622        1279 :         assert(peer);
     623        2558 :         for (Route::PathList::const_iterator it = route->GetPathList().begin();
     624        4650 :              it != route->GetPathList().end(); ++it) {
     625        1492 :             const BgpPath *path = static_cast<const BgpPath *>(it.operator->());
     626        1492 :             if (path->IsFeasible() && peer == path->GetPeer()) {
     627         446 :                 new_peerset->set(current_index);
     628         446 :                 break;
     629             :             }
     630             :         }
     631             :     }
     632         432 : }
     633             : 
     634        7862 : UpdateInfo *MvpnTable::GetMvpnUpdateInfo(RibOut *ribout, MvpnRoute *route,
     635             :     const RibPeerSet &peerset) {
     636       15208 :     if ((route->GetPrefix().type() != MvpnPrefix::SourceActiveADRoute) &&
     637        7346 :         (route->GetPrefix().type() != MvpnPrefix::SourceTreeJoinRoute))
     638        6954 :         return NULL;
     639         908 :     if (!route->IsUsable())
     640         175 :         return NULL;
     641             : 
     642         733 :     if (route->BestPath()->IsReplicated())
     643         301 :         return NULL;
     644             : 
     645         432 :     MvpnProjectManager *pm = GetProjectManager();
     646         432 :     if (!pm) {
     647           0 :         MVPN_RT_LOG(route, "Route was exported as ProjectManager was "
     648             :                     "not found");
     649           0 :         return NULL;
     650             :     }
     651             : 
     652         432 :     RibPeerSet new_peerset;
     653         432 :     GetPeerSet(ribout, route, peerset, &new_peerset);
     654             : 
     655         432 :     if (new_peerset.empty())
     656           5 :         return NULL;
     657             : 
     658         427 :     UpdateInfo *uinfo = pm->GetUpdateInfo(route);
     659         427 :     if (uinfo)
     660         269 :         uinfo->target = new_peerset;
     661         427 :     return uinfo;
     662         432 : }
     663             : 
     664     1380491 : bool MvpnTable::IsMaster() const {
     665     1380491 :     return routing_instance()->IsMasterRoutingInstance();
     666             : }
     667             : 
     668         159 : static void RegisterFactory() {
     669         159 :     DB::RegisterFactory("mvpn.0", &MvpnTable::CreateTable);
     670         159 : }
     671             : 
     672             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14