LCOV - code coverage report
Current view: top level - bgp/ermvpn - ermvpn_table.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 144 147 98.0 %
Date: 2026-06-04 02:06:09 Functions: 22 23 95.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/ermvpn/ermvpn_table.h"
       6             : 
       7             : #include "bgp/ipeer.h"
       8             : #include "bgp/bgp_factory.h"
       9             : #include "bgp/bgp_multicast.h"
      10             : #include "bgp/bgp_mvpn.h"
      11             : #include "bgp/bgp_server.h"
      12             : #include "bgp/bgp_update.h"
      13             : #include "bgp/inet/inet_table.h"
      14             : #include "bgp/origin-vn/origin_vn.h"
      15             : #include "bgp/routing-instance/routing_instance.h"
      16             : 
      17             : using std::unique_ptr;
      18             : using std::string;
      19             : 
      20      254370 : size_t ErmVpnTable::HashFunction(const ErmVpnPrefix &prefix) const {
      21      254370 :     return boost::hash_value(prefix.group().to_ulong());
      22             : }
      23             : 
      24       51136 : ErmVpnTable::ErmVpnTable(DB *db, const string &name)
      25       51136 :     : BgpTable(db, name), tree_manager_(NULL), mvpn_project_manager_(NULL) {
      26       51136 : }
      27             : 
      28        7274 : unique_ptr<DBEntry> ErmVpnTable::AllocEntry(
      29             :     const DBRequestKey *key) const {
      30        7274 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(key);
      31        7274 :     return unique_ptr<DBEntry> (new ErmVpnRoute(pfxkey->prefix));
      32             : }
      33             : 
      34             : 
      35         103 : unique_ptr<DBEntry> ErmVpnTable::AllocEntryStr(
      36             :     const string &key_str) const {
      37         103 :     ErmVpnPrefix prefix = ErmVpnPrefix::FromString(key_str);
      38         206 :     return unique_ptr<DBEntry> (new ErmVpnRoute(prefix));
      39             : }
      40             : 
      41      254372 : size_t ErmVpnTable::Hash(const DBEntry *entry) const {
      42      254372 :     const ErmVpnRoute *rt_entry = static_cast<const ErmVpnRoute *>(entry);
      43      254372 :     const ErmVpnPrefix &ermvpnprefix = rt_entry->GetPrefix();
      44      254372 :     size_t value = ErmVpnTable::HashFunction(ermvpnprefix);
      45      254360 :     return value % kPartitionCount;
      46             : }
      47             : 
      48        3378 : size_t ErmVpnTable::Hash(const Ip4Address &group) const {
      49        3378 :     return boost::hash_value(group.to_ulong()) % kPartitionCount;
      50             : }
      51             : 
      52       14793 : size_t ErmVpnTable::Hash(const DBRequestKey *key) const {
      53       14793 :     const RequestKey *rkey = static_cast<const RequestKey *>(key);
      54       14793 :     Ip4Prefix prefix(rkey->prefix.group(), 32);
      55       14793 :     size_t value = InetTable::HashFunction(prefix);
      56       14792 :     return value % kPartitionCount;
      57             : }
      58             : 
      59       14037 : BgpRoute *ErmVpnTable::TableFind(DBTablePartition *rtp,
      60             :     const DBRequestKey *prefix) {
      61       14037 :     const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix);
      62       14037 :     ErmVpnRoute rt_key(pfxkey->prefix);
      63       28074 :     return static_cast<BgpRoute *>(rtp->Find(&rt_key));
      64       14037 : }
      65             : 
      66       51135 : DBTableBase *ErmVpnTable::CreateTable(DB *db, const string &name) {
      67       51135 :     ErmVpnTable *table = new ErmVpnTable(db, name);
      68       51136 :     table->Init();
      69       51136 :     return table;
      70             : }
      71             : 
      72       14501 : BgpRoute *ErmVpnTable::RouteReplicate(BgpServer *server,
      73             :         BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path,
      74             :         ExtCommunityPtr community) {
      75       14501 :     assert(src_table->family() == Address::ERMVPN);
      76             : 
      77       14501 :     ErmVpnRoute *mroute = dynamic_cast<ErmVpnRoute *>(src_rt);
      78       14501 :     assert(mroute);
      79             : 
      80             :     // Native routes are not replicated to other VRFs or to the VPN table.
      81       14501 :     if (mroute->GetPrefix().type() == ErmVpnPrefix::NativeRoute)
      82        3724 :         return NULL;
      83             : 
      84       10777 :     if (!IsMaster()) {
      85             :         // Don't replicate to a VRF from other VRF tables.
      86        3656 :         ErmVpnTable *src_ermvpn_table = dynamic_cast<ErmVpnTable *>(src_table);
      87        3656 :         if (!src_ermvpn_table->IsMaster())
      88         173 :             return NULL;
      89             : 
      90             :         // Don't replicate to VRF from the VPN table if OriginVn doesn't match.
      91        6966 :         if (!community->ContainsOriginVn(server->autonomous_system(),
      92        3483 :                     routing_instance()->virtual_network_index()))
      93          93 :             return NULL;
      94             :     }
      95             : 
      96             :     // RD is always zero in the VRF.  When replicating to the VPN table, we
      97             :     // pick up the RD from the SourceRD attribute. The SourceRD is always set
      98             :     // for Local and Global routes that the multicast code adds to a VRF.
      99       10511 :     ErmVpnPrefix mprefix(mroute->GetPrefix());
     100       10511 :     if (IsMaster()) {
     101        7121 :         mprefix.set_route_distinguisher(src_path->GetAttr()->source_rd());
     102             :     } else {
     103        3390 :         mprefix.set_route_distinguisher(RouteDistinguisher::kZeroRd);
     104             :     }
     105       10511 :     ErmVpnRoute rt_key(mprefix);
     106             : 
     107             :     // Find or create the route.
     108             :     DBTablePartition *rtp =
     109       10511 :         static_cast<DBTablePartition *>(GetTablePartition(&rt_key));
     110       10511 :     BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key));
     111       10511 :     if (dest_route == NULL) {
     112        3467 :         dest_route = new ErmVpnRoute(mprefix);
     113        3467 :         rtp->Add(dest_route);
     114             :     } else {
     115        7044 :         dest_route->ClearDelete();
     116             :     }
     117             : 
     118             :     BgpAttrPtr new_attr =
     119             :         server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(),
     120       10511 :                                                         community);
     121             : 
     122             :     // Check whether peer already has a path.
     123       10511 :     BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt,
     124             :             src_path->GetSource(), src_path->GetPeer(),
     125             :             src_path->GetPathId());
     126       10511 :     if (dest_path != NULL) {
     127        7791 :         if (new_attr != dest_path->GetOriginalAttr() ||
     128        2760 :             src_path->GetFlags() != dest_path->GetFlags()) {
     129        2271 :             bool success = dest_route->RemoveSecondaryPath(src_rt,
     130             :                 src_path->GetSource(), src_path->GetPeer(),
     131             :                 src_path->GetPathId());
     132        2271 :             assert(success);
     133             :         } else {
     134        2760 :             return dest_route;
     135             :         }
     136             :     }
     137             : 
     138             :     // Create replicated path and insert it on the route.
     139             :     BgpSecondaryPath *replicated_path =
     140        7751 :         new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(),
     141        7751 :                              src_path->GetSource(), new_attr,
     142        7751 :                              src_path->GetFlags(), src_path->GetLabel());
     143        7751 :     replicated_path->SetReplicateInfo(src_table, src_rt);
     144        7751 :     dest_route->InsertPath(replicated_path);
     145        7751 :     rtp->Notify(dest_route);
     146             : 
     147        7751 :     return dest_route;
     148       10511 : }
     149             : 
     150       18804 : bool ErmVpnTable::Export(RibOut *ribout, Route *route,
     151             :     const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) {
     152       18804 :     if (ribout->IsEncodingBgp()) {
     153        7479 :         BgpRoute *bgp_route = static_cast<BgpRoute *> (route);
     154        7479 :         UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset);
     155        7479 :         if (!uinfo)
     156        3913 :             return false;
     157        3566 :         uinfo_slist->push_front(*uinfo);
     158        3566 :         return true;
     159             :     }
     160             : 
     161       11325 :     ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(route);
     162       19256 :     if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::NativeRoute &&
     163        7931 :             ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute)
     164        4858 :         return false;
     165             : 
     166        6467 :     if (!tree_manager_ || tree_manager_->deleter()->IsDeleted())
     167           0 :         return false;
     168             : 
     169        6467 :     const IPeer *peer = ermvpn_route->BestPath()->GetPeer();
     170        6467 :     if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer)))
     171        3073 :         return false;
     172             : 
     173        3394 :     size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer));
     174        3394 :     if (!peerset.test(peerbit))
     175         125 :         return false;
     176             : 
     177        3269 :     UpdateInfo *uinfo = tree_manager_->GetUpdateInfo(ermvpn_route);
     178        3269 :     if (!uinfo)
     179         641 :         return false;
     180             : 
     181        2628 :     uinfo->target.set(peerbit);
     182        2628 :     uinfo_slist->push_front(*uinfo);
     183        2628 :     return true;
     184             : }
     185             : 
     186       51136 : void ErmVpnTable::CreateTreeManager() {
     187             :     // Don't create the McastTreeManager for the VPN table.
     188       51136 :     if (IsMaster() && !server()->mvpn_ipv4_enable())
     189        8228 :         return;
     190       42908 :     assert(!tree_manager_);
     191       42908 :     tree_manager_ = BgpStaticObjectFactory::Create<McastTreeManager>(this);
     192       42906 :     tree_manager_->Initialize();
     193             : }
     194             : 
     195       42908 : void ErmVpnTable::DestroyTreeManager() {
     196       42908 :     assert(tree_manager_);
     197       42908 :     tree_manager_->Terminate();
     198       42908 :     delete tree_manager_;
     199       42908 :     tree_manager_ = NULL;
     200       42908 : }
     201             : 
     202           4 : McastTreeManager *ErmVpnTable::GetTreeManager() {
     203           4 :     return tree_manager_;
     204             : }
     205             : 
     206         210 : const McastTreeManager *ErmVpnTable::GetTreeManager() const {
     207         210 :     return tree_manager_;
     208             : }
     209             : 
     210       51136 : void ErmVpnTable::set_routing_instance(RoutingInstance *rtinstance) {
     211       51136 :     BgpTable::set_routing_instance(rtinstance);
     212       51136 :     CreateTreeManager();
     213       51135 :     CreateMvpnProjectManager();
     214       51135 : }
     215             : 
     216       51135 : void ErmVpnTable::CreateMvpnProjectManager() {
     217             :     // Don't create the MvpnProjectManager for the master table.
     218       51135 :     if (!server()->mvpn_ipv4_enable() || IsMaster())
     219       28572 :         return;
     220       22563 :     assert(!mvpn_project_manager_);
     221       22563 :     mvpn_project_manager_ = BgpStaticObjectFactory::Create<MvpnProjectManager>(this);
     222       22563 :     mvpn_project_manager_->Initialize();
     223             : }
     224             : 
     225       22563 : void ErmVpnTable::DestroyMvpnProjectManager() {
     226       22563 :     assert(mvpn_project_manager_);
     227       22563 :     mvpn_project_manager_->Terminate();
     228       22563 :     delete mvpn_project_manager_;
     229       22563 :     mvpn_project_manager_ = NULL;
     230       22563 : }
     231             : 
     232      764389 : bool ErmVpnTable::IsMaster() const {
     233      764389 :     return routing_instance()->IsMasterRoutingInstance();
     234             : }
     235             : 
     236             : // Find or create the route.
     237       30468 : ErmVpnRoute *ErmVpnTable::FindRoute(const ErmVpnPrefix &prefix) {
     238       30468 :     ErmVpnRoute rt_key(prefix);
     239             :     DBTablePartition *rtp = static_cast<DBTablePartition *>(
     240       30468 :         GetTablePartition(&rt_key));
     241       60936 :     return static_cast<ErmVpnRoute *>(rtp->Find(&rt_key));
     242       30468 : }
     243             : 
     244           0 : const ErmVpnRoute *ErmVpnTable::FindRoute(const ErmVpnPrefix &prefix) const {
     245             :     return const_cast<ErmVpnRoute *>(
     246           0 :         static_cast<const ErmVpnTable *>(this)->FindRoute(prefix));
     247             : }
     248             : 
     249        1321 : void ErmVpnTable::GetMvpnSourceAddress(ErmVpnRoute *ermvpn_rt,
     250             :                                        Ip4Address *address) const {
     251        1321 :     if (mvpn_project_manager_)
     252         381 :         mvpn_project_manager_->GetMvpnSourceAddress(ermvpn_rt, address);
     253        1321 : }
     254             : 
     255         159 : static void RegisterFactory() {
     256         159 :     DB::RegisterFactory("ermvpn.0", &ErmVpnTable::CreateTable);
     257         159 : }
     258             : 
     259             : MODULE_INITIALIZER(RegisterFactory);

Generated by: LCOV version 1.14