LCOV - code coverage report
Current view: top level - vnsw/agent/oper - mpls.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 227 308 73.7 %
Date: 2026-06-08 02:02:55 Functions: 34 40 85.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <boost/uuid/uuid_io.hpp>
       6             : #include <cmn/agent_cmn.h>
       7             : #include <init/agent_param.h>
       8             : #include <base/task_annotations.h>
       9             : #include <oper/interface_common.h>
      10             : #include <oper/vrf.h>
      11             : #include <oper/nexthop.h>
      12             : #include <oper/mpls.h>
      13             : #include <oper/mirror_table.h>
      14             : #include <oper/agent_sandesh.h>
      15             : #include <resource_manager/resource_manager.h>
      16             : #include <resource_manager/resource_table.h>
      17             : #include <resource_manager/mpls_index.h>
      18             : 
      19             : using namespace std;
      20             : 
      21             : SandeshTraceBufferPtr MplsTraceBuf(SandeshTraceBufferCreate("MplsTrace", 1000));
      22             : 
      23             : /****************************************************************************
      24             :  * MplsLabel routines
      25             :  ***************************************************************************/
      26         411 : MplsLabel::MplsLabel(Agent *agent, uint32_t label) :
      27         411 :     agent_(agent), label_(label), free_label_(false) {
      28         411 : }
      29             : 
      30         822 : MplsLabel::~MplsLabel() {
      31         411 :     if (free_label_) {
      32          75 :         if (label_ != MplsTable::kInvalidLabel) {
      33          75 :             MplsTable *table = static_cast<MplsTable *>(get_table());
      34          75 :             table->FreeMplsLabelIndex(label_);
      35             :         }
      36          75 :         agent_->resource_manager()->Release(Resource::MPLS_INDEX, label_);
      37             :     }
      38         822 : }
      39             : 
      40        2845 : bool MplsLabel::IsLess(const DBEntry &rhs) const {
      41        2845 :         const MplsLabel &mpls = static_cast<const MplsLabel &>(rhs);
      42        2845 :         return label_ < mpls.label_;
      43             : }
      44             : 
      45           0 : std::string MplsLabel::ToString() const {
      46           0 :     return "MPLS";
      47             : }
      48             : 
      49          68 : DBEntryBase::KeyPtr MplsLabel::GetDBRequestKey() const {
      50          68 :     MplsLabelKey *key = new MplsLabelKey(label_);
      51          68 :     return DBEntryBase::KeyPtr(key);
      52             : }
      53             : 
      54           0 : void MplsLabel::SetKey(const DBRequestKey *k) {
      55           0 :     const MplsLabelKey *key = static_cast<const MplsLabelKey *>(k);
      56           0 :     label_ = key->label();
      57           0 : }
      58             : 
      59          75 : uint32_t MplsLabel::GetRefCount() const {
      60          75 :     return AgentRefCount<MplsLabel>::GetRefCount();
      61             : }
      62             : 
      63          75 : void MplsLabel::Add(const DBRequest *req) {
      64          75 :     free_label_ = true;
      65          75 :     ChangeInternal(req);
      66          75 :     SendObjectLog(agent_->mpls_table(), AgentLogEvent::ADD);
      67          75 :     return;
      68             : }
      69             : 
      70          38 : bool MplsLabel::Change(const DBRequest *req) {
      71          38 :     const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
      72          38 :     bool ret = ChangeInternal(req);
      73          38 :     SendObjectLog(table, AgentLogEvent::CHANGE);
      74          38 :     return ret;
      75             : }
      76             : 
      77          75 : void MplsLabel::Delete(const DBRequest *req) {
      78          75 :     const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
      79          75 :     SendObjectLog(table, AgentLogEvent::DEL);
      80          75 :     return;
      81             : }
      82             : 
      83         113 : bool MplsLabel::ChangeInternal(const DBRequest *req) {
      84         113 :     NextHopTable *nh_table = agent_->nexthop_table();
      85         113 :     MplsLabelData *data = static_cast<MplsLabelData *>(req->data.get());
      86             :     NextHop *nh =
      87         113 :         static_cast<NextHop *>(nh_table->FindActiveEntry(data->nh_key()));
      88         113 :     if (!nh) {
      89             :         // NextHop not found, point mpls label to discard
      90           0 :         DiscardNH key;
      91           0 :         nh = static_cast<NextHop *>(nh_table->FindActiveEntry(&key));
      92           0 :     }
      93             : 
      94         113 :     return ChangeNH(nh);
      95             : }
      96             : 
      97         154 : bool MplsLabel::ChangeNH(NextHop *nh) {
      98         154 :     if (nh_ == nh)
      99          58 :         return false;
     100             : 
     101          96 :     assert(nh);
     102          96 :     nh_ = nh;
     103             : 
     104          96 :     if (IsFabricMulticastReservedLabel()) {
     105           0 :         CompositeNH *cnh = dynamic_cast<CompositeNH*>(nh);
     106           0 :         if (cnh && cnh->vrf()) {
     107           0 :             FmgVrfNhMap::iterator it = fmg_nh_list_.begin();
     108           0 :             while( it != fmg_nh_list_.end()) {
     109           0 :                 if (it->first != cnh->vrf()->GetName()) {
     110           0 :                     FmgVrfNhMap::iterator temp_it;
     111           0 :                     temp_it = it;
     112           0 :                     it++;
     113           0 :                     fmg_nh_list_.erase(temp_it);
     114             :                 } else {
     115           0 :                     it++;
     116             :                 }
     117             :             }
     118           0 :             fmg_nh_list_[cnh->vrf()->GetName()] = nh;
     119             :         }
     120             :     }
     121             : 
     122          96 :     SyncDependentPath();
     123          96 :     return true;
     124             : }
     125             : 
     126          96 : void MplsLabel::SyncDependentPath() {
     127          96 :     MPLS_TRACE(MplsTrace, "Syncing routes for label ", label());
     128          96 :     for (DependentPathList::iterator iter =
     129         192 :          mpls_label_.begin(); iter != mpls_label_.end(); iter++) {
     130           0 :         AgentRoute *rt = iter.operator->();
     131           0 :         rt->EnqueueRouteResync();
     132             :     }
     133          96 : }
     134             : 
     135         104 : bool MplsLabel::IsFabricMulticastReservedLabel() const {
     136             :     //MplsTable *table = static_cast<MplsTable *>(get_table());
     137         104 :     MplsTable *table = static_cast<MplsTable *>(agent_->mpls_table());
     138         104 :     return table->IsFabricMulticastLabel(label_);
     139             : }
     140             : 
     141             : /****************************************************************************
     142             :  * MplsLabel Sandesh routines
     143             :  ***************************************************************************/
     144           0 : bool MplsLabel::DBEntrySandesh(Sandesh *sresp, std::string &name) const {
     145           0 :     MplsResp *resp = static_cast<MplsResp *>(sresp);
     146             : 
     147           0 :     MplsSandeshData data;
     148           0 :     data.set_label(label_);
     149           0 :     nh_->SetNHSandeshData(data.nh);
     150             :     std::vector<MplsSandeshData> &list =
     151           0 :             const_cast<std::vector<MplsSandeshData>&>(resp->get_mpls_list());
     152           0 :     list.push_back(data);
     153             : 
     154           0 :     return true;
     155           0 : }
     156             : 
     157         188 : void MplsLabel::SendObjectLog(const AgentDBTable *table,
     158             :                               AgentLogEvent::type event) const {
     159         188 :     MplsObjectLogInfo info;
     160         188 :     string str, type_str, nh_type;
     161         188 :     info.set_type(type_str);
     162         188 :     info.set_label((int)label_);
     163         188 :     switch (event) {
     164          75 :     case AgentLogEvent::ADD:
     165          75 :         str.assign("Addition ");
     166          75 :         break;
     167          75 :     case AgentLogEvent::DEL:
     168          75 :         str.assign("Deletion ");
     169          75 :         info.set_event(str);
     170          75 :         OPER_TRACE_ENTRY(Mpls, table, info);
     171          75 :         return;
     172          38 :     case AgentLogEvent::CHANGE:
     173          38 :         str.assign("Modification ");
     174          38 :         break;
     175           0 :     default:
     176           0 :         str.assign("Unknown");
     177           0 :         break;
     178             :     }
     179         113 :     info.set_event(str);
     180         113 :     const NextHop *nh = nexthop();
     181         113 :     const Interface *intf = NULL;
     182             :     /* Mpls is not expected to have any other nexthop apart from Interface
     183             :        or Vlan */
     184         113 :     if (nh != NULL) {
     185         113 :         string policy_str("Disabled");
     186             :         const InterfaceNH *if_nh;
     187             :         const VlanNH *vlan_nh;
     188             : 
     189         113 :         switch(nh->GetType()) {
     190          65 :         case NextHop::INTERFACE:
     191          65 :             nh_type.assign("INTERFACE");
     192          65 :             if_nh = static_cast<const InterfaceNH *>(nh);
     193          65 :             intf = if_nh->GetInterface();
     194          65 :             if (if_nh->PolicyEnabled()) {
     195          26 :                 policy_str.assign("Enabled");
     196             :             }
     197          65 :             info.set_policy(policy_str);
     198          65 :             break;
     199           0 :         case NextHop::VLAN:
     200           0 :             nh_type.assign("VLAN");
     201           0 :             vlan_nh = static_cast<const VlanNH *>(nh);
     202           0 :             intf = vlan_nh->GetInterface();
     203           0 :             info.set_vlan_tag(vlan_nh->GetVlanTag());
     204           0 :             break;
     205          37 :         case NextHop::COMPOSITE:
     206          37 :             nh_type.assign("Composite");
     207          37 :             break;
     208          11 :         default:
     209          11 :             nh_type.assign("unknown");
     210          11 :             break;
     211             :         }
     212         113 :     }
     213         113 :     info.set_nh_type(nh_type);
     214             :     /* Interface Nexthop pointed by Mpls object will always be of type VMPORT */
     215         113 :     if (intf) {
     216          65 :         string if_type_str;
     217          65 :         switch(intf->type()) {
     218          65 :         case Interface::VM_INTERFACE:
     219          65 :             if_type_str.assign("VM_INTERFACE");
     220          65 :             break;
     221           0 :         default:
     222           0 :             if_type_str.assign("Invalid");
     223           0 :             break;
     224             :         }
     225          65 :         info.set_intf_type(if_type_str);
     226          65 :         info.set_intf_uuid(UuidToString(intf->GetUuid()));
     227          65 :         info.set_intf_name(intf->name());
     228          65 :     }
     229         113 :     OPER_TRACE_ENTRY(Mpls, table, info);
     230         413 : }
     231             : 
     232             : /****************************************************************************
     233             :  * MplsTable routines
     234             :  ***************************************************************************/
     235           1 : MplsTable::MplsTable(DB *db, const std::string &name) :
     236           1 :     AgentDBTable(db, name) {
     237           1 : }
     238             : 
     239           2 : MplsTable::~MplsTable() {
     240           2 : }
     241             : 
     242           1 : DBTableBase *MplsTable::CreateTable(DB *db, const std::string &name) {
     243           1 :     MplsTable *table = new MplsTable(db, name);
     244           1 :     table->Init();
     245           1 :     return table;
     246             : };
     247             : 
     248         188 : void MplsTable::Process(DBRequest &req) {
     249         188 :     agent()->ConcurrencyCheck();
     250             :     DBTablePartition *tpart =
     251         188 :         static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
     252         188 :     tpart->Process(NULL, &req);
     253         188 : }
     254             : 
     255             : /*
     256             :  * Allocates label from resource manager, currently used for evpn and
     257             :  * ecmp labels.
     258             :  */
     259           0 : uint32_t MplsTable::AllocLabel(ResourceManager::KeyPtr key) {
     260             :     uint32_t label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
     261           0 :                                       Allocate(key).get()))->index());
     262           0 :     assert(label != MplsTable::kInvalidLabel);
     263           0 :     return label;
     264             : }
     265             : 
     266             : //Free label from resource manager and delete db entry
     267           1 : void MplsTable::FreeLabel(uint32_t label) {
     268           1 :     FreeLabel(label, std::string());
     269           1 : }
     270             : 
     271           7 : void MplsTable::FreeLabel(uint32_t label, const std::string &vrf_name) {
     272           7 :     DBRequest req;
     273           7 :     req.oper = DBRequest::DB_ENTRY_DELETE;
     274             : 
     275           7 :     MplsLabelKey *key = new MplsLabelKey(label);
     276           7 :     MplsLabelData *data = new MplsLabelData(NULL);
     277           7 :     data->set_vrf_name(vrf_name);
     278           7 :     req.key.reset(key);
     279           7 :     req.data.reset(data);
     280             : 
     281           7 :     Process(req);
     282           7 : }
     283             : 
     284         336 : std::unique_ptr<DBEntry> MplsTable::AllocEntry(const DBRequestKey *k) const {
     285         336 :     const MplsLabelKey *key = static_cast<const MplsLabelKey *>(k);
     286         336 :     MplsLabel *mpls = new MplsLabel(agent(), key->label());
     287         336 :     return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(mpls));
     288             : }
     289             : 
     290          75 : DBEntry *MplsTable::Add(const DBRequest *req) {
     291          75 :     CheckVrLabelLimit();
     292          75 :     MplsLabelKey *key = static_cast<MplsLabelKey *>(req->key.get());
     293          75 :     assert(key->label() != MplsTable::kInvalidLabel);
     294             : 
     295          75 :     MplsLabel *mpls = new MplsLabel(agent(), key->label());
     296          75 :     label_table_.InsertAtIndex(mpls->label(), mpls);
     297          75 :     mpls->Add(req);
     298          75 :     return mpls;
     299             : }
     300             : 
     301          38 : bool MplsTable::OnChange(DBEntry *entry, const DBRequest *req) {
     302          38 :     MplsLabel *mpls = static_cast<MplsLabel *>(entry);
     303          38 :     return mpls->Change(req);
     304             : }
     305             : 
     306          75 : bool MplsTable::Delete(DBEntry *entry, const DBRequest *req) {
     307          75 :     MplsLabel *mpls = static_cast<MplsLabel *>(entry);
     308          75 :     if (IsFabricMulticastLabel(mpls->label())) {
     309           0 :         MplsLabelData *data = static_cast<MplsLabelData *>(req->data.get());
     310             :         // For multicast labels we not expect to be here
     311             :         // via MplsTable::OnZeroRefcount where data is not set.
     312           0 :         assert(data);
     313           0 :         if (mpls->fmg_nh_list().find(data->vrf_name()) !=
     314           0 :                 mpls->fmg_nh_list().end()) {
     315           0 :             mpls->fmg_nh_list().erase(data->vrf_name());
     316             :         }
     317           0 :         if (mpls->fmg_nh_list().empty() == false) {
     318           0 :             if (mpls->ChangeNH(mpls->fmg_nh_list().begin()->second.get())) {
     319             :                 DBTablePartBase *tpart =
     320           0 :                     static_cast<DBTablePartition *>(GetTablePartition(mpls));
     321           0 :                 tpart->Notify(mpls);
     322             :             }
     323           0 :             return false;
     324             :         }
     325             :     }
     326          75 :     mpls->Delete(req);
     327          75 :     CheckVrLabelLimit();
     328          75 :     return true;
     329             : }
     330             : 
     331          68 : void MplsTable::OnZeroRefcount(AgentDBEntry *e) {
     332          68 :     agent()->ConcurrencyCheck();
     333             : 
     334             :     //Delete db entry
     335          68 :     DBRequest req(DBRequest::DB_ENTRY_DELETE);
     336          68 :     req.key = e->GetDBRequestKey();
     337          68 :     req.data.reset(NULL);
     338          68 :     Process(req);
     339          68 : }
     340             : 
     341          45 : uint32_t MplsTable::CreateRouteLabel(uint32_t label, const NextHopKey *nh_key,
     342             :                                 const std::string &vrf_name,
     343             :                                 const std::string &route) {
     344          45 :     if (label == MplsTable::kInvalidLabel) {
     345             :         ResourceManager::KeyPtr key(new RouteMplsResourceKey(agent()->
     346           7 :                                 resource_manager(), vrf_name,
     347           7 :                                 route));
     348             :         label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
     349           7 :                                       Allocate(key).get()))->index());
     350           7 :         assert(label != MplsTable::kInvalidLabel);
     351           7 :         assert(FindMplsLabel(label) == NULL);
     352           7 :     }
     353             : 
     354          45 :     DBRequest req;
     355          45 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     356             : 
     357          45 :     MplsLabelKey *key = new MplsLabelKey(label);
     358          45 :     req.key.reset(key);
     359             : 
     360          45 :     MplsLabelData *data = new MplsLabelData(nh_key->Clone());
     361          45 :     data->set_vrf_name(vrf_name);
     362          45 :     req.data.reset(data);
     363             : 
     364          45 :     Process(req);
     365          45 :     return label;
     366          45 : }
     367             : 
     368         210 : bool MplsTable::IsFabricMulticastLabel(uint32_t label) const {
     369         630 :     for (uint8_t count = 0; count < MAX_XMPP_SERVERS; count++) {
     370         420 :         if ((label >= multicast_label_start_[count]) &&
     371          10 :             (label <= multicast_label_end_[count])) return true;
     372             :     }
     373         210 :     return false;
     374             : }
     375             : 
     376           3 : void MplsTable::ReserveLabel(uint32_t start, uint32_t end) {
     377             :     // We want to allocate labels from an offset
     378             :     // Pre-allocate entries
     379          19 :     for (uint32_t i = start; i <= end;  i++) {
     380          16 :         agent()->resource_manager()->ReserveIndex(Resource::MPLS_INDEX, i);
     381             :     }
     382           3 : }
     383             : 
     384           1 : void MplsTable::FreeReserveLabel(uint32_t start, uint32_t end) {
     385             :     // We want to allocate labels from an offset
     386             :     // Pre-allocate entries
     387          17 :     for (uint32_t i = start; i <= end;  i++) {
     388          16 :         agent()->resource_manager()->ReleaseIndex(Resource::MPLS_INDEX, i);
     389             :     }
     390           1 : }
     391             : 
     392           2 : void MplsTable::ReserveMulticastLabel(uint32_t start, uint32_t end,
     393             :                                       uint8_t idx) {
     394           2 :     multicast_label_start_[idx] = start;
     395           2 :     multicast_label_end_[idx] = end;
     396           2 :     ReserveLabel(start, end);
     397           2 : }
     398             : 
     399          31 : MplsLabel *MplsTable::FindMplsLabel(uint32_t label) {
     400          31 :     MplsLabelKey key(label);
     401          62 :     return static_cast<MplsLabel *>(Find(&key, false));
     402          31 : }
     403             : 
     404             : // Allocate label for next-hop(interface, vrf, vlan)
     405          68 : MplsLabel *MplsTable::AllocLabel(const NextHopKey *nh_key) {
     406          68 :     switch(nh_key->GetType()) {
     407          68 :     case NextHop::INTERFACE:
     408             :     case NextHop::VLAN:
     409             :     case NextHop::VRF:
     410          68 :         break;
     411           0 :     default:
     412           0 :         assert(0);
     413             :     }
     414             : 
     415             :     // Allocate label from resource manager
     416             :     ResourceManager::KeyPtr rkey(new NexthopIndexResourceKey(
     417          68 :                                          agent()->resource_manager(),
     418         136 :                                          nh_key->Clone()));
     419             :     uint32_t label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
     420          68 :                                       Allocate(rkey).get()))->index());
     421          68 :     assert(label != MplsTable::kInvalidLabel);
     422             : 
     423             :     // Add MplsLabel db entry
     424          68 :     DBRequest req;
     425          68 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     426             : 
     427          68 :     MplsLabelKey *key = new MplsLabelKey(label);
     428          68 :     req.key.reset(key);
     429             : 
     430          68 :     MplsLabelData *data = new MplsLabelData(nh_key->Clone());
     431          68 :     req.data.reset(data);
     432             : 
     433          68 :     agent()->mpls_table()->Process(req);
     434             : 
     435             :     // Return MplsLabel db entry for nh to hold reference
     436          68 :     MplsLabel *mpls_label = static_cast<MplsLabel *>
     437          68 :         (agent()->mpls_table()->FindActiveEntry(key));
     438          68 :     assert(mpls_label);
     439             : 
     440         136 :     return mpls_label;
     441             : }
     442             : 
     443         150 : void MplsTable::CheckVrLabelLimit() {
     444         150 :     VrLimitExceeded &vr_limits = agent()->get_vr_limits_exceeded_map();
     445         150 :     VrLimitExceeded::iterator vr_limit_itr = vr_limits.find("vr_mpls_labels");
     446         150 :     if (vr_limit_itr->second == "Normal") {
     447         150 :         if (label_table_.InUseIndexCount() >= ((agent()->vr_limit_high_watermark() *
     448         150 :             agent()->vrouter_max_labels())/100) ) {
     449           0 :             vr_limit_itr->second.assign(std::string("Exceeded"));
     450           0 :             LOG(ERROR, "Vrouter Mpls Labels Exceeded.");
     451             :         }
     452           0 :     } else if ( vr_limit_itr->second == "Exceeded") {
     453           0 :         if (label_table_.InUseIndexCount() >= agent()->vrouter_max_labels()) {
     454           0 :             vr_limit_itr->second.assign(std::string("TableLimit"));
     455           0 :             LOG(ERROR, "Vrouter Mpls Lablels Table Limit Reached. Skip Label Add.");
     456           0 :         } else if ( label_table_.InUseIndexCount() < ((agent()->vr_limit_low_watermark() *
     457           0 :             agent()->vrouter_max_labels())/100) ) {
     458           0 :             vr_limit_itr->second.assign(std::string("Normal"));
     459             :         }
     460           0 :     } else if ( vr_limit_itr->second == "TableLimit" ) {
     461           0 :         if (label_table_.InUseIndexCount() <
     462           0 :             ((agent()->vrouter_max_labels()*95)/100) ) {
     463           0 :             vr_limit_itr->second.assign(std::string("Exceeded"));
     464           0 :             LOG(ERROR, "Vrouter Mpls Labels Exceeded.");
     465             :         }
     466             :     }
     467         150 :     agent()->set_vr_limits_exceeded_map(vr_limits);
     468         150 : }
     469             : 
     470           0 : AgentSandeshPtr MplsTable::GetAgentSandesh(const AgentSandeshArguments *args,
     471             :                                            const std::string &context) {
     472             :     return AgentSandeshPtr(new AgentMplsSandesh
     473           0 :                            (context, args->GetString("type"),
     474           0 :                             args->GetString("label")));
     475             : }
     476             : 
     477           0 : void MplsReq::HandleRequest() const {
     478           0 :     AgentSandeshPtr sand(new AgentMplsSandesh(context(), get_type(),
     479           0 :                                               get_label()));
     480           0 :     sand->DoSandesh(sand);
     481           0 : }

Generated by: LCOV version 1.14