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

Generated by: LCOV version 1.14