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-09-07 02:14:47 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         159 : ConnectionState::ConnectionState(SendUveCb send_uve_cb) :
      26         159 :     send_uve_cb_(send_uve_cb) {
      27         159 : }
      28             : 
      29             : // CreateInstance should be called from ConnectionStateManager::Init()
      30          46 : void ConnectionState::CreateInstance(SendUveCb send_uve_cb) {
      31             :     // The assert is to catch errors where ConnectionState::GetInstance()
      32             :     // is called before ConnectionStateManager::Init()
      33          46 :     assert(instance_ == NULL);
      34          46 :     instance_.reset(new ConnectionState(send_uve_cb));
      35          46 : }
      36             : 
      37       60784 : ConnectionState* ConnectionState::GetInstance() {
      38       60784 :     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       60784 :     return instance_.get();
      44             : }
      45             : 
      46       16840 : void ConnectionState::Update() {
      47       16840 :     if (!send_uve_cb_.empty()) {
      48           2 :         send_uve_cb_();
      49             :     }
      50       16840 : }
      51             : 
      52       43518 : void ConnectionState::UpdateInternal(ConnectionType::type ctype,
      53             :     const string &name, ConnectionStatus::type status,
      54             :     const vector<Endpoint> &servers, string message) {
      55             :     // Populate key
      56       43518 :     ConnectionInfoKey key(ctype, name);
      57             :     // Populate info
      58       43518 :     ConnectionInfo info;
      59       43518 :     info.set_type(
      60       43517 :         g_process_info_constants.ConnectionTypeNames.find(ctype)->second);
      61       43518 :     info.set_name(name);
      62       43518 :     vector<string> server_addrs;
      63       45438 :     BOOST_FOREACH(const Endpoint &server, servers) {
      64         960 :         boost::system::error_code ec;
      65         960 :         string saddr(server.address().to_string(ec));
      66         960 :         int sport(server.port());
      67        1920 :         string server_address(saddr + ":" + integerToString(sport));
      68         960 :         server_addrs.push_back(server_address);
      69         960 :     }
      70       43518 :     info.set_server_addrs(server_addrs);
      71       43517 :     info.set_status(
      72       43516 :         g_process_info_constants.ConnectionStatusNames.find(status)->second);
      73       43517 :     info.set_description(message);
      74             :     // Lookup connection info map
      75       43518 :     std::scoped_lock lock(mutex_);
      76       43518 :     ConnectionInfoMap::iterator it = connection_map_.find(key);
      77       43518 :     if (it != connection_map_.end()) {
      78             :         // Update
      79       86645 :         if (it->second.server_addrs == info.server_addrs &&
      80       86645 :             it->second.status == info.status &&
      81       27417 :             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       16155 :         it->second = info;
      87             :     } else {
      88             :         // Add
      89         128 :         connection_map_[key] = info;
      90             :     }
      91       16283 :     if (!send_uve_cb_.empty()) {
      92         414 :         send_uve_cb_();
      93             :     }
      94      125223 : }
      95             : 
      96       43034 : void ConnectionState::Update(ConnectionType::type ctype,
      97             :     const string &name, ConnectionStatus::type status,
      98             :     const vector<Endpoint> &servers, string message) {
      99       43034 :     UpdateInternal(ctype, name, status, servers, message);
     100       43036 : }
     101             : 
     102         482 : void ConnectionState::Update(ConnectionType::type ctype,
     103             :     const string &name, ConnectionStatus::type status,
     104             :     Endpoint server, string message) {
     105         482 :     UpdateInternal(ctype, name, status, boost::assign::list_of(server),
     106             :         message);
     107         482 : }
     108             : 
     109           3 : void ConnectionState::Delete(ConnectionType::type ctype,
     110             :     const string &name) {
     111             :     // Construct key
     112           3 :     ConnectionInfoKey key(ctype, name);
     113             :     // Delete
     114           3 :     std::scoped_lock lock(mutex_);
     115           3 :     connection_map_.erase(key);
     116           3 :     if (!send_uve_cb_.empty()) {
     117           3 :         send_uve_cb_();
     118             :     }
     119           3 : }
     120             : 
     121         433 : vector<ConnectionInfo> ConnectionState::GetInfosUnlocked() const {
     122         433 :     vector<ConnectionInfo> infos;
     123         433 :     for (ConnectionInfoMap::const_iterator it = connection_map_.begin();
     124        1314 :          it != connection_map_.end(); it++) {
     125         881 :         infos.push_back(it->second);
     126             :     }
     127         433 :     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         423 : 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         423 :     size_t num_connections(cinfos.size());
     140         423 :     if (num_connections != expected_connections.size()) {
     141         304 :         GetConnectionInfoMessage(cinfos, expected_connections, message);
     142         304 :         state = ProcessState::NON_FUNCTIONAL;
     143         304 :         return;
     144             :     }
     145             :     string cup(g_process_info_constants.ConnectionStatusNames.
     146         119 :                     find(ConnectionStatus::UP)->second);
     147         119 :     bool is_cup = true;
     148             :     // Iterate to determine process connectivity status
     149         119 :     for (vector<ConnectionInfo>::const_iterator it = cinfos.begin();
     150         473 :          it != cinfos.end(); it++) {
     151         354 :         const ConnectionInfo &cinfo(*it);
     152         354 :         const string &conn_status(cinfo.get_status());
     153         354 :         if (conn_status != cup) {
     154          95 :             is_cup = false;
     155          95 :             if (message.empty()) {
     156          68 :                 message = cinfo.get_type();
     157             :             } else {
     158          27 :                 message += ", " + cinfo.get_type();
     159             :             }
     160          95 :             const string &name(cinfo.get_name());
     161          95 :             if (!name.empty()) {
     162          29 :                 message += ":" + name;
     163             :             }
     164             :         }
     165             :     }
     166             :     // All critical connections are in good condition.
     167         119 :     if (is_cup) {
     168          51 :         state = ProcessState::FUNCTIONAL;
     169             :     } else {
     170          68 :         state = ProcessState::NON_FUNCTIONAL;
     171          68 :         message += " connection down";
     172             :     }
     173         119 :     return;
     174         119 : }
     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         894 :     explicit CompareConnections(const ConnectionTypeName exp_connection) :
     182         894 :         expected_connection_(exp_connection) {}
     183        1270 :     bool operator() (const ConnectionInfo cinfo) {
     184        1764 :         if (expected_connection_.first == cinfo.get_type() &&
     185         494 :             expected_connection_.second == cinfo.get_name()) {
     186         491 :             return true;
     187             :         } else {
     188         779 :             return false;
     189             :         }
     190             :     }
     191             : };
     192             : 
     193         304 : void GetConnectionInfoMessage(const vector<ConnectionInfo> &cinfos,
     194             :     const vector<ConnectionTypeName> &expected_connections,
     195             :     string &message) {
     196         304 :     size_t num_connections(cinfos.size());
     197         608 :     message = "Number of connections:" + integerToString(num_connections) +
     198         912 :               ", Expected:" + integerToString(expected_connections.size());
     199         304 :     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         303 :         size_t i = 0;
     224         303 :         message += " Missing: ";
     225         303 :         for (vector<ConnectionTypeName>::const_iterator it =
     226        1500 :              expected_connections.begin(); it != expected_connections.end();
     227         894 :              it++) {
     228         894 :             vector<ConnectionInfo>::const_iterator position;
     229         894 :             position = std::find_if(cinfos.begin(), cinfos.end(),
     230        1788 :                                      CompareConnections(*it));
     231             :             // If connection is not found in cinfo, its a missing
     232             :             // connection
     233         894 :             if (position == cinfos.end()) {
     234         403 :                 i++;
     235         403 :                 message += it->first;
     236         403 :                 if (!it->second.empty()) {
     237         161 :                     message += ":" + it->second;
     238             :                 }
     239         403 :                 if (i != expected_connections.size() - cinfos.size()) {
     240         100 :                     message += ",";
     241             :                 }
     242             :             }
     243             :         }
     244             :     }
     245         304 : }
     246             : 
     247             : vector<FlagInfo>
     248         433 : ConnectionStateManager::GetFlagInfos(const FlagConfigVec &flag_infos) {
     249         433 :     FlagInfo info;
     250         433 :     vector<FlagInfo> infos;
     251         433 :     ContextInfo c_info;
     252         433 :     vector<ContextInfo> c_infos;
     253             :     FlagState state;
     254         433 :     ContextVec c_vec;
     255         433 :     context_iterator c_itr;
     256         433 :     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         866 :     return infos;
     271         433 : }
     272             : 
     273             : } // namespace process

Generated by: LCOV version 1.14