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

Generated by: LCOV version 1.14