LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - connection_info.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 143 160 89.4 %
Date: 2026-08-03 02:19:58 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include "base/connection_info.h"
       5             : 
       6             : #include <boost/system/error_code.hpp>
       7             : #include <boost/asio/ip/tcp.hpp>
       8             : #include <boost/asio/ip/address.hpp>
       9             : #include <boost/tuple/tuple_comparison.hpp>
      10             : #include <boost/foreach.hpp>
      11             : 
      12             : #include "base/string_util.h"
      13             : #include "base/sandesh/process_info_constants.h"
      14             : 
      15             : namespace process {
      16             : 
      17             : using std::vector;
      18             : using std::string;
      19             : 
      20             : // ConnectionState
      21             : boost::scoped_ptr<ConnectionState> ConnectionState::instance_;
      22             : boost::scoped_ptr<ConnectionStateManager> ConnectionStateManager::instance_;
      23             : 
      24             : 
      25         161 : ConnectionState::ConnectionState(SendUveCb send_uve_cb) :
      26         161 :     send_uve_cb_(send_uve_cb) {
      27         161 : }
      28             : 
      29             : // CreateInstance should be called from ConnectionStateManager::Init()
      30          48 : void ConnectionState::CreateInstance(SendUveCb send_uve_cb) {
      31             :     // The assert is to catch errors where ConnectionState::GetInstance()
      32             :     // is called before ConnectionStateManager::Init()
      33          48 :     assert(instance_ == NULL);
      34          48 :     instance_.reset(new ConnectionState(send_uve_cb));
      35          48 : }
      36             : 
      37       60810 : ConnectionState* ConnectionState::GetInstance() {
      38       60810 :     if (instance_ == NULL) {
      39             :         // This is needed to handle unit tests that do not call
      40             :         // ConnectionStateManager::Init()
      41         113 :         instance_.reset(new ConnectionState(NULL));
      42             :     }
      43       60810 :     return instance_.get();
      44             : }
      45             : 
      46       16848 : void ConnectionState::Update() {
      47       16848 :     if (!send_uve_cb_.empty()) {
      48          10 :         send_uve_cb_();
      49             :     }
      50       16848 : }
      51             : 
      52       43528 : void ConnectionState::UpdateInternal(ConnectionType::type ctype,
      53             :     const string &name, ConnectionStatus::type status,
      54             :     const vector<Endpoint> &servers, string message) {
      55             :     // Populate key
      56       43528 :     ConnectionInfoKey key(ctype, name);
      57             :     // Populate info
      58       43528 :     ConnectionInfo info;
      59       43526 :     info.set_type(
      60       43527 :         g_process_info_constants.ConnectionTypeNames.find(ctype)->second);
      61       43526 :     info.set_name(name);
      62       43526 :     vector<string> server_addrs;
      63       45466 :     BOOST_FOREACH(const Endpoint &server, servers) {
      64         970 :         boost::system::error_code ec;
      65         970 :         string saddr(server.address().to_string(ec));
      66         970 :         int sport(server.port());
      67        1940 :         string server_address(saddr + ":" + integerToString(sport));
      68         970 :         server_addrs.push_back(server_address);
      69         970 :     }
      70       43526 :     info.set_server_addrs(server_addrs);
      71       43526 :     info.set_status(
      72       43526 :         g_process_info_constants.ConnectionStatusNames.find(status)->second);
      73       43526 :     info.set_description(message);
      74             :     // Lookup connection info map
      75       43528 :     std::scoped_lock lock(mutex_);
      76       43528 :     ConnectionInfoMap::iterator it = connection_map_.find(key);
      77       43528 :     if (it != connection_map_.end()) {
      78             :         // Update
      79       86651 :         if (it->second.server_addrs == info.server_addrs &&
      80       86651 :             it->second.status == info.status &&
      81       27420 :             it->second.description == info.description) {
      82             :             // Do not send UVE if there is no change in the server_addrs,
      83             :             // status or description
      84       27235 :             return;
      85             :         }
      86       16161 :         it->second = info;
      87             :     } else {
      88             :         // Add
      89         132 :         connection_map_[key] = info;
      90             :     }
      91       16293 :     if (!send_uve_cb_.empty()) {
      92         424 :         send_uve_cb_();
      93             :     }
      94      125233 : }
      95             : 
      96       43036 : void ConnectionState::Update(ConnectionType::type ctype,
      97             :     const string &name, ConnectionStatus::type status,
      98             :     const vector<Endpoint> &servers, string message) {
      99       43036 :     UpdateInternal(ctype, name, status, servers, message);
     100       43036 : }
     101             : 
     102         492 : void ConnectionState::Update(ConnectionType::type ctype,
     103             :     const string &name, ConnectionStatus::type status,
     104             :     Endpoint server, string message) {
     105         492 :     UpdateInternal(ctype, name, status, boost::assign::list_of(server),
     106             :         message);
     107         492 : }
     108             : 
     109           5 : void ConnectionState::Delete(ConnectionType::type ctype,
     110             :     const string &name) {
     111             :     // Construct key
     112           5 :     ConnectionInfoKey key(ctype, name);
     113             :     // Delete
     114           5 :     std::scoped_lock lock(mutex_);
     115           5 :     connection_map_.erase(key);
     116           5 :     if (!send_uve_cb_.empty()) {
     117           5 :         send_uve_cb_();
     118             :     }
     119           5 : }
     120             : 
     121         453 : vector<ConnectionInfo> ConnectionState::GetInfosUnlocked() const {
     122         453 :     vector<ConnectionInfo> infos;
     123         453 :     for (ConnectionInfoMap::const_iterator it = connection_map_.begin();
     124        1367 :          it != connection_map_.end(); it++) {
     125         914 :         infos.push_back(it->second);
     126             :     }
     127         453 :     return infos;
     128           0 : }
     129             : 
     130           0 : vector<ConnectionInfo> ConnectionState::GetInfos() const {
     131           0 :     std::scoped_lock lock(mutex_);
     132           0 :     return GetInfosUnlocked();
     133           0 : }
     134             : 
     135         421 : void GetProcessStateCb(const vector<ConnectionInfo> &cinfos,
     136             :     ProcessState::type &state, string &message,
     137             :     const vector<ConnectionTypeName> &expected_connections) {
     138             :     // Determine if the number of connections is as expected.
     139         421 :     size_t num_connections(cinfos.size());
     140         421 :     if (num_connections != expected_connections.size()) {
     141         298 :         GetConnectionInfoMessage(cinfos, expected_connections, message);
     142         298 :         state = ProcessState::NON_FUNCTIONAL;
     143         298 :         return;
     144             :     }
     145             :     string cup(g_process_info_constants.ConnectionStatusNames.
     146         123 :                     find(ConnectionStatus::UP)->second);
     147         123 :     bool is_cup = true;
     148             :     // Iterate to determine process connectivity status
     149         123 :     for (vector<ConnectionInfo>::const_iterator it = cinfos.begin();
     150         489 :          it != cinfos.end(); it++) {
     151         366 :         const ConnectionInfo &cinfo(*it);
     152         366 :         const string &conn_status(cinfo.get_status());
     153         366 :         if (conn_status != cup) {
     154         100 :             is_cup = false;
     155         100 :             if (message.empty()) {
     156          72 :                 message = cinfo.get_type();
     157             :             } else {
     158          28 :                 message += ", " + cinfo.get_type();
     159             :             }
     160         100 :             const string &name(cinfo.get_name());
     161         100 :             if (!name.empty()) {
     162          30 :                 message += ":" + name;
     163             :             }
     164             :         }
     165             :     }
     166             :     // All critical connections are in good condition.
     167         123 :     if (is_cup) {
     168          51 :         state = ProcessState::FUNCTIONAL;
     169             :     } else {
     170          72 :         state = ProcessState::NON_FUNCTIONAL;
     171          72 :         message += " connection down";
     172             :     }
     173         123 :     return;
     174         123 : }
     175             : 
     176             : // Custom find function to compare ConnectionInfo and
     177             : // expected connection structures
     178             : struct CompareConnections : public std::unary_function<ConnectionTypeName,
     179             :     bool> {
     180             :     ConnectionTypeName expected_connection_;
     181         876 :     explicit CompareConnections(const ConnectionTypeName exp_connection) :
     182         876 :         expected_connection_(exp_connection) {}
     183        1230 :     bool operator() (const ConnectionInfo cinfo) {
     184        1707 :         if (expected_connection_.first == cinfo.get_type() &&
     185         477 :             expected_connection_.second == cinfo.get_name()) {
     186         474 :             return true;
     187             :         } else {
     188         756 :             return false;
     189             :         }
     190             :     }
     191             : };
     192             : 
     193         298 : void GetConnectionInfoMessage(const vector<ConnectionInfo> &cinfos,
     194             :     const vector<ConnectionTypeName> &expected_connections,
     195             :     string &message) {
     196         298 :     size_t num_connections(cinfos.size());
     197         596 :     message = "Number of connections:" + integerToString(num_connections) +
     198         894 :               ", Expected:" + integerToString(expected_connections.size());
     199         298 :     if (num_connections > expected_connections.size()) {
     200           1 :         size_t i = 0;
     201           1 :         message += " Extra: ";
     202             :         // find the extra connection
     203           1 :         for (vector<ConnectionInfo>::const_iterator it = cinfos.begin();
     204           4 :             it != cinfos.end(); it++) {
     205           3 :             const ConnectionInfo &cinfo(*it);
     206           3 :             ConnectionTypeName con_info(cinfo.get_type(), cinfo.get_name());
     207           3 :             vector<ConnectionTypeName>::const_iterator position;
     208           3 :             position = std::find(expected_connections.begin(),
     209             :                                  expected_connections.end(), con_info);
     210           3 :             if (position == expected_connections.end()) {
     211           1 :                 i++;
     212           1 :                 message += con_info.first;
     213           1 :                 if (!con_info.second.empty()) {
     214           1 :                     message += ":" + con_info.second;
     215             :                 }
     216           1 :                 if (i != num_connections-expected_connections.size()) {
     217           0 :                     message += ",";
     218             :                 }
     219             :             }
     220           3 :         }
     221             :     } else {
     222             :         // find the missing connection
     223         297 :         size_t i = 0;
     224         297 :         message += " Missing: ";
     225         297 :         for (vector<ConnectionTypeName>::const_iterator it =
     226        1470 :              expected_connections.begin(); it != expected_connections.end();
     227         876 :              it++) {
     228         876 :             vector<ConnectionInfo>::const_iterator position;
     229         876 :             position = std::find_if(cinfos.begin(), cinfos.end(),
     230        1752 :                                      CompareConnections(*it));
     231             :             // If connection is not found in cinfo, its a missing
     232             :             // connection
     233         876 :             if (position == cinfos.end()) {
     234         402 :                 i++;
     235         402 :                 message += it->first;
     236         402 :                 if (!it->second.empty()) {
     237         161 :                     message += ":" + it->second;
     238             :                 }
     239         402 :                 if (i != expected_connections.size() - cinfos.size()) {
     240         105 :                     message += ",";
     241             :                 }
     242             :             }
     243             :         }
     244             :     }
     245         298 : }
     246             : 
     247             : vector<FlagInfo>
     248         453 : ConnectionStateManager::GetFlagInfos(const FlagConfigVec &flag_infos) {
     249         453 :     FlagInfo info;
     250         453 :     vector<FlagInfo> infos;
     251         453 :     ContextInfo c_info;
     252         453 :     vector<ContextInfo> c_infos;
     253             :     FlagState state;
     254         453 :     ContextVec c_vec;
     255         453 :     context_iterator c_itr;
     256         453 :     for (flag_cfg_itr it = flag_infos.begin(); it != flag_infos.end(); it++) {
     257           0 :         info.set_name(it->name());
     258           0 :         info.set_version(it->version());
     259           0 :         info.set_enabled(it->enabled());
     260           0 :         info.set_state(state.ToString(it->state()));
     261           0 :         c_vec = it->context_infos();
     262           0 :         for (c_itr = c_vec.begin(); c_itr != c_vec.end(); c_itr++) {
     263           0 :             c_info.desc = c_itr->desc;
     264           0 :             c_info.value = c_itr->value;
     265           0 :             c_infos.push_back(c_info);
     266             :         }
     267           0 :         info.set_context_infos(c_infos);
     268           0 :         infos.push_back(info);
     269             :     }
     270         906 :     return infos;
     271         453 : }
     272             : 
     273             : } // namespace process

Generated by: LCOV version 1.14