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

Generated by: LCOV version 1.14