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

Generated by: LCOV version 1.14