LCOV - code coverage report
Current view: top level - vnsw/agent/mac_learning - mac_learning.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 44 320 13.8 %
Date: 2026-08-03 02:19:58 Functions: 10 37 27.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include <init/agent_param.h>
       5             : #include <oper/vn.h>
       6             : #include <oper/sg.h>
       7             : #include <oper/vrf.h>
       8             : #include <oper/nexthop.h>
       9             : #include <oper/interface_common.h>
      10             : #include <oper/route_common.h>
      11             : #include "mac_learning_proto.h"
      12             : #include "mac_learning_proto_handler.h"
      13             : #include "mac_learning_init.h"
      14             : #include "mac_learning.h"
      15             : #include "mac_learning_mgmt.h"
      16             : #include "mac_aging.h"
      17             : #include "vr_bridge.h"
      18             : 
      19             : 
      20           0 : MacPbbLearningEntry::MacPbbLearningEntry(MacLearningPartition *table, uint32_t vrf_id,
      21             :                                    const MacAddress &mac,
      22           0 :                                    uint32_t index):
      23           0 :     MacLearningEntry(vrf_id),mac_learning_table_(table), key_(vrf_id, mac), index_(index) {
      24             :     vrf_ = table->agent()->vrf_table()->
      25           0 :                FindVrfFromIdIncludingDeletedVrf(key_.vrf_id_);
      26           0 : }
      27             : 
      28           0 : void MacPbbLearningEntry::Delete() {
      29           0 :     deleted_ = true;
      30           0 :     AddToken(mac_learning_table_->agent()->mac_learning_proto()->
      31           0 :              GetToken(MacLearningEntryRequest::DELETE_MAC));
      32             : 
      33           0 :     mac_learning_table_->agent()->fabric_evpn_table()->
      34           0 :         DeleteReq(mac_learning_table_->agent()->mac_learning_peer(),
      35           0 :                   vrf()->GetName(), mac(), Ip4Address(0), 32, 0, NULL);
      36           0 : }
      37             : 
      38           0 : void MacPbbLearningEntry::AddWithToken() {
      39           0 :     if (Add()) {
      40           0 :         AddToken(mac_learning_table_->agent()->mac_learning_proto()->
      41           0 :                  GetToken(MacLearningEntryRequest::ADD_MAC));
      42             :     }
      43           0 : }
      44             : 
      45           0 : void MacPbbLearningEntry::Resync() {
      46           0 :     if (Add()) {
      47           0 :         AddToken(mac_learning_table_->agent()->mac_learning_proto()->
      48           0 :                  GetToken(MacLearningEntryRequest::RESYNC_MAC));
      49             :     }
      50           0 : }
      51             : 
      52           0 : void MacPbbLearningEntry::EnqueueToTable(MacLearningEntryRequestPtr req) {
      53           0 :         mac_learning_table_->Enqueue(req);
      54           0 : }
      55           0 : MacLearningEntryLocal::MacLearningEntryLocal(MacLearningPartition *table,
      56             :                                              uint32_t vrf_id,
      57             :                                              const MacAddress &mac,
      58             :                                              uint32_t index,
      59           0 :                                              InterfaceConstRef intf):
      60           0 :     MacPbbLearningEntry(table, vrf_id, mac, index), intf_(intf) {
      61           0 : }
      62             : 
      63           0 : bool MacLearningEntryLocal::Add() {
      64           0 :     const VmInterface *vm_intf = dynamic_cast<const VmInterface *>(intf_.get());
      65           0 :     assert(vm_intf);
      66             : 
      67           0 :     if (vrf()->IsActive() ==  false) {
      68           0 :         return false;
      69             :     }
      70             : 
      71           0 :     if (vm_intf->vn() == NULL) {
      72           0 :         return false;
      73             :     }
      74             : 
      75           0 :     if (vm_intf->vn() == NULL) {
      76           0 :         return false;
      77             :     }
      78             : 
      79           0 :     SecurityGroupList sg_list;
      80           0 :     vm_intf->CopySgIdList(&sg_list);
      81             : 
      82           0 :     TagList tag_list;
      83           0 :     vm_intf->CopyTagIdList(&tag_list);
      84             : 
      85           0 :     mac_learning_table_->agent()->fabric_evpn_table()->
      86           0 :         AddLocalVmRouteReq(mac_learning_table_->agent()->mac_learning_peer(),
      87             :                            vrf()->GetName(),
      88           0 :                            mac(), vm_intf, Ip4Address(0),
      89             :                            vm_intf->l2_label(),
      90             :                            vm_intf->vn()->GetName(), sg_list, tag_list,
      91           0 :                            PathPreference(), 0,
      92           0 :                            vm_intf->etree_leaf());
      93           0 :     return true;
      94           0 : }
      95             : 
      96           0 : MacLearningEntryRemote::MacLearningEntryRemote(MacLearningPartition *table,
      97             :                                                uint32_t vrf_id,
      98             :                                                const MacAddress &mac,
      99             :                                                uint32_t index,
     100           0 :                                                IpAddress remote_ip):
     101           0 :     MacPbbLearningEntry(table, vrf_id, mac, index), remote_ip_(remote_ip) {
     102           0 : }
     103             : 
     104           0 : bool MacLearningEntryRemote::Add() {
     105           0 :     return true;
     106             : }
     107             : 
     108           0 : MacLearningEntryPBB::MacLearningEntryPBB(MacLearningPartition *table,
     109             :                                          uint32_t vrf_id,
     110             :                                          const MacAddress &mac,
     111             :                                          uint32_t index,
     112           0 :                                          const MacAddress &bmac) :
     113           0 :     MacPbbLearningEntry(table, vrf_id, mac, index), bmac_(bmac) {
     114           0 : }
     115             : 
     116           0 : bool MacLearningEntryPBB::Add() {
     117           0 :     assert(vrf_);
     118           0 :     uint32_t isid = vrf_->isid();
     119           0 :     std::string bmac_vrf_name = vrf_->bmac_vrf_name();
     120           0 :     PBBRoute *data = new PBBRoute(VrfKey(bmac_vrf_name), bmac_, isid,
     121           0 :                                    VnListType(),
     122           0 :                                    SecurityGroupList(), TagList());
     123           0 :     EvpnAgentRouteTable::AddRemoteVmRouteReq(mac_learning_table_->agent()->
     124             :                                              mac_learning_peer(),
     125             :                                              vrf()->GetName(),
     126           0 :                                              mac(), Ip4Address(0), 32, 0, data);
     127           0 :     return true;
     128           0 : }
     129             : 
     130           9 : MacLearningRequestQueue::MacLearningRequestQueue(MacLearningPartition *partition,
     131           9 :                                                  TokenPool *pool):
     132           9 :     partition_(partition), pool_(pool),
     133          18 :     queue_(partition_->agent()->task_scheduler()->GetTaskId(kTaskMacLearning),
     134           9 :            partition->id(),
     135           9 :            boost::bind(&MacLearningRequestQueue::HandleEvent, this, _1)) {
     136           9 :     queue_.SetStartRunnerFunc(boost::bind(&MacLearningRequestQueue::TokenCheck,
     137             :                                           this));
     138           9 : }
     139             : 
     140          94 : bool MacLearningRequestQueue::TokenCheck() {
     141          94 :     if (pool_) {
     142          94 :         return pool_->TokenCheck();
     143             :     }
     144             : 
     145           0 :     return true;
     146             : }
     147             : 
     148          87 : bool MacLearningRequestQueue::HandleEvent(MacLearningEntryRequestPtr ptr) {
     149          87 :     return partition_->RequestHandler(ptr);
     150             : }
     151             : 
     152           3 : MacLearningPartition::MacLearningPartition(Agent *agent,
     153             :                                            MacLearningProto *proto,
     154           3 :                                            uint32_t id):
     155           3 :     agent_(agent), id_(id),
     156           3 :     add_request_queue_(this, proto->add_tokens()),
     157           3 :     change_request_queue_(this, proto->change_tokens()),
     158           6 :     delete_request_queue_(this, proto->delete_tokens()) {
     159           3 :     aging_partition_.reset(new MacAgingPartition(agent, id));
     160           3 : }
     161             : 
     162           6 : MacLearningPartition::~MacLearningPartition() {
     163           3 :     assert(mac_learning_table_.size() == 0);
     164           6 : }
     165             : 
     166           0 : void MacLearningPartition::MayBeStartRunner(TokenPool *pool) {
     167           0 :     if (agent_->mac_learning_proto()->add_tokens() == pool) {
     168           0 :         add_request_queue_.MayBeStartRunner();
     169           0 :     } else if (agent_->mac_learning_proto()->change_tokens() == pool) {
     170           0 :         change_request_queue_.MayBeStartRunner();
     171             :     } else {
     172           0 :         delete_request_queue_.MayBeStartRunner();
     173             :     }
     174           0 : }
     175             : 
     176          87 : bool MacLearningPartition::RequestHandler(MacLearningEntryRequestPtr ptr) {
     177          87 :     switch(ptr->event()) {
     178           0 :     case MacLearningEntryRequest::VROUTER_MSG:
     179           0 :         agent()->mac_learning_proto()->ProcessProto(ptr->pkt_info());
     180           0 :         break;
     181             : 
     182           0 :     case MacLearningEntryRequest::ADD_MAC:
     183           0 :         Add(ptr->mac_learning_entry());
     184           0 :         break;
     185             : 
     186           0 :     case MacLearningEntryRequest::RESYNC_MAC:
     187           0 :         Resync(ptr->mac_learning_entry());
     188           0 :         break;
     189             : 
     190           0 :     case MacLearningEntryRequest::DELETE_MAC:
     191           0 :         Delete(ptr->mac_learning_entry());
     192           0 :         break;
     193             : 
     194          87 :     case MacLearningEntryRequest::FREE_DB_ENTRY:
     195             :         agent()->mac_learning_module()->
     196          87 :             mac_learning_db_client()->FreeDBState(ptr->db_entry(),
     197             :                                                   ptr->gen_id());
     198          87 :         break;
     199             : 
     200           0 :     default:
     201           0 :         assert(0);
     202             :     }
     203          87 :     return true;
     204             : }
     205             : 
     206           0 : void MacLearningPartition::EnqueueMgmtReq(MacLearningEntryPtr ptr, bool add) {
     207           0 :     MacLearningMgmtRequest::Event e = MacLearningMgmtRequest::ADD_MAC;
     208           0 :     if (add == false) {
     209           0 :         e = MacLearningMgmtRequest::DELETE_MAC;
     210             :     }
     211           0 :     MacLearningMgmtRequestPtr req(new MacLearningMgmtRequest(e, ptr));
     212           0 :     agent()->mac_learning_module()->mac_learning_mgmt()->Enqueue(req);
     213           0 : }
     214             : 
     215           0 : void MacLearningPartition::Add(MacLearningEntryPtr ptr) {
     216           0 :     MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
     217           0 :     if (!entry) {
     218           0 :         return;
     219             :     }
     220           0 :     MacLearningKey key(ptr->vrf_id(), entry->mac());
     221             : 
     222             :     std::pair<MacLearningEntryTable::iterator, bool> it =
     223           0 :         mac_learning_table_.insert(MacLearningEntryPair(key, ptr));
     224           0 :     if (it.second == false) {
     225             :         //Entry already present, clear the entry and delete it from
     226             :         //aging tree
     227           0 :         ptr->CopyToken(it.first->second.get());
     228           0 :         if (it.first->second->deleted() == false) {
     229             :             MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
     230           0 :                         MacLearningEntryRequest::DELETE_MAC, it.first->second));
     231           0 :             aging_partition_->Enqueue(aging_req);
     232           0 :         }
     233           0 :         mac_learning_table_[key] = ptr;
     234             :     }
     235             : 
     236           0 :     ptr->AddWithToken();
     237           0 :     EnqueueMgmtReq(ptr, true);
     238             :     MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
     239           0 :                                    MacLearningEntryRequest::ADD_MAC, ptr));
     240           0 :     aging_partition_->Enqueue(aging_req);
     241           0 : }
     242             : 
     243           0 : void MacLearningPartition::Delete(const MacLearningEntryPtr ptr) {
     244           0 :     if (ptr->deleted() == true) {
     245           0 :         return;
     246             :     }
     247           0 :     MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
     248           0 :     if (!entry) {
     249           0 :         return;
     250             :     }
     251           0 :     MacLearningKey key(ptr->vrf_id(), entry->mac());
     252           0 :     if (mac_learning_table_.find(key) == mac_learning_table_.end()) {
     253           0 :         return;
     254             :     }
     255             : 
     256           0 :     ptr->Delete();
     257             :     MacLearningEntryRequestPtr aging_req(new MacLearningEntryRequest(
     258             :                                          MacLearningEntryRequest::DELETE_MAC,
     259           0 :                                          ptr));
     260           0 :     aging_partition_->Enqueue(aging_req);
     261           0 :     EnqueueMgmtReq(ptr, false);
     262           0 : }
     263             : 
     264           0 : void MacLearningPartition::Resync(MacLearningEntryPtr ptr) {
     265           0 :     MacPbbLearningEntry *entry = dynamic_cast<MacPbbLearningEntry *>(ptr.get());
     266           0 :     if (!entry) {
     267           0 :         return;
     268             :     }
     269           0 :     MacLearningKey key(ptr->vrf_id(), entry->mac());
     270           0 :     if (mac_learning_table_.find(key) == mac_learning_table_.end()) {
     271           0 :         return;
     272             :     }
     273             : 
     274           0 :     ptr->Resync();
     275             : }
     276             : 
     277          87 : void MacLearningPartition::Enqueue(MacLearningEntryRequestPtr req) {
     278          87 :     switch(req->event()) {
     279          87 :     case MacLearningEntryRequest::VROUTER_MSG:
     280             :     case MacLearningEntryRequest::ADD_MAC:
     281             :     case MacLearningEntryRequest::FREE_DB_ENTRY:
     282             :     case MacLearningEntryRequest::DELETE_VRF:
     283          87 :         add_request_queue_.Enqueue(req);
     284          87 :         break;
     285             : 
     286           0 :     case MacLearningEntryRequest::RESYNC_MAC:
     287           0 :         change_request_queue_.Enqueue(req);
     288           0 :         break;
     289             : 
     290           0 :     case MacLearningEntryRequest::DELETE_MAC:
     291           0 :         delete_request_queue_.Enqueue(req);
     292           0 :         break;
     293             : 
     294           0 :     default:
     295           0 :         assert(0);
     296             :     }
     297          87 :     return;
     298             : }
     299             : 
     300             : MacLearningEntry*
     301         237 : MacLearningPartition::Find(const MacLearningKey &key) {
     302         237 :     MacLearningEntryTable::iterator it = mac_learning_table_.find(key);
     303         237 :     if (it == mac_learning_table_.end()) {
     304         237 :         return NULL;
     305             :     }
     306           0 :     return it->second.get();
     307             : }
     308             : 
     309             : MacLearningEntryPtr
     310           0 : MacLearningPartition::TestGet(const MacLearningKey &key) {
     311           0 :     MacLearningEntryTable::iterator it = mac_learning_table_.find(key);
     312           0 :     return it->second;
     313             : }
     314             : 
     315         237 : void MacLearningPartition::ReleaseToken(const MacLearningKey &key) {
     316         237 :     MacLearningEntry *mac_entry = Find(key);
     317         237 :     if (mac_entry) {
     318           0 :         mac_entry->ReleaseToken();
     319           0 :         if (mac_entry->deleted()) {
     320           0 :             mac_learning_table_.erase(key);
     321             :         }
     322             :     }
     323         237 : }
     324             : 
     325           0 : MacLearningSandeshResp::MacLearningSandeshResp(Agent *agent,
     326             :                                          MacEntryResp *resp,
     327             :                                          std::string resp_ctx,
     328             :                                          std::string key,
     329           0 :                                          const MacAddress &mac) :
     330             :     Task((TaskScheduler::GetInstance()->
     331             :                 GetTaskId("Agent::MacLearningSandeshTask")), 0),
     332           0 :     agent_(agent), resp_(resp), resp_data_(resp_ctx), partition_id_(0),
     333           0 :     vrf_id_(0), mac_(MacAddress::ZeroMac()), exact_match_(false),
     334           0 :     user_given_mac_(mac) {
     335           0 :     if (key != agent_->NullString()) {
     336           0 :         SetMacKey(key);
     337             :     }
     338           0 : }
     339             : 
     340           0 : MacLearningSandeshResp::~MacLearningSandeshResp() {
     341           0 : }
     342             : 
     343           0 : bool MacLearningSandeshResp::SetMacKey(string key) {
     344           0 :     const char ch = kDelimiter;
     345           0 :     size_t n = std::count(key.begin(), key.end(), ch);
     346           0 :     if (n != 3) {
     347           0 :         return false;
     348             :     }
     349             : 
     350           0 :     std::stringstream ss(key);
     351           0 :     string item;
     352             : 
     353           0 :     if (getline(ss, item, ch)) {
     354           0 :         std::istringstream(item) >> partition_id_;
     355             :     }
     356           0 :     if (getline(ss, item, ch)) {
     357           0 :         std::istringstream(item) >> vrf_id_;
     358             :     }
     359           0 :     if (getline(ss, item, ch)) {
     360           0 :         mac_ = MacAddress::FromString(item);
     361             :     }
     362           0 :     if (getline(ss, item, ch)) {
     363           0 :         std::istringstream(item) >> exact_match_;
     364             :     }
     365           0 :     return true;
     366           0 : }
     367             : 
     368             : string
     369           0 : MacLearningSandeshResp::GetMacKey() {
     370           0 :     std::stringstream ss;
     371           0 :     ss << partition_id_ << kDelimiter;
     372           0 :     ss << vrf_id_ << kDelimiter;
     373           0 :     ss << mac_.ToString();
     374           0 :     ss << kDelimiter << exact_match_;
     375           0 :     return ss.str();
     376           0 : }
     377             : 
     378             : const MacLearningPartition*
     379           0 : MacLearningSandeshResp::GetPartition() {
     380           0 :     if (partition_id_ >= agent_->params()->mac_learning_thread_count()) {
     381           0 :         return NULL;
     382             :     }
     383             : 
     384           0 :     MacLearningPartition *mp = agent_->mac_learning_proto()->
     385           0 :                                 Find(partition_id_);
     386           0 :     return mp;
     387             : }
     388             : 
     389             : bool
     390           0 : MacLearningSandeshResp::Run() {
     391             :     std::vector<SandeshMacEntry>& list =
     392           0 :         const_cast<std::vector<SandeshMacEntry>&>(resp_->get_mac_entry_list());
     393           0 :     uint32_t entries_count = 0;
     394             : 
     395           0 :     while (entries_count < kMaxResponse) {
     396           0 :         const MacLearningPartition *mp = GetPartition();
     397           0 :         if (mp == NULL) {
     398           0 :             break;
     399             :         }
     400             : 
     401           0 :         MacLearningKey key(vrf_id_, mac_);
     402           0 :         MacLearningPartition::MacLearningEntryTable::const_iterator it;
     403           0 :         if (user_given_mac_ != MacAddress::ZeroMac()) {
     404           0 :             it = mp->mac_learning_table_.find(key);
     405             :         } else {
     406           0 :             it = mp->mac_learning_table_.upper_bound(key);
     407             :         }
     408             : 
     409           0 :         while (entries_count < kMaxResponse) {
     410           0 :             if (exact_match_ && it->first.vrf_id_ != vrf_id_) {
     411           0 :                 break;
     412             :             } else {
     413           0 :                 vrf_id_ = it->first.vrf_id_;
     414             :             }
     415             : 
     416           0 :             if (it == mp->mac_learning_table_.end()) {
     417           0 :                 break;
     418             :             }
     419             : 
     420             :             const MacAgingTable *at =
     421           0 :                 mp->aging_partition()->Find(it->first.vrf_id_);
     422             :             //Find the aging entry
     423           0 :             const MacAgingEntry *aging_entry =  NULL;
     424           0 :             if (at) {
     425           0 :                 aging_entry = at->Find(it->second.get());
     426             :             }
     427           0 :             if (aging_entry) {
     428           0 :                 SandeshMacEntry data;
     429           0 :                 data.set_partition(partition_id_);
     430           0 :                 aging_entry->FillSandesh(&data);
     431           0 :                 list.push_back(data);
     432           0 :             }
     433             : 
     434           0 :             entries_count++;
     435           0 :             if (user_given_mac_ != MacAddress::ZeroMac()) {
     436           0 :                 break;
     437             :             }
     438           0 :             mac_ = it->first.mac_;
     439           0 :             it++;
     440             :         }
     441             : 
     442           0 :         if (entries_count >= kMaxResponse) {
     443           0 :             break;
     444             :         }
     445             : 
     446           0 :         if (exact_match_ == false) {
     447           0 :             vrf_id_++;
     448             :         }
     449             : 
     450           0 :         if (it == mp->mac_learning_table_.end()) {
     451           0 :             partition_id_++;
     452           0 :             if (exact_match_ == false) {
     453           0 :                 vrf_id_ = 0;
     454             :             }
     455             :         }
     456             : 
     457           0 :         if (user_given_mac_ != MacAddress::ZeroMac()) {
     458             :             //If entry is found in current partition
     459             :             //move on to next partition
     460           0 :             if (it != mp->mac_learning_table_.end()) {
     461           0 :                 partition_id_++;
     462             :             }
     463           0 :             mac_ = user_given_mac_;
     464             :         } else {
     465           0 :             mac_ = MacAddress::ZeroMac();
     466             :         }
     467             :     }
     468             : 
     469           0 :     if (partition_id_ < agent_->params()->mac_learning_thread_count()) {
     470           0 :         resp_->set_mac_key(GetMacKey());
     471             :     }
     472             : 
     473           0 :     SendResponse(resp_);
     474           0 :     return true;
     475             : }
     476             : 
     477           0 : void MacLearningSandeshResp::SendResponse(SandeshResponse *resp) {
     478           0 :     resp->set_context(resp_data_);
     479           0 :     resp->set_more(false);
     480           0 :     resp->Response();
     481           0 : }
     482             : 
     483           0 : void FetchMacEntry::HandleRequest() const {
     484           0 :     Agent *agent = Agent::GetInstance();
     485             : 
     486           0 :     std::ostringstream str;
     487           0 :     str << "0" << MacLearningSandeshResp::kDelimiter << get_vrf_id() <<
     488           0 :          MacLearningSandeshResp::kDelimiter << get_mac();
     489             : 
     490           0 :     bool exact_match = false;
     491           0 :     if (get_vrf_id() != 0 || get_mac() != agent->NullString()) {
     492           0 :         exact_match = true;
     493             :     }
     494           0 :     str << MacLearningSandeshResp::kDelimiter << exact_match;
     495             : 
     496           0 :     MacAddress mac = MacAddress::FromString(get_mac());
     497             : 
     498           0 :     MacEntryResp *resp = new MacEntryResp();
     499             :     MacLearningSandeshResp *task = new MacLearningSandeshResp(agent, resp,
     500           0 :                                                         context(),
     501           0 :                                                         str.str(), mac);
     502           0 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     503           0 :     scheduler->Enqueue(task);
     504           0 : }
     505             : 
     506           0 : void NextMacEntrySet::HandleRequest() const {
     507           0 :     Agent *agent = Agent::GetInstance();
     508             : 
     509           0 :     MacEntryResp *resp = new MacEntryResp();
     510             :     MacLearningSandeshResp *task = new MacLearningSandeshResp(agent, resp,
     511           0 :                                                         context(),
     512           0 :                                                         get_mac_entry_key(),
     513           0 :                                                         MacAddress::ZeroMac());
     514           0 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     515           0 :     scheduler->Enqueue(task);
     516           0 : }

Generated by: LCOV version 1.14