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

Generated by: LCOV version 1.14