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: 240 308 77.9 %
Date: 2026-08-24 02:06:43 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        1338 : MplsLabel::MplsLabel(Agent *agent, uint32_t label) :
      27        1338 :     agent_(agent), label_(label), free_label_(false) {
      28        1338 : }
      29             : 
      30        2676 : MplsLabel::~MplsLabel() {
      31        1338 :     if (free_label_) {
      32         229 :         if (label_ != MplsTable::kInvalidLabel) {
      33         229 :             MplsTable *table = static_cast<MplsTable *>(get_table());
      34         229 :             table->FreeMplsLabelIndex(label_);
      35             :         }
      36         229 :         agent_->resource_manager()->Release(Resource::MPLS_INDEX, label_);
      37             :     }
      38        2676 : }
      39             : 
      40        9140 : bool MplsLabel::IsLess(const DBEntry &rhs) const {
      41        9140 :         const MplsLabel &mpls = static_cast<const MplsLabel &>(rhs);
      42        9140 :         return label_ < mpls.label_;
      43             : }
      44             : 
      45           0 : std::string MplsLabel::ToString() const {
      46           0 :     return "MPLS";
      47             : }
      48             : 
      49         198 : DBEntryBase::KeyPtr MplsLabel::GetDBRequestKey() const {
      50         198 :     MplsLabelKey *key = new MplsLabelKey(label_);
      51         198 :     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         229 : uint32_t MplsLabel::GetRefCount() const {
      60         229 :     return AgentRefCount<MplsLabel>::GetRefCount();
      61             : }
      62             : 
      63         229 : void MplsLabel::Add(const DBRequest *req) {
      64         229 :     free_label_ = true;
      65         229 :     ChangeInternal(req);
      66         229 :     SendObjectLog(agent_->mpls_table(), AgentLogEvent::ADD);
      67         229 :     return;
      68             : }
      69             : 
      70         190 : bool MplsLabel::Change(const DBRequest *req) {
      71         190 :     const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
      72         190 :     bool ret = ChangeInternal(req);
      73         190 :     SendObjectLog(table, AgentLogEvent::CHANGE);
      74         190 :     return ret;
      75             : }
      76             : 
      77         229 : void MplsLabel::Delete(const DBRequest *req) {
      78         229 :     const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
      79         229 :     SendObjectLog(table, AgentLogEvent::DEL);
      80         229 :     return;
      81             : }
      82             : 
      83         419 : bool MplsLabel::ChangeInternal(const DBRequest *req) {
      84         419 :     NextHopTable *nh_table = agent_->nexthop_table();
      85         419 :     MplsLabelData *data = static_cast<MplsLabelData *>(req->data.get());
      86             :     NextHop *nh =
      87         419 :         static_cast<NextHop *>(nh_table->FindActiveEntry(data->nh_key()));
      88         419 :     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         419 :     return ChangeNH(nh);
      95             : }
      96             : 
      97         611 : bool MplsLabel::ChangeNH(NextHop *nh) {
      98         611 :     if (nh_ == nh)
      99         286 :         return false;
     100             : 
     101         325 :     assert(nh);
     102         325 :     nh_ = nh;
     103             : 
     104         325 :     if (IsFabricMulticastReservedLabel()) {
     105           6 :         CompositeNH *cnh = dynamic_cast<CompositeNH*>(nh);
     106           6 :         if (cnh && cnh->vrf()) {
     107           6 :             FmgVrfNhMap::iterator it = fmg_nh_list_.begin();
     108          10 :             while( it != fmg_nh_list_.end()) {
     109           4 :                 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           4 :                     it++;
     116             :                 }
     117             :             }
     118           6 :             fmg_nh_list_[cnh->vrf()->GetName()] = nh;
     119             :         }
     120             :     }
     121             : 
     122         325 :     SyncDependentPath();
     123         325 :     return true;
     124             : }
     125             : 
     126         325 : void MplsLabel::SyncDependentPath() {
     127         325 :     MPLS_TRACE(MplsTrace, "Syncing routes for label ", label());
     128         325 :     for (DependentPathList::iterator iter =
     129         650 :          mpls_label_.begin(); iter != mpls_label_.end(); iter++) {
     130           0 :         AgentRoute *rt = iter.operator->();
     131           0 :         rt->EnqueueRouteResync();
     132             :     }
     133         325 : }
     134             : 
     135         333 : bool MplsLabel::IsFabricMulticastReservedLabel() const {
     136             :     //MplsTable *table = static_cast<MplsTable *>(get_table());
     137         333 :     MplsTable *table = static_cast<MplsTable *>(agent_->mpls_table());
     138         333 :     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         648 : void MplsLabel::SendObjectLog(const AgentDBTable *table,
     158             :                               AgentLogEvent::type event) const {
     159         648 :     MplsObjectLogInfo info;
     160         648 :     string str, type_str, nh_type;
     161         648 :     info.set_type(type_str);
     162         648 :     info.set_label((int)label_);
     163         648 :     switch (event) {
     164         229 :     case AgentLogEvent::ADD:
     165         229 :         str.assign("Addition ");
     166         229 :         break;
     167         229 :     case AgentLogEvent::DEL:
     168         229 :         str.assign("Deletion ");
     169         229 :         info.set_event(str);
     170         229 :         OPER_TRACE_ENTRY(Mpls, table, info);
     171         229 :         return;
     172         190 :     case AgentLogEvent::CHANGE:
     173         190 :         str.assign("Modification ");
     174         190 :         break;
     175           0 :     default:
     176           0 :         str.assign("Unknown");
     177           0 :         break;
     178             :     }
     179         419 :     info.set_event(str);
     180         419 :     const NextHop *nh = nexthop();
     181         419 :     const Interface *intf = NULL;
     182             :     /* Mpls is not expected to have any other nexthop apart from Interface
     183             :        or Vlan */
     184         419 :     if (nh != NULL) {
     185         419 :         string policy_str("Disabled");
     186             :         const InterfaceNH *if_nh;
     187             :         const VlanNH *vlan_nh;
     188             : 
     189         419 :         switch(nh->GetType()) {
     190         175 :         case NextHop::INTERFACE:
     191         175 :             nh_type.assign("INTERFACE");
     192         175 :             if_nh = static_cast<const InterfaceNH *>(nh);
     193         175 :             intf = if_nh->GetInterface();
     194         175 :             if (if_nh->PolicyEnabled()) {
     195          70 :                 policy_str.assign("Enabled");
     196             :             }
     197         175 :             info.set_policy(policy_str);
     198         175 :             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         186 :         case NextHop::COMPOSITE:
     206         186 :             nh_type.assign("Composite");
     207         186 :             break;
     208          58 :         default:
     209          58 :             nh_type.assign("unknown");
     210          58 :             break;
     211             :         }
     212         419 :     }
     213         419 :     info.set_nh_type(nh_type);
     214             :     /* Interface Nexthop pointed by Mpls object will always be of type VMPORT */
     215         419 :     if (intf) {
     216         175 :         string if_type_str;
     217         175 :         switch(intf->type()) {
     218         175 :         case Interface::VM_INTERFACE:
     219         175 :             if_type_str.assign("VM_INTERFACE");
     220         175 :             break;
     221           0 :         default:
     222           0 :             if_type_str.assign("Invalid");
     223           0 :             break;
     224             :         }
     225         175 :         info.set_intf_type(if_type_str);
     226         175 :         info.set_intf_uuid(UuidToString(intf->GetUuid()));
     227         175 :         info.set_intf_name(intf->name());
     228         175 :     }
     229         419 :     OPER_TRACE_ENTRY(Mpls, table, info);
     230        1335 : }
     231             : 
     232             : /****************************************************************************
     233             :  * MplsTable routines
     234             :  ***************************************************************************/
     235           3 : MplsTable::MplsTable(DB *db, const std::string &name) :
     236           3 :     AgentDBTable(db, name) {
     237           3 : }
     238             : 
     239           6 : MplsTable::~MplsTable() {
     240           6 : }
     241             : 
     242           3 : DBTableBase *MplsTable::CreateTable(DB *db, const std::string &name) {
     243           3 :     MplsTable *table = new MplsTable(db, name);
     244           3 :     table->Init();
     245           3 :     return table;
     246             : };
     247             : 
     248         650 : void MplsTable::Process(DBRequest &req) {
     249         650 :     agent()->ConcurrencyCheck();
     250             :     DBTablePartition *tpart =
     251         650 :         static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
     252         650 :     tpart->Process(NULL, &req);
     253         650 : }
     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          33 : void MplsTable::FreeLabel(uint32_t label, const std::string &vrf_name) {
     272          33 :     DBRequest req;
     273          33 :     req.oper = DBRequest::DB_ENTRY_DELETE;
     274             : 
     275          33 :     MplsLabelKey *key = new MplsLabelKey(label);
     276          33 :     MplsLabelData *data = new MplsLabelData(NULL);
     277          33 :     data->set_vrf_name(vrf_name);
     278          33 :     req.key.reset(key);
     279          33 :     req.data.reset(data);
     280             : 
     281          33 :     Process(req);
     282          33 : }
     283             : 
     284        1109 : std::unique_ptr<DBEntry> MplsTable::AllocEntry(const DBRequestKey *k) const {
     285        1109 :     const MplsLabelKey *key = static_cast<const MplsLabelKey *>(k);
     286        1109 :     MplsLabel *mpls = new MplsLabel(agent(), key->label());
     287        1109 :     return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(mpls));
     288             : }
     289             : 
     290         229 : DBEntry *MplsTable::Add(const DBRequest *req) {
     291         229 :     CheckVrLabelLimit();
     292         229 :     MplsLabelKey *key = static_cast<MplsLabelKey *>(req->key.get());
     293         229 :     assert(key->label() != MplsTable::kInvalidLabel);
     294             : 
     295         229 :     MplsLabel *mpls = new MplsLabel(agent(), key->label());
     296         229 :     label_table_.InsertAtIndex(mpls->label(), mpls);
     297         229 :     mpls->Add(req);
     298         229 :     return mpls;
     299             : }
     300             : 
     301         190 : bool MplsTable::OnChange(DBEntry *entry, const DBRequest *req) {
     302         190 :     MplsLabel *mpls = static_cast<MplsLabel *>(entry);
     303         190 :     return mpls->Change(req);
     304             : }
     305             : 
     306         229 : bool MplsTable::Delete(DBEntry *entry, const DBRequest *req) {
     307         229 :     MplsLabel *mpls = static_cast<MplsLabel *>(entry);
     308         229 :     if (IsFabricMulticastLabel(mpls->label())) {
     309           2 :         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           2 :         assert(data);
     313           2 :         if (mpls->fmg_nh_list().find(data->vrf_name()) !=
     314           4 :                 mpls->fmg_nh_list().end()) {
     315           2 :             mpls->fmg_nh_list().erase(data->vrf_name());
     316             :         }
     317           2 :         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         229 :     mpls->Delete(req);
     327         229 :     CheckVrLabelLimit();
     328         229 :     return true;
     329             : }
     330             : 
     331         198 : void MplsTable::OnZeroRefcount(AgentDBEntry *e) {
     332         198 :     agent()->ConcurrencyCheck();
     333             : 
     334             :     //Delete db entry
     335         198 :     DBRequest req(DBRequest::DB_ENTRY_DELETE);
     336         198 :     req.key = e->GetDBRequestKey();
     337         198 :     req.data.reset(NULL);
     338         198 :     Process(req);
     339         198 : }
     340             : 
     341         221 : uint32_t MplsTable::CreateRouteLabel(uint32_t label, const NextHopKey *nh_key,
     342             :                                 const std::string &vrf_name,
     343             :                                 const std::string &route) {
     344         221 :     if (label == MplsTable::kInvalidLabel) {
     345             :         ResourceManager::KeyPtr key(new RouteMplsResourceKey(agent()->
     346          29 :                                 resource_manager(), vrf_name,
     347          29 :                                 route));
     348             :         label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
     349          29 :                                       Allocate(key).get()))->index());
     350          29 :         assert(label != MplsTable::kInvalidLabel);
     351          29 :         assert(FindMplsLabel(label) == NULL);
     352          29 :     }
     353             : 
     354         221 :     DBRequest req;
     355         221 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     356             : 
     357         221 :     MplsLabelKey *key = new MplsLabelKey(label);
     358         221 :     req.key.reset(key);
     359             : 
     360         221 :     MplsLabelData *data = new MplsLabelData(nh_key->Clone());
     361         221 :     data->set_vrf_name(vrf_name);
     362         221 :     req.data.reset(data);
     363             : 
     364         221 :     Process(req);
     365         221 :     return label;
     366         221 : }
     367             : 
     368         717 : bool MplsTable::IsFabricMulticastLabel(uint32_t label) const {
     369        2125 :     for (uint8_t count = 0; count < MAX_XMPP_SERVERS; count++) {
     370        1421 :         if ((label >= multicast_label_start_[count]) &&
     371          43 :             (label <= multicast_label_end_[count])) return true;
     372             :     }
     373         704 :     return false;
     374             : }
     375             : 
     376          14 : void MplsTable::ReserveLabel(uint32_t start, uint32_t end) {
     377             :     // We want to allocate labels from an offset
     378             :     // Pre-allocate entries
     379        5067 :     for (uint32_t i = start; i <= end;  i++) {
     380        5053 :         agent()->resource_manager()->ReserveIndex(Resource::MPLS_INDEX, i);
     381             :     }
     382          14 : }
     383             : 
     384           3 : void MplsTable::FreeReserveLabel(uint32_t start, uint32_t end) {
     385             :     // We want to allocate labels from an offset
     386             :     // Pre-allocate entries
     387          51 :     for (uint32_t i = start; i <= end;  i++) {
     388          48 :         agent()->resource_manager()->ReleaseIndex(Resource::MPLS_INDEX, i);
     389             :     }
     390           3 : }
     391             : 
     392          11 : void MplsTable::ReserveMulticastLabel(uint32_t start, uint32_t end,
     393             :                                       uint8_t idx) {
     394          11 :     multicast_label_start_[idx] = start;
     395          11 :     multicast_label_end_[idx] = end;
     396          11 :     ReserveLabel(start, end);
     397          11 : }
     398             : 
     399          57 : MplsLabel *MplsTable::FindMplsLabel(uint32_t label) {
     400          57 :     MplsLabelKey key(label);
     401         114 :     return static_cast<MplsLabel *>(Find(&key, false));
     402          57 : }
     403             : 
     404             : // Allocate label for next-hop(interface, vrf, vlan)
     405         198 : MplsLabel *MplsTable::AllocLabel(const NextHopKey *nh_key) {
     406         198 :     switch(nh_key->GetType()) {
     407         198 :     case NextHop::INTERFACE:
     408             :     case NextHop::VLAN:
     409             :     case NextHop::VRF:
     410         198 :         break;
     411           0 :     default:
     412           0 :         assert(0);
     413             :     }
     414             : 
     415             :     // Allocate label from resource manager
     416             :     ResourceManager::KeyPtr rkey(new NexthopIndexResourceKey(
     417         198 :                                          agent()->resource_manager(),
     418         396 :                                          nh_key->Clone()));
     419             :     uint32_t label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
     420         198 :                                       Allocate(rkey).get()))->index());
     421         198 :     assert(label != MplsTable::kInvalidLabel);
     422             : 
     423             :     // Add MplsLabel db entry
     424         198 :     DBRequest req;
     425         198 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     426             : 
     427         198 :     MplsLabelKey *key = new MplsLabelKey(label);
     428         198 :     req.key.reset(key);
     429             : 
     430         198 :     MplsLabelData *data = new MplsLabelData(nh_key->Clone());
     431         198 :     req.data.reset(data);
     432             : 
     433         198 :     agent()->mpls_table()->Process(req);
     434             : 
     435             :     // Return MplsLabel db entry for nh to hold reference
     436         198 :     MplsLabel *mpls_label = static_cast<MplsLabel *>
     437         198 :         (agent()->mpls_table()->FindActiveEntry(key));
     438         198 :     assert(mpls_label);
     439             : 
     440         396 :     return mpls_label;
     441             : }
     442             : 
     443         458 : void MplsTable::CheckVrLabelLimit() {
     444         458 :     VrLimitExceeded &vr_limits = agent()->get_vr_limits_exceeded_map();
     445         458 :     VrLimitExceeded::iterator vr_limit_itr = vr_limits.find("vr_mpls_labels");
     446         458 :     if (vr_limit_itr->second == "Normal") {
     447         458 :         if (label_table_.InUseIndexCount() >= ((agent()->vr_limit_high_watermark() *
     448         458 :             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         458 :     agent()->set_vr_limits_exceeded_map(vr_limits);
     468         458 : }
     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