LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/gmp_map - gmp_proto.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 161 515 31.3 %
Date: 2026-08-03 02:19:58 Functions: 18 36 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "cmn/agent_cmn.h"
       6             : #include <init/agent_param.h>
       7             : #include "oper/route_common.h"
       8             : #include "oper/multicast.h"
       9             : #include "oper/multicast_policy.h"
      10             : #include "oper/nexthop.h"
      11             : 
      12             : #ifdef __cplusplus
      13             : extern "C" {
      14             : #endif
      15             : #include "mcast_common.h"
      16             : #include "gmpx_basic_types.h"
      17             : #include "gmp.h"
      18             : #include "gmpx_environment.h"
      19             : #include "gmp_intf.h"
      20             : #include "gmp_map.h"
      21             : #ifdef __cplusplus
      22             : }
      23             : #endif
      24             : 
      25             : #include "task_map.h"
      26             : #include "gmp_proto.h"
      27             : 
      28             : extern SandeshTraceBufferPtr MulticastTraceBuf;
      29             : 
      30           3 : GmpIntf::GmpIntf(const GmpProto *gmp_proto) : gmp_proto_(gmp_proto),
      31           3 :                                     vrf_name_(), ip_addr_() {
      32             : 
      33           3 :     gif_ = NULL;
      34           3 :     querying_ = false;
      35           3 : }
      36             : 
      37             : // GmpIntf is local to Agent IGMP implementation and is not known
      38             : // by core IGMP module.
      39             : // IP address change to be reflected in GMP interface also.
      40           6 : bool GmpIntf::set_ip_address(const IpAddress &addr) {
      41             : 
      42           6 :     if (ip_addr_ != addr) {
      43           6 :         ip_addr_ = addr;
      44             : 
      45           6 :         uint32_t intf_addr = htonl(ip_addr_.to_v4().to_ulong());
      46             :         gmp_addr_string gmp_addr;
      47           6 :         memcpy(&gmp_addr, &intf_addr, IPV4_ADDR_LEN);
      48           6 :         gmp_update_intf_state(gmp_proto_->gd_, gif_,
      49           6 :                                     addr != IpAddress() ?
      50             :                                     (const gmp_addr_string *)&intf_addr : NULL);
      51           6 :         return true;
      52             :     }
      53             : 
      54           0 :     return false;
      55             : }
      56             : 
      57             : // Update the new VRF name for GmpIntf.
      58           6 : bool GmpIntf::set_vrf_name(const string &vrf_name) {
      59           6 :     vrf_name_ = vrf_name;
      60           6 :     return true;
      61             : }
      62             : 
      63             : // Change of querying mode per-GmpIntf.
      64           0 : bool GmpIntf::set_gmp_querying(bool querying) {
      65             : 
      66           0 :     if (querying_ != querying) {
      67           0 :         querying_ = querying;
      68           0 :         boolean ret = gmp_update_intf_querying(gmp_proto_->gd_, gif_,
      69             :                                 querying ? TRUE : FALSE);
      70           0 :         return ret ? true : false;
      71             :     }
      72             : 
      73           0 :     return true;
      74             : }
      75             : 
      76           1 : GmpProto::GmpProto(GmpType::Type type, Agent *agent,
      77             :                             const std::string &task_name, int instance,
      78           1 :                             boost::asio::io_context &io) :
      79           1 :     type_(type), agent_(agent), name_(task_name), instance_(instance), io_(io) {
      80             : 
      81           1 :     task_map_ = NULL;
      82           1 :     gmp_trigger_timer_ = NULL;
      83           1 :     gmp_notif_trigger_ = NULL;
      84           1 :     gd_ = NULL;
      85           1 :     cb_ = NULL;
      86             : 
      87           1 :     stats_.gmp_g_add_count_ = 0;
      88           1 :     stats_.gmp_g_del_count_ = 0;
      89             : 
      90           1 :     stats_.gmp_sg_add_count_ = 0;
      91           1 :     stats_.gmp_sg_del_count_ = 0;
      92           1 : }
      93             : 
      94           1 : GmpProto::~GmpProto() {
      95           1 : }
      96             : 
      97             : // Start the GmpProto that represents the agent's IGMP functionality.
      98           1 : bool GmpProto::Start() {
      99             : 
     100           1 :     if (type_ != GmpType::IGMP) {
     101           0 :         return false;
     102             :     }
     103             : 
     104           1 :     task_map_ = TaskMapManager::CreateTaskMap(agent_, name_, instance_, io_);
     105           1 :     if (!task_map_) {
     106           0 :         return false;
     107             :     }
     108             : 
     109             :     // TaskTrigger instance for handling GMP notifications like join, leave
     110             :     // per-<S,G> and per-host as required.
     111           2 :     gmp_notif_trigger_ = new TaskTrigger(
     112             :                             boost::bind(&GmpProto::GmpNotificationHandler,this),
     113           1 :                             TaskScheduler::GetInstance()->GetTaskId(name_),
     114           1 :                             instance_);
     115             : 
     116           1 :     gd_ = gmp_init(MCAST_AF_IPV4, (task *)task_map_->task_, this);
     117           1 :     if (!gd_) {
     118           0 :         if (task_map_) TaskMapManager::DeleteTaskMap(task_map_);
     119           0 :         task_map_ = NULL;
     120             : 
     121           0 :         if (gmp_notif_trigger_) {
     122           0 :             gmp_notif_trigger_->Reset();
     123           0 :             delete gmp_notif_trigger_;
     124             :         }
     125           0 :         gmp_notif_trigger_ = NULL;
     126             : 
     127           0 :         return false;
     128             :     }
     129             : 
     130           1 :     vn_listener_id_ = agent_->vn_table()->Register(
     131             :             boost::bind(&GmpProto::GmpVnNotify, this, _1, _2));
     132           1 :     itf_listener_id_ = agent_->interface_table()->Register(
     133             :             boost::bind(&GmpProto::GmpItfNotify, this, _1, _2));
     134             : 
     135           1 :     return true;
     136             : }
     137             : 
     138             : // Stop the GmpProto that represents the agent's IGMP functionality.
     139           1 : bool GmpProto::Stop() {
     140             : 
     141           1 :     if (!gd_) {
     142           0 :         return true;
     143             :     }
     144             : 
     145           1 :     agent_->interface_table()->Unregister(itf_listener_id_);
     146           1 :     agent_->vn_table()->Unregister(vn_listener_id_);
     147             : 
     148           1 :     gmp_deinit(MCAST_AF_IPV4);
     149           1 :     gd_ = NULL;
     150             : 
     151           1 :     if (gmp_trigger_timer_) {
     152           0 :         gmp_trigger_timer_->Cancel();
     153           0 :         TimerManager::DeleteTimer(gmp_trigger_timer_);
     154           0 :         gmp_trigger_timer_ = NULL;
     155             :     }
     156             : 
     157           1 :     gmp_notif_trigger_->Reset();
     158           1 :     delete gmp_notif_trigger_;
     159           1 :     gmp_notif_trigger_ = NULL;
     160             : 
     161           1 :     TaskMapManager::DeleteTaskMap(task_map_);
     162           1 :     task_map_ = NULL;
     163             : 
     164           1 :     return true;
     165             : }
     166             : 
     167             : // Cleans up <S,G> per-GmpIntf. Also cleans up VMIs per-<S,G> from NH.
     168           3 : void GmpProto::GmpIntfSGClear(VnGmpDBState *state,
     169             :                             VnGmpDBState::VnGmpIntfState *gmp_intf_state) {
     170             : 
     171           3 :     MulticastHandler *m_handler = agent_->oper_db()->multicast();
     172             : 
     173           3 :     GmpSourceGroup *gmp_sg = NULL;
     174           3 :     std::set<GmpSourceGroup *> sg_to_delete;
     175             :     VnGmpDBState::VnGmpSGIntfListIter gif_sg_it =
     176           3 :                             gmp_intf_state->gmp_intf_sg_list_.begin();
     177           3 :     for (; gif_sg_it != gmp_intf_state->gmp_intf_sg_list_.end(); ++gif_sg_it) {
     178             : 
     179           0 :         gmp_sg = *gif_sg_it;
     180             : 
     181           0 :         MCTRACE(LogSG, "Delete Mcast VRF SG for VN ",
     182             :                             gmp_intf_state->gmp_intf_->get_vrf_name(),
     183             :                             gmp_sg->source_.to_v4().to_string(),
     184             :                             gmp_sg->group_.to_v4().to_string(), 0);
     185             : 
     186           0 :         gmp_sg->refcount_--;
     187           0 :         sg_to_delete.insert(gmp_sg);
     188           0 :         if (gmp_sg->refcount_ == 0) {
     189           0 :             state->gmp_sg_list_.erase(gmp_sg);
     190             :             // Delete VMIs from multicast list for the <S,G>
     191           0 :             m_handler->DeleteMulticastVrfSourceGroup(
     192           0 :                             gmp_intf_state->gmp_intf_->get_vrf_name(),
     193           0 :                             gmp_sg->source_.to_v4(), gmp_sg->group_.to_v4());
     194             :         }
     195             :     }
     196             : 
     197           3 :     for(std::set<GmpSourceGroup *>::iterator sg_it = sg_to_delete.begin();
     198           3 :         sg_it != sg_to_delete.end(); sg_it++) {
     199           0 :         gmp_sg = *sg_it;
     200           0 :         gmp_intf_state->gmp_intf_sg_list_.erase(gmp_sg);
     201           0 :         if (gmp_sg->refcount_ == 0) {
     202           0 :             delete gmp_sg;
     203             :         }
     204             :     }
     205             : 
     206           6 :     return;
     207           3 : }
     208             : 
     209             : // Handle VN change notification, specifically IPAM changes
     210          19 : void GmpProto::GmpVnNotify(DBTablePartBase *part, DBEntryBase *entry) {
     211             : 
     212             :     // Registering/Unregistering every IPAM gateway (or) dns_server
     213             :     // present in the VN with the IGMP module.
     214             :     // Changes to VN, or VN IPAM info, or gateway or dns server is
     215             :     // handled below.
     216             : 
     217          19 :     VnEntry *vn = static_cast<VnEntry *>(entry);
     218             : 
     219             :     VnGmpDBState *state = static_cast<VnGmpDBState *>
     220          19 :                         (entry->GetState(part->parent(), vn_listener_id_));
     221             :     VnGmpDBState::VnGmpIntfState *gmp_intf_state;
     222             : 
     223          19 :     if (vn->IsDeleted() || !vn->GetVrf()) {
     224          16 :         if (!state) {
     225          10 :             return;
     226             :         }
     227           6 :         VnGmpDBState::VnGmpIntfMap::iterator it = state->gmp_intf_map_.begin();
     228           9 :         for (;it != state->gmp_intf_map_.end(); ++it) {
     229           3 :             gmp_intf_state = it->second;
     230           3 :             GmpIntfSGClear(state, gmp_intf_state);
     231             :             // Cleanup the GMP database and timers
     232           3 :             gmp_intf_state->gmp_intf_->set_vrf_name(string());
     233           3 :             gmp_intf_state->gmp_intf_->set_ip_address(IpAddress(Ip4Address()));
     234           3 :             DeleteIntf(gmp_intf_state->gmp_intf_);
     235           3 :             delete gmp_intf_state;
     236           3 :             itf_attach_count_--;
     237             :         }
     238           6 :         state->gmp_intf_map_.clear();
     239             : 
     240           6 :         if (vn->IsDeleted()) {
     241           3 :             entry->ClearState(part->parent(), vn_listener_id_);
     242           3 :             delete state;
     243             :         }
     244           6 :         return;
     245             :     }
     246             : 
     247           3 :     if (!vn->GetVrf()) {
     248           0 :         return;
     249             :     }
     250             : 
     251           6 :     if ((vn->GetVrf()->GetName() == agent_->fabric_policy_vrf_name()) ||
     252           3 :         (vn->GetVrf()->GetName() == agent_->fabric_vrf_name())) {
     253           0 :         return;
     254             :     }
     255             : 
     256           3 :     if (state == NULL) {
     257           3 :         state = new VnGmpDBState();
     258             : 
     259           3 :         entry->SetState(part->parent(), vn_listener_id_, state);
     260             :     }
     261             : 
     262           3 :     VnGmpDBState::VnGmpIntfMap::iterator it = state->gmp_intf_map_.begin();
     263           3 :     while (it != state->gmp_intf_map_.end()) {
     264           0 :         const VnIpam *ipam = vn->GetIpam(it->first);
     265           0 :         if ((ipam != NULL) && ((ipam->default_gw == it->first) ||
     266           0 :                 (ipam->dns_server == it->first))) {
     267           0 :             it++;
     268           0 :             continue;
     269             :         }
     270           0 :         gmp_intf_state = it->second;
     271           0 :         GmpIntfSGClear(state, gmp_intf_state);
     272             :         // Cleanup the GMP database and timers
     273           0 :         gmp_intf_state->gmp_intf_->set_vrf_name(string());
     274           0 :         gmp_intf_state->gmp_intf_->set_ip_address(IpAddress(Ip4Address()));
     275           0 :         DeleteIntf(gmp_intf_state->gmp_intf_);
     276           0 :         delete gmp_intf_state;
     277           0 :         itf_attach_count_--;
     278           0 :         state->gmp_intf_map_.erase(it++);
     279             :     }
     280             : 
     281           3 :     const std::vector<VnIpam> &ipam = vn->GetVnIpam();
     282           6 :     for (unsigned int i = 0; i < ipam.size(); ++i) {
     283           3 :         if (!ipam[i].IsV4()) {
     284           0 :             continue;
     285             :         }
     286           3 :         if ((ipam[i].default_gw == IpAddress(Ip4Address())) &&
     287           3 :             (ipam[i].dns_server == IpAddress(Ip4Address()))) {
     288           0 :             continue;
     289             :         }
     290             : 
     291           3 :         IpAddress gmp_address = IpAddress(Ip4Address());
     292           3 :         VnGmpDBState::VnGmpIntfMap::const_iterator it;
     293             : 
     294           3 :         if (ipam[i].dns_server != IpAddress(Ip4Address())) {
     295           3 :             it = state->gmp_intf_map_.find(ipam[i].dns_server);
     296           3 :             gmp_address = ipam[i].dns_server;
     297             :         }
     298           3 :         if (ipam[i].default_gw != IpAddress(Ip4Address())) {
     299           3 :             if ((it != state->gmp_intf_map_.end()) &&
     300           0 :                 (ipam[i].default_gw != ipam[i].dns_server)) {
     301           0 :                 gmp_intf_state = it->second;
     302           0 :                 GmpIntfSGClear(state, gmp_intf_state);
     303             :                 // Cleanup the GMP database and timers
     304           0 :                 gmp_intf_state->gmp_intf_->set_vrf_name(string());
     305           0 :                 gmp_intf_state->gmp_intf_->set_ip_address(IpAddress(Ip4Address()));
     306           0 :                 DeleteIntf(gmp_intf_state->gmp_intf_);
     307           0 :                 itf_attach_count_--;
     308           0 :                 delete gmp_intf_state;
     309           0 :                 state->gmp_intf_map_.erase(it->first);
     310             :             }
     311             : 
     312           3 :             gmp_address = ipam[i].default_gw;
     313             :         }
     314             : 
     315           3 :         it = state->gmp_intf_map_.find(gmp_address);
     316           3 :         if (it == state->gmp_intf_map_.end()) {
     317           3 :             gmp_intf_state = new VnGmpDBState::VnGmpIntfState();
     318           3 :             gmp_intf_state->gmp_intf_ = CreateIntf();
     319           3 :             itf_attach_count_++;
     320           3 :             state->gmp_intf_map_.insert(
     321           6 :                             std::pair<IpAddress,VnGmpDBState::VnGmpIntfState*>
     322             :                             (gmp_address, gmp_intf_state));
     323             :         } else {
     324           0 :             gmp_intf_state = it->second;
     325             :         }
     326           3 :         if (gmp_intf_state) {
     327           3 :             gmp_intf_state->gmp_intf_->set_ip_address(gmp_address);
     328           3 :             if (vn->GetVrf()) {
     329           3 :                 gmp_intf_state->gmp_intf_->set_vrf_name(vn->GetVrf()->GetName());
     330             :             }
     331             :         }
     332             :     }
     333             : }
     334             : 
     335             : // Handle Interface notification, specifically VMI delete notification
     336             : // Clean up VMI from NH for the <S,G>s on VMI delete
     337          82 : void GmpProto::GmpItfNotify(DBTablePartBase *part, DBEntryBase *entry) {
     338             : 
     339          82 :     Interface *itf = static_cast<Interface *>(entry);
     340          82 :     if (itf->type() != Interface::VM_INTERFACE) {
     341          15 :         return;
     342             :     }
     343             : 
     344          67 :     VmInterface *vm_itf = static_cast<VmInterface *>(itf);
     345          67 :     if (vm_itf->vmi_type() == VmInterface::VHOST) {
     346           1 :         return;
     347             :     }
     348             : 
     349             :     VmiGmpDBState *vmi_state = static_cast<VmiGmpDBState *>
     350          66 :                         (entry->GetState(part->parent(), itf_listener_id_));
     351             : 
     352          66 :     if (itf->IsDeleted() || !vm_itf->igmp_enabled()) {
     353          66 :         if (!vmi_state) {
     354          66 :             MCTRACE(IgmpIntf, "Itf Notify, no VMI state ",
     355             :                             "no-vrf", vm_itf->primary_ip_addr().to_string(),
     356             :                             vm_itf->igmp_enabled());
     357          66 :             return;
     358             :         }
     359             : 
     360           0 :         MCTRACE(IgmpIntf, "Itf Notify, VMI delete or IGMP disable ",
     361             :                             vmi_state->vrf_name_,
     362             :                             vm_itf->primary_ip_addr().to_string(),
     363             :                             vm_itf->igmp_enabled());
     364           0 :         if (agent_->oper_db()->multicast()) {
     365           0 :             agent_->oper_db()->multicast()->DeleteVmInterfaceFromVrfSourceGroup(
     366           0 :                                     vmi_state->vrf_name_, vm_itf);
     367             :         }
     368           0 :         if (itf->IsDeleted()) {
     369           0 :             vm_ip_to_vmi_.erase(vmi_state->vmi_v4_addr_);
     370           0 :             entry->ClearState(part->parent(), itf_listener_id_);
     371           0 :             delete vmi_state;
     372             :         }
     373           0 :         return;
     374             :     }
     375             : 
     376           0 :     MCTRACE(IgmpIntf, "Itf Notify, VMI create or IGMP enable",
     377             :                             vm_itf->vrf() ? vm_itf->vrf()->GetName() : "",
     378             :                             vm_itf->primary_ip_addr().to_string(),
     379             :                             vm_itf->igmp_enabled());
     380           0 :     if (vmi_state == NULL) {
     381           0 :         vmi_state = new VmiGmpDBState();
     382           0 :         entry->SetState(part->parent(), itf_listener_id_, vmi_state);
     383             :     }
     384             : 
     385           0 :     if (vm_itf->vrf()) {
     386           0 :         if (vmi_state->vrf_name_ != vm_itf->vrf()->GetName()) {
     387           0 :             if (agent_->oper_db()->multicast()) {
     388           0 :                 agent_->oper_db()->multicast()->
     389           0 :                             DeleteVmInterfaceFromVrfSourceGroup(
     390           0 :                                     vmi_state->vrf_name_, vm_itf);
     391             :             }
     392             : 
     393           0 :             vmi_state->vrf_name_ = vm_itf->vrf()->GetName();
     394             :         }
     395             :     }
     396             : 
     397           0 :     if (vmi_state->vmi_v4_addr_ != vm_itf->primary_ip_addr()) {
     398             : 
     399           0 :         if (vm_ip_to_vmi_.find(vmi_state->vmi_v4_addr_) !=
     400           0 :                                     vm_ip_to_vmi_.end()) {
     401           0 :             if (agent_->oper_db()->multicast()) {
     402           0 :                 agent_->oper_db()->multicast()->
     403           0 :                             DeleteVmInterfaceFromVrfSourceGroup(
     404           0 :                                     vmi_state->vrf_name_, vm_itf);
     405             :             }
     406             : 
     407           0 :             vm_ip_to_vmi_.erase(vmi_state->vmi_v4_addr_);
     408             :         }
     409             : 
     410           0 :         vmi_state->vmi_v4_addr_ = vm_itf->primary_ip_addr();
     411           0 :         vm_ip_to_vmi_.insert(std::pair<IpAddress,boost::uuids::uuid>
     412           0 :                                         (vmi_state->vmi_v4_addr_,
     413             :                                          vm_itf->GetUuid()));
     414             :     }
     415             : 
     416           0 :     return;
     417             : }
     418             : 
     419             : // Create a GmpIntf. Represents per-IPAM entry.
     420           3 : GmpIntf *GmpProto::CreateIntf() {
     421             : 
     422           3 :     GmpIntf *gmp_intf = new GmpIntf(this);
     423             : 
     424           3 :     gmp_intf->SetGif(gmp_attach_intf(gd_, gmp_intf));
     425           3 :     if (!gmp_intf->GetGif()) {
     426           0 :         delete gmp_intf;
     427           0 :         return NULL;
     428             :     }
     429             : 
     430           3 :     return gmp_intf;
     431             : }
     432             : 
     433             : // Delete a GmpIntf.
     434           3 : bool GmpProto::DeleteIntf(GmpIntf *gif) {
     435             : 
     436           3 :     gmp_detach_intf(gd_, gif->GetGif());
     437           3 :     delete gif;
     438             : 
     439           3 :     return true;
     440             : }
     441             : 
     442             : // Pass the IP header processed IGMP packet to the GMP
     443           0 : bool GmpProto::GmpProcessPkt(const VmInterface *vm_itf,
     444             :                         void *rcv_pkt, uint32_t packet_len,
     445             :                         IpAddress ip_saddr, IpAddress ip_daddr) {
     446             : 
     447             :     uint32_t addr;
     448             :     gmp_addr_string src_addr, dst_addr;
     449             : 
     450           0 :     const VnEntry *vn = vm_itf->vn();
     451           0 :     VnGmpDBState *state = NULL;
     452           0 :     state = static_cast<VnGmpDBState *>(vn->GetState(
     453             :                                 vn->get_table_partition()->parent(),
     454             :                                 vn_listener_id_));
     455           0 :     if (!state) {
     456           0 :         return false;
     457             :     }
     458             : 
     459           0 :     const VnIpam *ipam = vn->GetIpam(ip_saddr);
     460             :     VnGmpDBState::VnGmpIntfMap::const_iterator it =
     461           0 :                             state->gmp_intf_map_.find(ipam->default_gw);
     462           0 :     if (it == state->gmp_intf_map_.end()) {
     463           0 :         it = state->gmp_intf_map_.find(ipam->dns_server);
     464             :     }
     465           0 :     if (it == state->gmp_intf_map_.end()) {
     466           0 :         return false;
     467             :     }
     468             : 
     469           0 :     VnGmpDBState::VnGmpIntfState *gmp_intf_state = it->second;
     470           0 :     GmpIntf *gmp_intf = gmp_intf_state->gmp_intf_;
     471             : 
     472           0 :     addr = htonl(ip_saddr.to_v4().to_ulong());
     473           0 :     memcpy(&src_addr, &addr, IPV4_ADDR_LEN);
     474           0 :     addr = htonl(ip_daddr.to_v4().to_ulong());
     475           0 :     memcpy(&dst_addr, &addr, IPV4_ADDR_LEN);
     476             : 
     477           0 :     boolean ret = gmp_process_pkt(gd_, gmp_intf->GetGif(), rcv_pkt,
     478             :                         packet_len, &src_addr, &dst_addr);
     479             : 
     480           0 :     return ret ? true : false;
     481             : }
     482             : 
     483           3 : uint8_t *GmpProto::GmpBufferGet() {
     484           3 :     return new uint8_t[GMP_TX_BUFF_LEN];
     485             : }
     486             : 
     487           3 : void GmpProto::GmpBufferFree(uint8_t *pkt) {
     488           3 :     delete [] pkt;
     489           3 : }
     490             : 
     491             : // TaskTrigger handler for IGMP notifications like join, leave.
     492           0 : bool GmpProto::GmpNotificationHandler() {
     493             : 
     494           0 :     boolean pending = FALSE;
     495             : 
     496           0 :     pending = gmp_notification_handler(gd_);
     497             : 
     498           0 :     if ((pending == TRUE) && gmp_notif_trigger_) {
     499           0 :         gmp_trigger_timer_ = TimerManager::CreateTimer(io_, "GMP Trigger Timer",
     500             :                             TaskScheduler::GetInstance()->GetTaskId(name_),
     501             :                             instance_, true);
     502             : 
     503           0 :         gmp_trigger_timer_->Start(kGmpTriggerRestartTimer,
     504             :                             boost::bind(&GmpProto::GmpNotificationTimer, this));
     505             :     }
     506             : 
     507           0 :     return true;
     508             : }
     509             : 
     510             : // Timer instance to handle pending notifications not handled in previous run
     511           0 : bool GmpProto::GmpNotificationTimer() {
     512             : 
     513           0 :     if (gmp_notif_trigger_ && !gmp_notif_trigger_->IsSet()) {
     514           0 :         gmp_notif_trigger_->Set();
     515             :     }
     516             : 
     517           0 :     gmp_trigger_timer_ = NULL;
     518             : 
     519           0 :     return false;
     520             : }
     521             : 
     522             : // Handler registered with GMP to take care of per-<S,G> and also
     523             : // per-host, per-<S,G> notifications. TaskTriggers instance created
     524             : // above is triggered to further handle the notifications
     525           0 : void GmpProto::GmpNotificationReady() {
     526             : 
     527           0 :     if (!gmp_notif_trigger_ || gmp_notif_trigger_->IsSet()) {
     528           0 :         return;
     529             :     }
     530             : 
     531           0 :     gmp_notif_trigger_->Set();
     532             : 
     533           0 :     return;
     534             : }
     535             : 
     536             : // <S,G>, including <*,G> notification handling
     537           0 : void GmpProto::GroupNotify(GmpIntf *gif, IpAddress source, IpAddress group,
     538             :                             int group_action) {
     539             : 
     540           0 :     if (agent_->params()->mvpn_ipv4_enable()) {
     541           0 :         return;
     542             :     }
     543             : 
     544             :     // Support for EVPN <*,G> only.
     545           0 :     if (!gif) {
     546           0 :         return;
     547             :     }
     548             : 
     549           0 :     VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(gif->get_vrf_name());
     550             :     VnEntry *vn;
     551           0 :     if (vrf) {
     552           0 :         vn = vrf->vn();
     553             :     }
     554           0 :     if (!vrf || !vn) {
     555           0 :         return;
     556             :     }
     557             : 
     558           0 :     VnGmpDBState *state = NULL;
     559           0 :     state = static_cast<VnGmpDBState *>(vn->GetState(
     560             :                                 vn->get_table_partition()->parent(),
     561             :                                 vn_listener_id_));
     562           0 :     if (!state) {
     563           0 :         return;
     564             :     }
     565             : 
     566           0 :     VnGmpDBState::VnGmpIntfMap::iterator gif_it = state->gmp_intf_map_.begin();
     567           0 :     VnGmpDBState::VnGmpIntfState *gmp_intf_state = NULL;
     568           0 :     while (gif_it != state->gmp_intf_map_.end()) {
     569           0 :         gmp_intf_state = gif_it->second;
     570           0 :         if (gmp_intf_state->gmp_intf_ == gif) {
     571           0 :             break;
     572             :         }
     573           0 :         gif_it++;
     574             :     }
     575             : 
     576           0 :     if (gif_it == state->gmp_intf_map_.end()) {
     577           0 :         return;
     578             :     }
     579             : 
     580           0 :     GmpSourceGroup *gmp_sg = NULL;
     581           0 :     VnGmpDBState::VnGmpSGListIter sg_it = state->gmp_sg_list_.begin();
     582           0 :     for (;sg_it != state->gmp_sg_list_.end(); ++sg_it) {
     583           0 :         gmp_sg = *sg_it;
     584           0 :         if ((gmp_sg->source_ == source) || (gmp_sg->group_ == group)) {
     585           0 :             break;
     586             :         }
     587             :     }
     588             : 
     589           0 :     if (sg_it == state->gmp_sg_list_.end()) {
     590           0 :         if (group_action == MGM_GROUP_REMOVED ||
     591             :             group_action == MGM_GROUP_SRC_REMOVED) {
     592             : 
     593           0 :             return;
     594             :         }
     595             :     }
     596             : 
     597           0 :     bool created = false;
     598           0 :     if (!gmp_sg) {
     599           0 :         gmp_sg = new GmpSourceGroup();
     600           0 :         gmp_sg->source_ = source;
     601           0 :         gmp_sg->group_ = group;
     602           0 :         gmp_sg->flags_ = GmpSourceGroup::IGMP_VERSION_V1 |
     603             :                             GmpSourceGroup::IGMP_VERSION_V2;
     604           0 :         created = true;
     605           0 :         state->gmp_sg_list_.insert(gmp_sg);
     606             :     }
     607             : 
     608             :     VnGmpDBState::VnGmpSGIntfListIter gif_sg_it =
     609           0 :                             gmp_intf_state->gmp_intf_sg_list_.begin();
     610             : 
     611           0 :     MulticastHandler *m_handler = agent_->oper_db()->multicast();
     612           0 :     if (group_action == MGM_GROUP_ADDED) {
     613           0 :         gif_sg_it = gmp_intf_state->gmp_intf_sg_list_.find(gmp_sg);
     614           0 :         if (gif_sg_it == gmp_intf_state->gmp_intf_sg_list_.end()) {
     615           0 :             gmp_intf_state->gmp_intf_sg_list_.insert(gmp_sg);
     616           0 :             gmp_sg->refcount_++;
     617             :         }
     618           0 :         if (created) {
     619           0 :             MCTRACE(LogSG, "Create Mcast VRF SG ", vrf->GetName(),
     620             :                             source.to_string(), group.to_string(), 0);
     621           0 :             m_handler->CreateMulticastVrfSourceGroup(vrf->GetName(),
     622           0 :                             vn->GetName(), source.to_v4(), group.to_v4());
     623           0 :             m_handler->SetEvpnMulticastSGFlags(vrf->GetName(),
     624           0 :                             source.to_v4(), group.to_v4(), gmp_sg->flags_);
     625             :         }
     626             :     }
     627             : 
     628           0 :     if (group_action == MGM_GROUP_REMOVED ||
     629             :         group_action == MGM_GROUP_SRC_REMOVED) {
     630             : 
     631           0 :         gif_sg_it = gmp_intf_state->gmp_intf_sg_list_.find(gmp_sg);
     632           0 :         if (gif_sg_it != gmp_intf_state->gmp_intf_sg_list_.end()) {
     633           0 :             gmp_sg->refcount_--;
     634           0 :             gmp_intf_state->gmp_intf_sg_list_.erase(gmp_sg);
     635           0 :             if (gmp_sg->refcount_ == 0) {
     636           0 :                 state->gmp_sg_list_.erase(gmp_sg);
     637           0 :                 MCTRACE(LogSG, "Delete Mcast VRF SG ", vrf->GetName(),
     638             :                             source.to_string(), group.to_string(), 0);
     639           0 :                 m_handler->DeleteMulticastVrfSourceGroup(vrf->GetName(),
     640           0 :                             source.to_v4(), group.to_v4());
     641           0 :                 delete gmp_sg;
     642             :             }
     643             :         }
     644             :     }
     645             : 
     646           0 :     return;
     647             : }
     648             : 
     649           0 : void GmpProto::ResyncNotify(GmpIntf *gif, IpAddress source, IpAddress group) {
     650             : 
     651           0 :     return;
     652             : }
     653             : 
     654             : // Per-host, per-<S,G> handling. For now, only per-host, per-<*,G> handling
     655           0 : void GmpProto::UpdateHostInSourceGroup(GmpIntf *gif, bool join, IpAddress host,
     656             :                                     IpAddress source, IpAddress group) {
     657             : 
     658           0 :     if (!agent_->oper_db()->multicast()) {
     659           0 :         return;
     660             :     }
     661             : 
     662           0 :     if (!host.is_v4()) {
     663           0 :         return;
     664             :     }
     665             : 
     666           0 :     if (source.to_v4() == Ip4Address()) {
     667           0 :         join ? stats_.gmp_g_add_count_++ : stats_.gmp_g_del_count_++;
     668             :     } else {
     669           0 :         join ? stats_.gmp_sg_add_count_++ : stats_.gmp_sg_del_count_++;
     670             :     }
     671             : 
     672           0 :     if (vm_ip_to_vmi_.find(host) == vm_ip_to_vmi_.end()) {
     673           0 :         MCTRACE(Info, "igmp_trace: No host found", host.to_string());
     674           0 :         return;
     675             :     }
     676             : 
     677           0 :     boost::uuids::uuid vmi_uuid = vm_ip_to_vmi_[host];
     678           0 :     InterfaceConstRef intf_ref = agent_->interface_table()->FindVmi(vmi_uuid);
     679           0 :     const VmInterface *vm_intf = static_cast<const VmInterface *>(intf_ref.get());
     680           0 :     if (!vm_intf) {
     681           0 :         MCTRACE(Info, "igmp_trace: No VM Interface for host", host.to_string());
     682           0 :         return;
     683             :     }
     684             : 
     685           0 :     if (agent_->params()->mvpn_ipv4_enable()) {
     686             :         // Support for MVPN <S,G> only.
     687           0 :         TriggerMvpnNotification(vm_intf, join, source, group);
     688             :     } else {
     689             :         // Support for EVPN <*,G> only.
     690           0 :         TriggerEvpnNotification(vm_intf, join, source, group);
     691             :     }
     692             : 
     693           0 :     return;
     694           0 : }
     695             : 
     696             : // Handling per-host, per-<S,G> notification for MVPN case
     697           0 : void GmpProto::TriggerMvpnNotification(const VmInterface *vm_intf, bool join,
     698             :                                     IpAddress source, IpAddress group) {
     699             : 
     700             :     uint32_t src_addr;
     701           0 :     src_addr = htonl(source.to_v4().to_ulong());
     702             : 
     703           0 :     if (src_addr) {
     704           0 :         if (join) {
     705           0 :             agent_->oper_db()->multicast()->AddVmInterfaceToSourceGroup(
     706           0 :                                     agent_->fabric_policy_vrf_name(),
     707           0 :                                     agent_->fabric_vn_name(), vm_intf,
     708           0 :                                     source.to_v4(), group.to_v4());
     709             :         } else {
     710           0 :             agent_->oper_db()->multicast()->DeleteVmInterfaceFromSourceGroup(
     711           0 :                                     agent_->fabric_policy_vrf_name(), vm_intf,
     712           0 :                                     source.to_v4(), group.to_v4());
     713             :         }
     714             :     } else {
     715           0 :         if (!join) {
     716           0 :             agent_->oper_db()->multicast()->DeleteVmInterfaceFromSourceGroup(
     717           0 :                                     agent_->fabric_policy_vrf_name(), vm_intf,
     718           0 :                                     group.to_v4());
     719             :         }
     720             :     }
     721             : 
     722           0 :     return;
     723             : }
     724             : 
     725             : // Handling per-host, per-<S,G> notification for EVPN(SMET) case
     726           0 : void GmpProto::TriggerEvpnNotification(const VmInterface *vm_intf, bool join,
     727             :                                     IpAddress source, IpAddress group) {
     728             : 
     729           0 :     if (join) {
     730           0 :         MCTRACE(LogSG, "Add VM Mcast VRF SG ",
     731             :                             vm_intf->primary_ip_addr().to_string(),
     732             :                             source.to_string(), group.to_string(), 0);
     733           0 :         agent_->oper_db()->multicast()->AddVmInterfaceToVrfSourceGroup(
     734             :                 vm_intf->vrf()->GetName(),
     735           0 :                 agent_->fabric_vn_name(), vm_intf,
     736           0 :                 source.to_v4(), group.to_v4());
     737             :     } else {
     738           0 :         MCTRACE(LogSG, "Delete VM Mcast VRF SG ",
     739             :                             vm_intf->primary_ip_addr().to_string(),
     740             :                             source.to_string(), group.to_string(), 0);
     741           0 :         agent_->oper_db()->multicast()->DeleteVmInterfaceFromVrfSourceGroup(
     742             :                 vm_intf->vrf()->GetName(), vm_intf,
     743           0 :                 source.to_v4(), group.to_v4());
     744             :     }
     745             : 
     746           0 :     return;
     747             : }
     748             : 
     749             : // Accept/reject <S,G> based on the multicast policy configured
     750             : // by the user/application.
     751           0 : bool GmpProto::MulticastPolicyCheck(GmpIntf *gif, IpAddress source,
     752             :                             IpAddress group) {
     753             : 
     754           0 :     if (!gif) {
     755           0 :         return false;
     756             :     }
     757             : 
     758           0 :     VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(gif->get_vrf_name());
     759           0 :     VnEntry *vn = vrf ? vrf->vn() : NULL;
     760           0 :     if (!vn) {
     761           0 :         return false;
     762             :     }
     763             : 
     764           0 :     const UuidList &mp_list = vn->mp_list();
     765           0 :     if (!mp_list.size()) {
     766           0 :         return true;
     767             :     }
     768             : 
     769           0 :     UuidList::const_iterator it = mp_list.begin();
     770           0 :     MulticastPolicyTable *table = agent_->mp_table();
     771           0 :     while (it != mp_list.end()) {
     772           0 :         MulticastPolicyKey key(*it);
     773           0 :         MulticastPolicyEntry *entry = static_cast<MulticastPolicyEntry *>
     774           0 :                                             (table->FindActiveEntry(&key));
     775           0 :         SourceGroupInfo::Action action = entry->GetAction(source, group);
     776           0 :         if (action == SourceGroupInfo::ACTION_PASS) {
     777           0 :             return true;
     778             :         }
     779           0 :         it++;
     780           0 :     }
     781             : 
     782           0 :     return false;
     783             : }
     784             : 
     785             : // Send IGMP packet generated by the GMP to particular destination
     786           0 : bool GmpProto::SendPacket(GmpIntf *gif, uint8_t *pkt, uint32_t pkt_len,
     787             :                             IpAddress dest) {
     788             : 
     789           0 :     GmpPacket packet(pkt, pkt_len, dest);
     790             : 
     791           0 :     if (!cb_) {
     792           0 :         return false;
     793             :     }
     794             : 
     795           0 :     const VrfEntry *vrf = agent_->vrf_table()->FindVrfFromName(
     796             :                             gif->get_vrf_name());
     797           0 :     if (!vrf) {
     798           0 :         return false;
     799             :     }
     800             : 
     801           0 :     return cb_(vrf, gif->get_ip_address(), &packet);
     802             : }
     803             : 
     804           1 : GmpProto *GmpProtoManager::CreateGmpProto(GmpType::Type type, Agent *agent,
     805             :                             const std::string &task_name, int instance,
     806             :                             boost::asio::io_context &io) {
     807             : 
     808           1 :     GmpProto *proto_inst = new GmpProto(type, agent, task_name, instance, io);
     809           1 :     if (!proto_inst) {
     810           0 :         return NULL;
     811             :     }
     812             : 
     813           1 :     return proto_inst;
     814             : }
     815             : 
     816           1 : bool GmpProtoManager::DeleteGmpProto(GmpProto *proto_inst) {
     817           1 :     if (!proto_inst) {
     818           0 :         return false;
     819             :     }
     820             : 
     821           1 :     delete proto_inst;
     822             : 
     823           1 :     return true;
     824             : }
     825             : 
     826             : // Callback registered with GMP to check <S,G> for multicast policy
     827           0 : boolean gmp_policy_check(mgm_global_data *gd, gmp_intf *intf,
     828             :                             gmp_addr_string source, gmp_addr_string group)
     829             : {
     830           0 :     if (!gd || !intf) {
     831           0 :         return FALSE;
     832             :     }
     833             : 
     834           0 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     835           0 :         return FALSE;
     836             :     }
     837             : 
     838           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     839           0 :     GmpIntf *gif = (GmpIntf *)intf->vm_interface;
     840             : 
     841           0 :     if (!gmp_proto || !gif) {
     842           0 :         return FALSE;
     843             :     }
     844             : 
     845             :     uint32_t addr;
     846           0 :     memcpy(&addr, &source, IPV4_ADDR_LEN);
     847           0 :     IpAddress source_addr = Ip4Address(ntohl(addr));
     848           0 :     memcpy(&addr, &group, IPV4_ADDR_LEN);
     849           0 :     IpAddress group_addr = Ip4Address(ntohl(addr));
     850             : 
     851           0 :     bool permit = gmp_proto->MulticastPolicyCheck(gif, source_addr, group_addr);
     852             : 
     853           0 :     return (permit ? TRUE : FALSE);
     854             : }
     855             : 
     856           0 : void gmp_notification_ready(mgm_global_data *gd)
     857             : {
     858           0 :    if (!gd) {
     859           0 :         return;
     860             :     }
     861             : 
     862           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     863             : 
     864           0 :     gmp_proto->GmpNotificationReady();
     865             : 
     866           0 :     return;
     867             : }
     868             : 
     869             : // Function to handle per-<S,G> notifications
     870           0 : void gmp_group_notify(mgm_global_data *gd, gmp_intf *intf,
     871             :                             int group_action, gmp_addr_string source,
     872             :                             gmp_addr_string group)
     873             : {
     874           0 :     if (!gd || !intf) {
     875           0 :         return;
     876             :     }
     877             : 
     878           0 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     879           0 :         return;
     880             :     }
     881             : 
     882           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     883           0 :     GmpIntf *gif = (GmpIntf *)intf->vm_interface;
     884             : 
     885           0 :     if (!gmp_proto || !gif) {
     886           0 :         return;
     887             :     }
     888             : 
     889             :     uint32_t addr;
     890           0 :     memcpy(&addr, &source, IPV4_ADDR_LEN);
     891           0 :     IpAddress source_addr = Ip4Address(ntohl(addr));
     892           0 :     memcpy(&addr, &group, IPV4_ADDR_LEN);
     893           0 :     IpAddress group_addr = Ip4Address(ntohl(addr));
     894             : 
     895           0 :     gmp_proto->GroupNotify(gif, source_addr, group_addr, group_action);
     896             : }
     897             : 
     898             : // C-based function to handle per-<S,G> resync notifications
     899           0 : void gmp_cache_resync_notify(mgm_global_data *gd, gmp_intf *intf,
     900             :                             gmp_addr_string source, gmp_addr_string group)
     901             : {
     902           0 :     if (!gd || !intf) {
     903           0 :         return;
     904             :     }
     905             : 
     906           0 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     907           0 :         return;
     908             :     }
     909             : 
     910           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     911           0 :     GmpIntf *gif = (GmpIntf *)intf->vm_interface;
     912             : 
     913           0 :     if (!gmp_proto || !gif) {
     914           0 :         return;
     915             :     }
     916             : 
     917             :     uint32_t addr;
     918           0 :     memcpy(&addr, &source, IPV4_ADDR_LEN);
     919           0 :     IpAddress source_addr = Ip4Address(ntohl(addr));
     920           0 :     memcpy(&addr, &group, IPV4_ADDR_LEN);
     921           0 :     IpAddress group_addr = Ip4Address(ntohl(addr));
     922             : 
     923           0 :     gmp_proto->ResyncNotify(gif, source_addr, group_addr);
     924             : }
     925             : 
     926             : // C-based function to handle per-host, per-<S,G> notifications
     927           0 : void gmp_host_update(mgm_global_data *gd, gmp_intf *intf, boolean join,
     928             :                             gmp_addr_string host, gmp_addr_string source,
     929             :                             gmp_addr_string group)
     930             : {
     931           0 :     if (!gd || !intf) {
     932           0 :         return;
     933             :     }
     934             : 
     935           0 :     if (gd->mgm_gd_af != MCAST_AF_IPV4) {
     936           0 :         return;
     937             :     }
     938             : 
     939           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     940           0 :     GmpIntf *gif = (GmpIntf *)intf->vm_interface;
     941             : 
     942           0 :     if (!gmp_proto || !gif) {
     943           0 :         return;
     944             :     }
     945             : 
     946             :     uint32_t addr;
     947           0 :     memcpy(&addr, &host, IPV4_ADDR_LEN);
     948           0 :     IpAddress host_addr = Ip4Address(ntohl(addr));
     949           0 :     memcpy(&addr, &source, IPV4_ADDR_LEN);
     950           0 :     IpAddress source_addr = Ip4Address(ntohl(addr));
     951           0 :     memcpy(&addr, &group, IPV4_ADDR_LEN);
     952           0 :     IpAddress group_addr = Ip4Address(ntohl(addr));
     953             : 
     954           0 :     gmp_proto->UpdateHostInSourceGroup(gif, join ? true : false, host_addr,
     955             :                                     source_addr, group_addr);
     956             : }
     957             : 
     958             : // Allocate buffer for use in sending IGMP packet
     959           3 : uint8_t *gmp_get_send_buffer(mgm_global_data *gd, gmp_intf *intf)
     960             : {
     961           3 :     if (!gd || !intf) {
     962           0 :         return NULL;
     963             :     }
     964             : 
     965           3 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     966           3 :     return gmp_proto->GmpBufferGet();
     967             : }
     968             : 
     969             : // Free the allocated buffer used in sending IGMP packet
     970           3 : void gmp_free_send_buffer(mgm_global_data *gd, gmp_intf *intf, uint8_t *buffer)
     971             : {
     972           3 :     if (!gd || !intf) {
     973           0 :         return;
     974             :     }
     975             : 
     976           3 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     977           3 :     gmp_proto->GmpBufferFree(buffer);
     978             : 
     979           3 :     return;
     980             : }
     981             : 
     982             : // Send IGMP packet out to the VMs.
     983           0 : void gmp_send_one_packet(mgm_global_data *gd, gmp_intf *intf, uint8_t *pkt,
     984             :                             uint32_t pkt_len, gmp_addr_string dest)
     985             : {
     986           0 :     if (!gd || !intf) {
     987           0 :         return;
     988             :     }
     989             : 
     990           0 :     GmpProto *gmp_proto = (GmpProto *)gd->gmp_sm;
     991           0 :     GmpIntf *gif = (GmpIntf *)intf->vm_interface;
     992             : 
     993             :     uint32_t addr;
     994           0 :     memcpy(&addr, &dest, IPV4_ADDR_LEN);
     995           0 :     IpAddress dst_addr = IpAddress(Ip4Address(ntohl(addr)));
     996             : 
     997           0 :     gmp_proto->SendPacket(gif, pkt, pkt_len, dst_addr);
     998             : 
     999           0 :     return;
    1000             : }

Generated by: LCOV version 1.14