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

Generated by: LCOV version 1.14