LCOV - code coverage report
Current view: top level - vnsw/agent/mac_learning - mac_ip_learning.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 38 230 16.5 %
Date: 2026-08-03 02:19:58 Functions: 8 23 34.8 %
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_ip_learning_proto_handler.h"
      13             : #include "mac_learning_init.h"
      14             : #include "mac_ip_learning.h"
      15             : #include "mac_learning_mgmt.h"
      16             : #include "mac_learning_event.h"
      17             : 
      18             : 
      19           3 : MacIpLearningTable::MacIpLearningTable(Agent *agent, MacLearningProto *proto) :
      20           3 :     agent_(agent),
      21           3 :     work_queue_(this), macip_map_mutex_() {
      22           3 :     agent->health_check_table()->RegisterHealthCheckNotifyCallback(
      23             :             boost::bind(&MacIpLearningTable::MacIpEntryHcNotify, this, _1));
      24           3 : }
      25             : 
      26           5 : bool MacIpLearningTable::RequestHandler(MacLearningEntryRequestPtr ptr) {
      27           5 :     switch(ptr->event()) {
      28           0 :     case MacLearningEntryRequest::VROUTER_MSG:
      29           0 :         agent()->mac_learning_proto()->ProcessProto(ptr->pkt_info());
      30           0 :         break;
      31             : 
      32           0 :     case MacLearningEntryRequest::ADD_MAC:
      33           0 :         Add(ptr->mac_learning_entry());
      34           0 :         break;
      35             : 
      36           0 :     case MacLearningEntryRequest::RESYNC_MAC:
      37           0 :         Resync(ptr->mac_learning_entry());
      38           0 :         break;
      39             : 
      40           0 :     case MacLearningEntryRequest::DELETE_MAC:
      41           0 :         Delete(ptr->mac_learning_entry());
      42           0 :         break;
      43           5 :     case MacLearningEntryRequest::REMOTE_MAC_IP:
      44           5 :         DetectIpMove(ptr);
      45           5 :         break;
      46             : 
      47           0 :     case MacLearningEntryRequest::MAC_IP_UNREACHABLE:
      48           0 :         MacIpEntryUnreachable(ptr);
      49           0 :         break;
      50             : 
      51           0 :     default:
      52           0 :         assert(0);
      53             :     }
      54           5 :     return true;
      55             : }
      56           0 : void MacIpLearningTable::EnqueueMgmtReq(MacLearningEntryPtr ptr, bool add) {
      57           0 :     MacLearningMgmtRequest::Event e = MacLearningMgmtRequest::ADD_MAC_IP;
      58           0 :     if (add == false) {
      59           0 :         e = MacLearningMgmtRequest::DELETE_MAC_IP;
      60             :     }
      61           0 :     MacLearningMgmtRequestPtr req(new MacLearningMgmtRequest(e, ptr));
      62           0 :     agent()->mac_learning_module()->mac_learning_mgmt()->Enqueue(req);
      63           0 : }
      64           0 : void MacIpLearningTable::Add(MacLearningEntryPtr ptr) {
      65           0 :     MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
      66           0 :     MacIpLearningKey key(entry->vrf_id(), entry->IpAddr());
      67             :     //check whether IP belongs to subnet of VN
      68             :     const VmInterface *vm_intf =
      69           0 :         dynamic_cast<const VmInterface *>(entry->intf());
      70           0 :     if (!vm_intf ||
      71           0 :             !vm_intf->vn()->GetIpam(entry->IpAddr())) {
      72           0 :         MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
      73             :                     entry->IpAddr().to_string(), entry->Mac().ToString(),
      74             :                     entry->intf()->name(),
      75             :                     "ip address does not belong to same subnet, ignoring");
      76           0 :         return;
      77             :     }
      78           0 :     std::scoped_lock lock(macip_map_mutex_);
      79           0 :     MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
      80           0 :     if (it != mac_ip_learning_entry_map_.end()) {
      81             :         MacIpLearningEntry *existing_entry =
      82           0 :             dynamic_cast<MacIpLearningEntry *>(it->second.get());
      83           0 :         if ( existing_entry && existing_entry->Mac() == entry->Mac()) {
      84             :             // ignore duplicate add requests, it is possible that
      85             :             // duplicate requests may come till route processing is done.
      86           0 :             MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
      87             :                     entry->IpAddr().to_string(), entry->Mac().ToString(),
      88             :                     entry->intf()->name(),
      89             :                     "duplicate add request, ingoring");
      90           0 :             return;
      91             :         }
      92           0 :         MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
      93             :                     entry->IpAddr().to_string(), entry->Mac().ToString(),
      94             :                     entry->intf()->name(),
      95             :                     "local IP move detected, delete and add with new mac");
      96             :         //Entry already present, clear the entry
      97           0 :         if (it->second->deleted() == false) {
      98           0 :             it->second->Delete();
      99           0 :             EnqueueMgmtReq(it->second, false);
     100             :         }
     101           0 :         mac_ip_learning_entry_map_[key] = ptr;
     102             :     } else {
     103             :         // check whether mac limit reached for learning new mac-ip
     104             :         // on the interface
     105           0 :         if (vm_intf->IsMaxMacIpLearnt()) {
     106           0 :             MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
     107             :                         entry->IpAddr().to_string(), entry->Mac().ToString(),
     108             :                         entry->intf()->name(),
     109             :                         "max mac ip learnt limit reached on interface");
     110           0 :             return;
     111             :         }
     112             : 
     113           0 :         mac_ip_learning_entry_map_.insert(MacIpLearningEntryPair(key, ptr));
     114             :     }
     115           0 :     ptr->Add();
     116           0 :     EnqueueMgmtReq(ptr, true);
     117           0 : }
     118             : 
     119           0 : void MacIpLearningTable::Delete(const MacLearningEntryPtr ptr) {
     120           0 :     if (ptr->deleted() == true) {
     121           0 :         return;
     122             :     }
     123           0 :     MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
     124           0 :     if (entry == NULL) {
     125           0 :         return;
     126             :     }
     127             : 
     128           0 :     std::scoped_lock lock(macip_map_mutex_);
     129           0 :     MacIpLearningKey key(ptr->vrf_id(), entry->IpAddr());
     130           0 :     if (mac_ip_learning_entry_map_.find(key) == mac_ip_learning_entry_map_.end()) {
     131           0 :         return;
     132             :     }
     133           0 :     MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
     134             :                     entry->IpAddr().to_string(), entry->Mac().ToString(),
     135             :                     entry->intf()->name(), "Delete");
     136             : 
     137           0 :     ptr->Delete();
     138           0 :     mac_ip_learning_entry_map_.erase(key);
     139           0 :     EnqueueMgmtReq(ptr, false);
     140           0 : }
     141             : 
     142           0 : void MacIpLearningTable::Resync(MacLearningEntryPtr ptr) {
     143           0 :     MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
     144           0 :     if (entry == NULL) {
     145           0 :         return;
     146             :     }
     147           0 :     MacIpLearningKey key(ptr->vrf_id(), entry->IpAddr());
     148           0 :     std::scoped_lock lock(macip_map_mutex_);
     149           0 :     if (mac_ip_learning_entry_map_.find(key) == mac_ip_learning_entry_map_.end()) {
     150           0 :         return;
     151             :     }
     152             : 
     153           0 :     MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
     154             :                     entry->IpAddr().to_string(), entry->Mac().ToString(),
     155             :                     entry->intf()->name(), "Resync");
     156           0 :     ptr->Resync();
     157           0 :     EnqueueMgmtReq(ptr, true);
     158           0 : }
     159             : 
     160           5 : void MacIpLearningTable::DetectIpMove(MacLearningEntryRequestPtr ptr) {
     161           5 :     MacIpLearningKey key(ptr->vrf_id(), ptr->ip());
     162           5 :     std::scoped_lock lock(macip_map_mutex_);
     163           5 :     MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
     164           5 :     if (it == mac_ip_learning_entry_map_.end()) {
     165           5 :         return;
     166             :     }
     167           0 :     MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
     168           0 :     if (!mac_ip_entry || mac_ip_entry->Mac() == ptr->mac()) {
     169           0 :         return;
     170             :     }
     171             : 
     172           0 :     VrfEntry *vrf = Agent::GetInstance()->vrf_table()->FindVrfFromId(ptr->vrf_id());
     173           0 :     MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, vrf?vrf->GetName():"NULL",
     174             :                     ptr->ip().to_string(), mac_ip_entry->Mac().ToString(),
     175             :                     mac_ip_entry->intf()->name(),
     176             :                     "IP Move detected, deleting local entry");
     177             : 
     178           0 :     it->second->Delete();
     179           0 :     EnqueueMgmtReq(it->second, false);
     180           0 :     mac_ip_learning_entry_map_.erase(key);
     181           5 : }
     182           0 : void MacIpLearningTable::MacIpEntryUnreachable(uint32_t vrf_id, IpAddress &ip,
     183             :                                                             MacAddress &mac) {
     184             :     MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
     185             :                                    MacLearningEntryRequest::MAC_IP_UNREACHABLE,
     186           0 :                                    vrf_id, ip, mac));
     187           0 :     Enqueue(ptr);
     188           0 : }
     189           0 : void MacIpLearningTable::MacIpEntryHcNotify(
     190             :             const HealthCheckInstanceService *instance_service) {
     191             :     const HealthCheckMacIpInstanceService *mac_ip_instance_service =
     192           0 :         dynamic_cast<const HealthCheckMacIpInstanceService *>(instance_service);
     193           0 :     if (mac_ip_instance_service) {
     194           0 :         IpAddress ip = mac_ip_instance_service->destination_ip();
     195           0 :         MacAddress mac = mac_ip_instance_service->destination_mac();
     196             :         uint32_t vrf_id =
     197           0 :             mac_ip_instance_service->interface()->vrf()->vrf_id();
     198             :         MacLearningEntryRequestPtr ptr(new MacLearningEntryRequest(
     199             :                                    MacLearningEntryRequest::MAC_IP_UNREACHABLE,
     200           0 :                                    vrf_id, ip, mac));
     201           0 :         Enqueue(ptr);
     202           0 :     }
     203           0 : }
     204           0 : void MacIpLearningTable::MacIpEntryUnreachable(MacLearningEntryRequestPtr ptr) {
     205           0 :     MacIpLearningKey key(ptr->vrf_id(), ptr->ip());
     206           0 :     std::scoped_lock lock(macip_map_mutex_);
     207           0 :     MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
     208           0 :     if (it == mac_ip_learning_entry_map_.end()) {
     209           0 :         return;
     210             :     }
     211           0 :     MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
     212           0 :     if (mac_ip_entry->Mac() == ptr->mac()) {
     213           0 :         MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, mac_ip_entry->vrf()->GetName(),
     214             :                     mac_ip_entry->IpAddr().to_string(), mac_ip_entry->Mac().ToString(),
     215             :                     mac_ip_entry->intf()->name(), "MACIP unreachable, trigger delete");
     216           0 :         it->second->Delete();
     217           0 :         EnqueueMgmtReq(it->second, false);
     218           0 :         mac_ip_learning_entry_map_.erase(key);
     219             :     }
     220           0 : }
     221             : 
     222           5 : void MacIpLearningTable::Enqueue(MacLearningEntryRequestPtr req) {
     223           5 :     work_queue_.Enqueue(req);
     224           5 :     return;
     225             : }
     226             : MacIpLearningEntry*
     227          96 : MacIpLearningTable::Find(const MacIpLearningKey &key) {
     228          96 :     std::scoped_lock lock(macip_map_mutex_);
     229          96 :     MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
     230          96 :     if (it == mac_ip_learning_entry_map_.end()) {
     231          96 :         return NULL;
     232             :     }
     233             : 
     234           0 :     MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
     235           0 :     return mac_ip_entry;
     236          96 : }
     237          96 : MacAddress MacIpLearningTable::GetPairedMacAddress(uint32_t vrf_id, const IpAddress& ip) {
     238          96 :     MacIpLearningKey key(vrf_id, ip);
     239          96 :     MacIpLearningEntry *entry = Find(key);
     240          96 :     if (entry) {
     241           0 :         return entry->Mac();
     242             :     }
     243          96 :     return  MacAddress();
     244             : 
     245             : }
     246             : 
     247           0 : MacIpLearningEntry::MacIpLearningEntry(MacIpLearningTable *table,
     248             :                 uint32_t vrf_id, const IpAddress &ip,
     249           0 :                 const MacAddress &mac, InterfaceConstRef intf) :
     250           0 :     MacLearningEntry(vrf_id), mac_ip_learning_table_(table),
     251           0 :     key_(vrf_id, ip), ip_(ip), mac_(mac),
     252           0 :     intf_(intf), vn_(NULL), hc_service_(NULL), hc_instance_(NULL) {
     253           0 :         const VmInterface *vm_port = dynamic_cast<const VmInterface *>(intf_.get());
     254           0 :         assert(vm_port);
     255           0 :         vn_ = vm_port->vn();
     256             : 
     257           0 : }
     258           0 : bool MacIpLearningEntry::Add() {
     259           0 :     VmInterfaceLearntMacIpData *data = new VmInterfaceLearntMacIpData();
     260           0 :     data->is_add = true;
     261           0 :     data->mac_ip_list_.list_.insert(
     262           0 :             VmInterface::LearntMacIp(ip_, mac_));
     263           0 :     DBRequest req;
     264           0 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     265           0 :     req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, intf_->GetUuid(), ""));
     266           0 :     req.data.reset(data);
     267           0 :     mac_ip_learning_table_->agent()->interface_table()->Enqueue(&req);
     268           0 :     UpdateHealthCheckService();
     269           0 :     return 0;
     270           0 : }
     271             : 
     272           0 : void MacIpLearningEntry::Delete() {
     273           0 :     if (hc_instance_ && hc_service_) {
     274           0 :         hc_service_->StopHealthCheckService(hc_instance_);
     275           0 :         hc_instance_ = NULL;
     276           0 :         hc_service_ = NULL;
     277             :     }
     278           0 :     VmInterfaceLearntMacIpData *data = new VmInterfaceLearntMacIpData();
     279           0 :     data->is_add = false;
     280           0 :     data->mac_ip_list_.list_.insert(
     281           0 :             VmInterface::LearntMacIp(ip_, mac_));
     282           0 :     DBRequest req;
     283           0 :     req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     284           0 :     req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, intf_->GetUuid(), ""));
     285           0 :     req.data.reset(data);
     286           0 :     mac_ip_learning_table_->agent()->interface_table()->Enqueue(&req);
     287           0 : }
     288             : 
     289           0 : void MacIpLearningEntry::Resync() {
     290           0 :     UpdateHealthCheckService();
     291           0 : }
     292             : 
     293           0 : void MacIpLearningEntry::EnqueueToTable(MacLearningEntryRequestPtr req) {
     294           0 :         mac_ip_learning_table_->Enqueue(req);
     295           0 : }
     296             : 
     297           0 : void MacIpLearningEntry::UpdateHealthCheckService() {
     298             :     HealthCheckService *hc_service =
     299           0 :         GetHealthCheckService(vn_.get());
     300           0 :     if (hc_service_ != hc_service) {
     301           0 :         if (hc_service_ == NULL) {
     302           0 :             AddHealthCheckService(hc_service);
     303             :         } else {
     304           0 :             if (hc_instance_) {
     305           0 :                 hc_service_->StopHealthCheckService(hc_instance_);
     306             :             }
     307           0 :             hc_instance_ = NULL;
     308           0 :             hc_service_= NULL;
     309           0 :             if (hc_service) {
     310           0 :                 AddHealthCheckService(hc_service);
     311             :             }
     312             :         }
     313           0 :     } else if (hc_service_) {
     314           0 :         hc_instance_->UpdateInstanceTask();
     315             :     }
     316           0 : }
     317           0 : void MacIpLearningEntry::AddHealthCheckService(HealthCheckService *service) {
     318           0 :     if (service) {
     319           0 :         hc_service_ = service;
     320           0 :         IpAddress gateway_ip = vn_->GetGatewayFromIpam(ip_);
     321           0 :         const VmInterface *vm_intf = static_cast< const VmInterface *>(intf_.get());
     322             :         //TODO: add validation check for null gateway ip
     323           0 :         hc_instance_ = service->StartHealthCheckService(
     324             :                    const_cast< VmInterface *>(vm_intf), NULL,
     325           0 :                    gateway_ip, ip_, mac_, false, false);
     326           0 :         hc_instance_->set_service(hc_service_);
     327             :     }
     328           0 : }
     329             : 
     330           0 : HealthCheckService* MacIpLearningEntry::GetHealthCheckService(const VnEntry *vn) {
     331             :     //1. check if hc is attached
     332           0 :     const boost::uuids::uuid hc_uuid = vn->health_check_uuid();
     333           0 :     if (hc_uuid == boost::uuids::nil_uuid()) {
     334           0 :         return NULL;
     335             :     }
     336             :     HealthCheckService *hc_service = Agent::GetInstance()->
     337           0 :         health_check_table()->Find(hc_uuid);
     338             :     //2. if attached , check whether target ip present in tragte ip list
     339           0 :     if (!hc_service) {
     340           0 :         return NULL;
     341             :     }
     342           0 :     if (hc_service->IsTargetIpPresent(IpAddr())) {
     343           0 :             return hc_service;
     344             :     }
     345             : 
     346           0 :     return NULL;
     347             : }
     348           3 : MacIpLearningRequestQueue::MacIpLearningRequestQueue(MacIpLearningTable *table):
     349           3 :     table_(table),
     350           3 :     queue_(table_->agent()->task_scheduler()->GetTaskId(kTaskMacLearning),
     351             :             0,
     352             :             boost::bind(&MacIpLearningRequestQueue::HandleEvent,this,_1)) {
     353           3 : }
     354             : 
     355           5 : bool MacIpLearningRequestQueue::HandleEvent(MacLearningEntryRequestPtr ptr) {
     356           5 :     return table_->RequestHandler(ptr);
     357             : }

Generated by: LCOV version 1.14