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

Generated by: LCOV version 1.14