LCOV - code coverage report
Current view: top level - vnsw/agent/controller - controller_ifmap.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 107 195 54.9 %
Date: 2026-11-09 02:10:49 Functions: 16 27 59.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <stdint.h>
       7             : #include <string.h>
       8             : #include <pugixml/pugixml.hpp>
       9             : #include <xml/xml_base.h>
      10             : #include <xml/xml_pugi.h>
      11             : 
      12             : #include <base/util.h>
      13             : #include <base/logging.h>
      14             : #include <xmpp/xmpp_channel.h>
      15             : #include <ifmap/ifmap_agent_parser.h>
      16             : 
      17             : #include <cmn/agent_cmn.h>
      18             : #include <cmn/agent_stats.h>
      19             : 
      20             : #include <controller/controller_init.h>
      21             : #include <controller/controller_ifmap.h>
      22             : #include <controller/controller_peer.h>
      23             : #include <controller/controller_types.h>
      24             : 
      25             : 
      26             : uint64_t AgentIfMapXmppChannel::seq_number_;
      27             : 
      28           2 : AgentIfMapXmppChannel::AgentIfMapXmppChannel(Agent *agent, XmppChannel *channel,
      29           2 :                                              uint8_t cnt) : channel_(channel),
      30           2 :                                              xs_idx_(cnt),
      31           2 :                                              agent_(agent) {
      32           2 :     channel_->RegisterReceive(xmps::CONFIG,
      33             :                               boost::bind(&AgentIfMapXmppChannel::ReceiveInternal,
      34             :                                           this, _1));
      35           2 :     config_cleanup_timer_.reset(new ConfigCleanupTimer(agent));
      36           2 :     end_of_config_timer_.reset(new EndOfConfigTimer(agent, this));
      37           2 : }
      38             : 
      39           4 : AgentIfMapXmppChannel::~AgentIfMapXmppChannel() {
      40           2 :     channel_->UnRegisterWriteReady(xmps::CONFIG);
      41           2 :     channel_->UnRegisterReceive(xmps::CONFIG);
      42           2 :     config_cleanup_timer_.reset();
      43           2 :     end_of_config_timer_.reset();
      44           4 : }
      45             : 
      46          38 : uint64_t AgentIfMapXmppChannel::NewSeqNumber() {
      47             : 
      48          38 :     seq_number_++;
      49             : 
      50          38 :     if (seq_number_ == 0) {
      51           0 :         return ++seq_number_;
      52             :     }
      53             : 
      54          38 :     CONTROLLER_TRACE(IFMapSeqTrace, GetSeqNumber(), seq_number_, "New Config Seq Num");
      55          38 :     return  seq_number_;
      56             : }
      57             : 
      58          57 : ConfigCleanupTimer *AgentIfMapXmppChannel::config_cleanup_timer() {
      59          57 :     return config_cleanup_timer_.get();
      60             : }
      61             : 
      62          57 : EndOfConfigTimer *AgentIfMapXmppChannel::end_of_config_timer() {
      63          57 :     return end_of_config_timer_.get();
      64             : }
      65             : 
      66           0 : bool AgentIfMapXmppChannel::SendUpdate(const std::string &msg) {
      67           0 :     if (!channel_) return false;
      68           0 :     return channel_->Send((const uint8_t *)msg.data(), msg.size(), xmps::CONFIG,
      69           0 :                            boost::bind(&AgentIfMapXmppChannel::WriteReadyCb, this, _1));
      70             : }
      71             : 
      72           0 : void AgentIfMapXmppChannel::ReceiveUpdate(const XmppStanza::XmppMessage *msg) {
      73           0 :     if (msg && msg->type == XmppStanza::IQ_STANZA) {
      74           0 :         std::unique_ptr<XmlBase> impl(XmppXmlImplFactory::Instance()->GetXmlImpl());
      75           0 :         XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl.get());
      76           0 :         XmlPugi *msg_pugi = reinterpret_cast<XmlPugi *>(msg->dom.get());
      77           0 :         pugi->LoadXmlDoc(msg_pugi->doc());
      78             :         boost::shared_ptr<ControllerXmppData> data(new ControllerXmppData(xmps::CONFIG,
      79             :                                                                           xmps::UNKNOWN,
      80           0 :                                                                           xs_idx_,
      81           0 :                                                                           std::move(impl),
      82           0 :                                                                           true));
      83           0 :         agent_->controller()->Enqueue(data);
      84           0 :         end_of_config_timer()->last_config_receive_time_ = UTCTimestampUsec();
      85           0 :     }
      86           0 : }
      87             : 
      88           0 : void AgentIfMapXmppChannel::ReceiveConfigMessage(std::unique_ptr<XmlBase> impl) {
      89             : 
      90           0 :     if (GetXmppServerIdx() != agent_->ifmap_active_xmpp_server_index()) {
      91           0 :         LOG(WARN, "IFMap config on non primary channel");
      92           0 :         return;
      93             :     }
      94             : 
      95           0 :     XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl.get());
      96           0 :     pugi::xml_node node = pugi->FindNode("config");
      97           0 :     IFMapAgentParser *parser = agent_->ifmap_parser();
      98           0 :     assert(parser);
      99           0 :     parser->ConfigParse(node, seq_number_);
     100             : }
     101             : 
     102           0 : void AgentIfMapXmppChannel::ReceiveInternal(const XmppStanza::XmppMessage *msg) {
     103           0 :     if (agent_->stats())
     104           0 :         agent_->stats()->incr_xmpp_config_in_msgs(GetXmppServerIdx());
     105           0 :     ReceiveUpdate(msg);
     106           0 : }
     107             : 
     108           0 : std::string AgentIfMapXmppChannel::ToString() const {
     109           0 :     return channel_->ToString();
     110             : }
     111             : 
     112           0 : void AgentIfMapXmppChannel::WriteReadyCb(const boost::system::error_code &ec) {
     113           0 : }
     114             : 
     115           0 : void AgentIfMapXmppChannel::StartEndOfConfigTimer() {
     116             :     //First start for end of config identification.
     117           0 :     end_of_config_timer()->Start(agent_->controller_xmpp_channel(xs_idx_));
     118           0 : }
     119             : 
     120           0 : void AgentIfMapXmppChannel::StopEndOfConfigTimer() {
     121             :     //First start for end of config identification.
     122           0 :     end_of_config_timer()->Cancel();
     123           0 : }
     124             : 
     125           0 : void AgentIfMapXmppChannel::StartConfigCleanupTimer() {
     126           0 :     config_cleanup_timer()->Start(agent_->controller_xmpp_channel(xs_idx_));
     127           0 : }
     128             : 
     129           0 : void AgentIfMapXmppChannel::StopConfigCleanupTimer() {
     130           0 :     config_cleanup_timer()->Cancel();
     131           0 : }
     132             : 
     133          19 : void AgentIfMapXmppChannel::EnqueueEndOfConfig() {
     134          19 :     EndOfConfigDataPtr data(new EndOfConfigData(this));
     135             :     VNController::ControllerWorkQueueDataType base_data =
     136          19 :         boost::static_pointer_cast<ControllerWorkQueueData>(data);
     137          19 :     agent_->controller()->Enqueue(base_data);
     138          19 : }
     139             : 
     140           0 : void AgentIfMapXmppChannel::ProcessEndOfConfig() {
     141           0 :     config_cleanup_timer()->Start(agent_->controller_xmpp_channel(xs_idx_));
     142           0 :     agent_->controller()->StartEndOfRibTxTimer();
     143           0 :     end_of_config_timer()->end_of_config_processed_time_ = UTCTimestampUsec();
     144           0 : }
     145             : 
     146          19 : EndOfConfigData::EndOfConfigData(AgentIfMapXmppChannel *ch) :
     147          19 :     ControllerWorkQueueData(), channel_(ch) {
     148          19 : }
     149             : 
     150             : // Get active xmpp-peer
     151         328 : static AgentXmppChannel *GetActivePeer(Agent *agent) {
     152         328 :     int active_index = agent->ifmap_active_xmpp_server_index();
     153         328 :     if (active_index == -1) {
     154         136 :         return NULL;
     155             :     }
     156             : 
     157         192 :     AgentXmppChannel *peer = agent->controller_xmpp_channel(active_index);
     158         192 :     if (peer == NULL)
     159           0 :         return NULL;
     160             : 
     161         192 :     if (AgentXmppChannel::IsBgpPeerActive(agent, peer) == false) {
     162           8 :         return NULL;
     163             :     }
     164             : 
     165         184 :     return peer;
     166             : }
     167             : 
     168             : 
     169         184 : static AgentIfMapXmppChannel *GetActiveChannel
     170             : (Agent *agent, struct AgentIfMapVmExport::VmExportInfo *info) {
     171         184 :     int active_index = agent->ifmap_active_xmpp_server_index();
     172         184 :     AgentIfMapXmppChannel *ifmap = agent->ifmap_xmpp_channel(active_index);
     173             :     // Peer is valid, but channel may be down
     174         184 :     if (ifmap == NULL)
     175         184 :         return NULL;
     176             : 
     177           0 :     if (info && (info->seq_number_ != ifmap->GetSeqNumber())) {
     178           0 :         return NULL;
     179             :     }
     180             : 
     181           0 :     return ifmap;
     182             : }
     183             : 
     184         165 : void AgentIfMapVmExport::VmiDelete(const ControllerVmiSubscribeData *entry) {
     185         165 :     VmMap::iterator vm_it = vm_map_.find(entry->vm_uuid_);
     186         165 :     if (vm_map_.end() == vm_it) {
     187           0 :         return;
     188             :     }
     189             : 
     190         165 :     struct VmExportInfo *info = vm_it->second;
     191             :     //If delete already processed, neglect the delete
     192         165 :     if (!info)
     193           0 :         return;
     194             : 
     195             :     // Find VMI-UUID in the list of VMI
     196         165 :     UuidList::const_iterator vmi_it = std::find(info->vmi_list_.begin(),
     197             :                                                 info->vmi_list_.end(),
     198         330 :                                                 entry->vmi_uuid_);
     199         165 :     if (vmi_it == info->vmi_list_.end())
     200           0 :         return;
     201             : 
     202         165 :     CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_),
     203             :                      UuidToString(entry->vmi_uuid_), "Delete");
     204         165 :     info->vmi_list_.remove(entry->vmi_uuid_);
     205             :     // Stop here if VM has more interfaces
     206         165 :     if (info->vmi_list_.size() != 0) {
     207           2 :         return;
     208             :     }
     209             : 
     210             :     // All interfaces deleted. Remove the VM entry
     211         163 :     vm_map_.erase(entry->vm_uuid_);
     212             : 
     213             :     // Unsubscribe from config if we have active channel
     214         163 :     AgentXmppChannel *peer = GetActivePeer(agent_);
     215         163 :     if (peer == NULL) {
     216           0 :         delete info;
     217           0 :         CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_), "",
     218             :                          "Peer NULL skipped Unsubscribe ");
     219           0 :         return;
     220             :     }
     221             : 
     222         163 :     AgentIfMapXmppChannel *ifmap = GetActiveChannel(agent_, info);
     223         163 :     delete info;
     224         163 :     if (ifmap == NULL) {
     225         163 :         CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_), "",
     226             :                          "Channel NULL skipped Unsubscribe ");
     227         163 :         return;
     228             :     }
     229             : 
     230           0 :     CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_), "",
     231             :                      "Unsubscribe ");
     232           0 :     AgentXmppChannel::ControllerSendVmCfgSubscribe(peer, entry->vm_uuid_,
     233             :                                                    false);
     234           0 :     return;
     235             : }
     236             : 
     237         165 : void AgentIfMapVmExport::VmiAdd(const ControllerVmiSubscribeData *entry) {
     238         165 :     struct VmExportInfo *info = NULL;
     239         165 :     VmMap::iterator vm_it = vm_map_.find(entry->vm_uuid_);
     240         165 :     if (vm_map_.end() != vm_it) {
     241           2 :         info = vm_it->second;
     242             :     } else {
     243             :         //If first VMI create the data
     244         163 :         info = new VmExportInfo(0);
     245         163 :         vm_map_[entry->vm_uuid_] = info;
     246             :     }
     247             : 
     248             :     //If VMI is not found, insert in the list
     249         165 :     UuidList::const_iterator vmi_it = std::find(info->vmi_list_.begin(),
     250             :                                                 info->vmi_list_.end(),
     251         330 :                                                 entry->vmi_uuid_);
     252         165 :     if (vmi_it == info->vmi_list_.end()) {
     253         165 :         CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_),
     254             :                          UuidToString(entry->vmi_uuid_), "Add");
     255         165 :         info->vmi_list_.push_back(entry->vmi_uuid_);
     256             :     }
     257             : 
     258             :     // Ensure that peer exists and is in active state
     259         165 :     AgentXmppChannel *peer = GetActivePeer(agent_);
     260         165 :     if (peer == NULL) {
     261         165 :         return;
     262             :     }
     263             : 
     264             :     // Ensure that channel is valid
     265          21 :     AgentIfMapXmppChannel *ifmap = GetActiveChannel(agent_, NULL);
     266          21 :     if (ifmap == NULL) {
     267          21 :         return;
     268             :     }
     269             : 
     270             :     //We have already sent the subscribe
     271           0 :     if (info->seq_number_ == ifmap->GetSeqNumber()) {
     272           0 :         return;
     273             :     }
     274             : 
     275           0 :     CONTROLLER_TRACE(IFMapVmExportTrace, UuidToString(entry->vm_uuid_),
     276             :                      UuidToString(entry->vmi_uuid_), "Subscribe");
     277           0 :     AgentXmppChannel::ControllerSendVmCfgSubscribe(peer, entry->vm_uuid_, true);
     278             : 
     279             :     //Update the sequence number
     280           0 :     info->seq_number_ = ifmap->GetSeqNumber();
     281             : }
     282             : 
     283         330 : void AgentIfMapVmExport::VmiEvent(const ControllerVmiSubscribeData *entry) {
     284         330 :     if (entry->del_) {
     285         165 :         VmiDelete(entry);
     286         165 :         return;
     287             :     }
     288             : 
     289         165 :     VmiAdd(entry);
     290         165 :     return;
     291             : }
     292             : 
     293          19 : void AgentIfMapVmExport::NotifyAll(AgentXmppChannel *peer) {
     294          19 :     VmMap::iterator vm_it;
     295          19 :     AgentIfMapXmppChannel *ifmap = NULL;
     296          19 :     struct VmExportInfo *info = NULL;
     297          19 :     Agent *agent = peer->agent();
     298             : 
     299          19 :     if (!AgentXmppChannel::IsBgpPeerActive(agent, peer)) {
     300           0 :         return;
     301             :     }
     302             : 
     303          19 :     ifmap = agent->ifmap_xmpp_channel(agent->ifmap_active_xmpp_server_index());
     304          19 :     if (!ifmap) {
     305          19 :         return;
     306             :     }
     307             : 
     308             :     //We have all the required data. Send config subscribe for all VM's
     309             :     AgentIfMapVmExport *agent_ifmap_vm_export = peer->agent()->controller()->
     310           0 :         agent_ifmap_vm_export();
     311           0 :     vm_it = agent_ifmap_vm_export->vm_map_.begin();
     312           0 :     for(; vm_it != agent_ifmap_vm_export->vm_map_.end(); vm_it++) {
     313           0 :         info = vm_it->second;
     314           0 :         if (info->seq_number_ == ifmap->GetSeqNumber()) {
     315           0 :             continue;
     316             :         }
     317             : 
     318           0 :         std::stringstream vmid;
     319           0 :         vmid << vm_it->first;
     320           0 :         CONTROLLER_TRACE(IFMapVmExportTrace, vmid.str(), "",
     321             :                          "Subscribe");
     322           0 :         AgentXmppChannel::ControllerSendVmCfgSubscribe(peer,
     323           0 :                                     vm_it->first, true);
     324             : 
     325             :         //Update the sequence number so that we dont send duplicate
     326             :         //subscribe
     327           0 :         info->seq_number_ = ifmap->GetSeqNumber();
     328           0 :     }
     329             : 
     330           0 :     return;
     331             : }
     332             : 
     333           2 : AgentIfMapVmExport::AgentIfMapVmExport(Agent *agent) :
     334           2 :     agent_(agent) {
     335           2 : }
     336             : 
     337           2 : AgentIfMapVmExport::~AgentIfMapVmExport() {
     338           2 :     VmMap::iterator vm_it;
     339           2 :     struct VmExportInfo *info = NULL;
     340             : 
     341             :     //Destroy the vm_map and vmi list
     342           2 :     for(vm_it = vm_map_.begin(); vm_it != vm_map_.end(); vm_it++) {
     343           0 :         info = vm_it->second;
     344           0 :         delete info;
     345             :     }
     346             : 
     347           2 :     vm_map_.clear();
     348           2 : }

Generated by: LCOV version 1.14