OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
connection_info.cc
Go to the documentation of this file.
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 
26  send_uve_cb_(send_uve_cb) {
27 }
28 
29 // CreateInstance should be called from ConnectionStateManager::Init()
31  // The assert is to catch errors where ConnectionState::GetInstance()
32  // is called before ConnectionStateManager::Init()
33  assert(instance_ == NULL);
34  instance_.reset(new ConnectionState(send_uve_cb));
35 }
36 
38  if (instance_ == NULL) {
39  // This is needed to handle unit tests that do not call
40  // ConnectionStateManager::Init()
41  instance_.reset(new ConnectionState(NULL));
42  }
43  return instance_.get();
44 }
45 
47  if (!send_uve_cb_.empty()) {
48  send_uve_cb_();
49  }
50 }
51 
53  const string &name, ConnectionStatus::type status,
54  const vector<Endpoint> &servers, string message) {
55  // Populate key
56  ConnectionInfoKey key(ctype, name);
57  // Populate info
58  ConnectionInfo info;
59  info.set_type(
60  g_process_info_constants.ConnectionTypeNames.find(ctype)->second);
61  info.set_name(name);
62  vector<string> server_addrs;
63  BOOST_FOREACH(const Endpoint &server, servers) {
64  boost::system::error_code ec;
65  string saddr(server.address().to_string(ec));
66  int sport(server.port());
67  string server_address(saddr + ":" + integerToString(sport));
68  server_addrs.push_back(server_address);
69  }
70  info.set_server_addrs(server_addrs);
71  info.set_status(
72  g_process_info_constants.ConnectionStatusNames.find(status)->second);
73  info.set_description(message);
74  // Lookup connection info map
75  tbb::mutex::scoped_lock lock(mutex_);
76  ConnectionInfoMap::iterator it = connection_map_.find(key);
77  if (it != connection_map_.end()) {
78  // Update
79  if (it->second.server_addrs == info.server_addrs &&
80  it->second.status == info.status &&
81  it->second.description == info.description) {
82  // Do not send UVE if there is no change in the server_addrs,
83  // status or description
84  return;
85  }
86  it->second = info;
87  } else {
88  // Add
89  connection_map_[key] = info;
90  }
91  if (!send_uve_cb_.empty()) {
92  send_uve_cb_();
93  }
94 }
95 
97  const string &name, ConnectionStatus::type status,
98  const vector<Endpoint> &servers, string message) {
99  UpdateInternal(ctype, name, status, servers, message);
100 }
101 
103  const string &name, ConnectionStatus::type status,
104  Endpoint server, string message) {
105  UpdateInternal(ctype, name, status, boost::assign::list_of(server),
106  message);
107 }
108 
110  const string &name) {
111  // Construct key
112  ConnectionInfoKey key(ctype, name);
113  // Delete
114  tbb::mutex::scoped_lock lock(mutex_);
115  connection_map_.erase(key);
116  if (!send_uve_cb_.empty()) {
117  send_uve_cb_();
118  }
119 }
120 
121 vector<ConnectionInfo> ConnectionState::GetInfosUnlocked() const {
122  vector<ConnectionInfo> infos;
123  for (ConnectionInfoMap::const_iterator it = connection_map_.begin();
124  it != connection_map_.end(); it++) {
125  infos.push_back(it->second);
126  }
127  return infos;
128 }
129 
130 vector<ConnectionInfo> ConnectionState::GetInfos() const {
131  tbb::mutex::scoped_lock lock(mutex_);
132  return GetInfosUnlocked();
133 }
134 
135 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  size_t num_connections(cinfos.size());
140  if (num_connections != expected_connections.size()) {
141  GetConnectionInfoMessage(cinfos, expected_connections, message);
142  state = ProcessState::NON_FUNCTIONAL;
143  return;
144  }
145  string cup(g_process_info_constants.ConnectionStatusNames.
146  find(ConnectionStatus::UP)->second);
147  bool is_cup = true;
148  // Iterate to determine process connectivity status
149  for (vector<ConnectionInfo>::const_iterator it = cinfos.begin();
150  it != cinfos.end(); it++) {
151  const ConnectionInfo &cinfo(*it);
152  const string &conn_status(cinfo.get_status());
153  if (conn_status != cup) {
154  is_cup = false;
155  if (message.empty()) {
156  message = cinfo.get_type();
157  } else {
158  message += ", " + cinfo.get_type();
159  }
160  const string &name(cinfo.get_name());
161  if (!name.empty()) {
162  message += ":" + name;
163  }
164  }
165  }
166  // All critical connections are in good condition.
167  if (is_cup) {
168  state = ProcessState::FUNCTIONAL;
169  } else {
170  state = ProcessState::NON_FUNCTIONAL;
171  message += " connection down";
172  }
173  return;
174 }
175 
176 // Custom find function to compare ConnectionInfo and
177 // expected connection structures
178 struct CompareConnections : public std::unary_function<ConnectionTypeName,
179  bool> {
181  explicit CompareConnections(const ConnectionTypeName exp_connection) :
182  expected_connection_(exp_connection) {}
183  bool operator() (const ConnectionInfo cinfo) {
184  if (expected_connection_.first == cinfo.get_type() &&
185  expected_connection_.second == cinfo.get_name()) {
186  return true;
187  } else {
188  return false;
189  }
190  }
191 };
192 
193 void GetConnectionInfoMessage(const vector<ConnectionInfo> &cinfos,
194  const vector<ConnectionTypeName> &expected_connections,
195  string &message) {
196  size_t num_connections(cinfos.size());
197  message = "Number of connections:" + integerToString(num_connections) +
198  ", Expected:" + integerToString(expected_connections.size());
199  if (num_connections > expected_connections.size()) {
200  size_t i = 0;
201  message += " Extra: ";
202  // find the extra connection
203  for (vector<ConnectionInfo>::const_iterator it = cinfos.begin();
204  it != cinfos.end(); it++) {
205  const ConnectionInfo &cinfo(*it);
206  ConnectionTypeName con_info(cinfo.get_type(), cinfo.get_name());
207  vector<ConnectionTypeName>::const_iterator position;
208  position = std::find(expected_connections.begin(),
209  expected_connections.end(), con_info);
210  if (position == expected_connections.end()) {
211  i++;
212  message += con_info.first;
213  if (!con_info.second.empty()) {
214  message += ":" + con_info.second;
215  }
216  if (i != num_connections-expected_connections.size()) {
217  message += ",";
218  }
219  }
220  }
221  } else {
222  // find the missing connection
223  size_t i = 0;
224  message += " Missing: ";
225  for (vector<ConnectionTypeName>::const_iterator it =
226  expected_connections.begin(); it != expected_connections.end();
227  it++) {
228  vector<ConnectionInfo>::const_iterator position;
229  position = std::find_if(cinfos.begin(), cinfos.end(),
230  CompareConnections(*it));
231  // If connection is not found in cinfo, its a missing
232  // connection
233  if (position == cinfos.end()) {
234  i++;
235  message += it->first;
236  if (!it->second.empty()) {
237  message += ":" + it->second;
238  }
239  if (i != expected_connections.size() - cinfos.size()) {
240  message += ",";
241  }
242  }
243  }
244  }
245 }
246 
247 vector<FlagInfo>
249  FlagInfo info;
250  vector<FlagInfo> infos;
251  ContextInfo c_info;
252  vector<ContextInfo> c_infos;
253  FlagState state;
254  ContextVec c_vec;
255  context_iterator c_itr;
256  for (flag_cfg_itr it = flag_infos.begin(); it != flag_infos.end(); it++) {
257  info.set_name(it->name());
258  info.set_version(it->version());
259  info.set_enabled(it->enabled());
260  info.set_state(state.ToString(it->state()));
261  c_vec = it->context_infos();
262  for (c_itr = c_vec.begin(); c_itr != c_vec.end(); c_itr++) {
263  c_info.desc = c_itr->desc;
264  c_info.value = c_itr->value;
265  c_infos.push_back(c_info);
266  }
267  info.set_context_infos(c_infos);
268  infos.push_back(info);
269  }
270  return infos;
271 }
272 
273 } // namespace process
void UpdateInternal(ConnectionType::type ctype, const std::string &name, ConnectionStatus::type status, const std::vector< Endpoint > &servers, std::string message)
static void CreateInstance(SendUveCb send_uve_cb)
boost::asio::ip::tcp::endpoint Endpoint
static std::string ToString(Type state)
bool operator()(const ConnectionInfo cinfo)
ConnectionState(SendUveCb send_uve_cb)
void GetConnectionInfoMessage(const vector< ConnectionInfo > &cinfos, const vector< ConnectionTypeName > &expected_connections, string &message)
void Delete(ConnectionType::type ctype, const std::string &name)
static boost::scoped_ptr< ConnectionState > instance_
uint8_t type
Definition: load_balance.h:109
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
void GetProcessStateCb(const vector< ConnectionInfo > &cinfos, ProcessState::type &state, string &message, const vector< ConnectionTypeName > &expected_connections)
std::vector< ConnectionInfo > GetInfosUnlocked() const
std::vector< FlagConfig > FlagConfigVec
std::pair< std::string, std::string > ConnectionTypeName
CompareConnections(const ConnectionTypeName exp_connection)
std::vector< FlagInfo > GetFlagInfos(const FlagConfigVec &flag_infos)
ConnectionTypeName expected_connection_
std::vector< FlagContext > ContextVec
std::vector< FlagContext >::const_iterator context_iterator
static ConnectionState * GetInstance()
std::vector< FlagConfig >::const_iterator flag_cfg_itr
ConnectionInfoMap connection_map_
boost::function< void(void)> SendUveCb
static boost::scoped_ptr< ConnectionStateManager > instance_
boost::tuple< ConnectionType::type, std::string > ConnectionInfoKey
std::vector< ConnectionInfo > GetInfos() const