OpenSDN source code
controller/src/control-node/main.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 
6 #include <csignal>
7 #include <fstream>
8 #include <iostream>
9 
10 #include <boost/asio/ip/host_name.hpp>
11 #include <boost/bind/bind.hpp>
12 #include <boost/date_time/posix_time/posix_time.hpp>
13 #include <boost/program_options.hpp>
14 
15 #include "nodeinfo_types.h"
16 #include "base/connection_info.h"
17 #include "base/logging.h"
18 #include "base/misc_utils.h"
19 #include "base/address_util.h"
20 #include "io/process_signal.h"
21 #include "bgp/bgp_config.h"
22 #include "bgp/bgp_config_ifmap.h"
23 #include "bgp/bgp_config_parser.h"
24 #include "bgp/bgp_ifmap_sandesh.h"
25 #include "bgp/bgp_peer.h"
26 #include "bgp/bgp_peer_types.h"
27 #include "bgp/bgp_sandesh.h"
28 #include "bgp/bgp_xmpp_sandesh.h"
29 #include "bgp/bgp_server.h"
31 #include "bgp/bgp_xmpp_channel.h"
35 #include "config_client_manager.h"
36 #include "control-node/buildinfo.h"
38 #include "control-node/options.h"
39 #include "db/db_graph.h"
41 #include "ifmap/ifmap_link_table.h"
43 #include "ifmap/ifmap_server.h"
44 #include "ifmap/ifmap_xmpp.h"
45 #include "io/event_manager.h"
46 #include "sandesh/common/vns_constants.h"
47 #include "sandesh/common/vns_types.h"
48 #include "sandesh/sandesh_http.h"
49 #include "sandesh/sandesh_trace.h"
50 #include "schema/bgp_schema_types.h"
51 #include "schema/vnc_cfg_types.h"
52 #include "xmpp/sandesh/xmpp_peer_info_types.h"
53 #include "xmpp/xmpp_init.h"
54 #include "xmpp/xmpp_sandesh.h"
55 #include "xmpp/xmpp_server.h"
56 
57 using namespace std;
58 using namespace boost::asio::ip;
59 using process::ConnectionInfo;
62 using process::ProcessState;
63 using process::ConnectionType;
65 using process::g_process_info_constants;
66 using process::Signal;
67 using namespace boost::placeholders;
68 
71 
72 static string FileRead(const char *filename) {
73  ifstream file(filename);
74  string content((istreambuf_iterator<char>(file)),
75  istreambuf_iterator<char>());
76  return content;
77 }
78 
79 static void IFMap_Initialize(IFMapServer *server, ConfigJsonParser *json_parser) {
80  IFMapLinkTable_Init(server->database(), server->graph());
81  vnc_cfg_JsonParserInit(json_parser);
82  vnc_cfg_Server_ModuleInit(server->database(), server->graph());
83  bgp_schema_JsonParserInit(json_parser);
84  bgp_schema_Server_ModuleInit(server->database(), server->graph());
85  server->Initialize();
86 }
87 
89  XmppChannelConfig *xmpp_cfg) {
90 
91  // XmppChannel Configuration
92  xmpp_cfg->endpoint.port(options->xmpp_port());
94  xmpp_cfg->auth_enabled = options->xmpp_auth_enabled();
95  xmpp_cfg->tcp_hold_time = options->tcp_hold_time();
96  xmpp_cfg->gr_helper_disable = options->gr_helper_xmpp_disable();
97 
98  if (xmpp_cfg->auth_enabled) {
99  xmpp_cfg->path_to_server_cert = options->xmpp_server_cert();
100  xmpp_cfg->path_to_server_priv_key = options->xmpp_server_key();
101  xmpp_cfg->path_to_ca_cert = options->xmpp_ca_cert();
102  }
103 
104  // Create XmppServer
105  XmppServer *xmpp_server;
106  xmpp_server = new XmppServer(evm, options->hostname(), xmpp_cfg);
107  boost::system::error_code ec;
108  IpAddress xmpp_ip_address = AddressFromString(options->host_ip(), &ec);
109  if (ec) {
110  CONTROL_NODE_EXIT("Xmpp IP Address " << options->host_ip() <<
111  " conversion error:" << ec.message());
112  }
113  if (!xmpp_server->Initialize(options->xmpp_port(), true,
114  xmpp_ip_address)) {
115  return NULL;
116  } else {
117  return (xmpp_server);
118  }
119 }
120 
121 static void WaitForIdle() {
122  static const int kTimeout = 15;
124 
125  for (int i = 0; i < (kTimeout * 1000); i++) {
126  if (scheduler->IsEmpty()) {
127  break;
128  }
129  usleep(1000);
130  }
131 }
132 
133 // Shutdown various server objects used in the control-node.
134 static void ShutdownServers(
135  boost::scoped_ptr<BgpXmppChannelManager> *channel_manager) {
136 
137  // Bring down bgp server, xmpp server, etc. in the right order.
138  BgpServer *bgp_server = (*channel_manager)->bgp_server();
139  XmppServer *xmpp_server = (*channel_manager)->xmpp_server();
140 
141  // Shutdown Xmpp server first.
142  xmpp_server->Shutdown();
143  WaitForIdle();
144 
145  // Wait until all XMPP connections are cleaned up.
146  for (int cnt = 0; xmpp_server->ConnectionCount() != 0 && cnt < 15; cnt++) {
147  sleep(1);
148  }
149 
150  // Shutdown BGP server.
151  bgp_server->Shutdown();
152  WaitForIdle();
153 
154  // Wait until all routing-instances are cleaned up.
155  for (int cnt = 0;
156  bgp_server->routing_instance_mgr()->count() != 0 && cnt < 15;
157  cnt++) {
158  sleep(1);
159  }
160 
161  channel_manager->reset();
162  TcpServerManager::DeleteServer(xmpp_server);
164 
165  ConnectionStateManager::
166  GetInstance()->Shutdown();
167 
168  // Do sandesh cleanup.
169  Sandesh::Uninit();
170  WaitForIdle();
172  WaitForIdle();
173 }
174 
175 // Trigger graceful shutdown of control-node process.
176 //
177 // IO (evm) is shutdown first. Afterwards, main() resumes, shutting down rest
178 // of the objects, and eventually exit()s.
180  static bool shutdown_;
181 
182  if (shutdown_) return;
183  shutdown_ = true;
184 
185  // Shutdown event manager first to stop all IO activities.
186  evm.Shutdown();
187 }
188 
189 static void ControlNodeGetProcessStateCb(const BgpServer *bgp_server,
190  const ConfigClientManager *config_client_manager,
191  const std::vector<ConnectionInfo> &cinfos,
192  ProcessState::type &state, std::string &message,
193  std::vector<ConnectionTypeName> expected_connections) {
194  GetProcessStateCb(cinfos, state, message, expected_connections);
196  bgp_server->admin_down(), config_client_manager->GetEndOfRibComputed(),
197  &state, &message);
198 }
199 
200 // Docker restart takes long time as control node is not handling SIGTERM
201 // its better to exit gracefully.
202 void SigTermSignalHandler(const boost::system::error_code &error, int sig,
203  bool force_reinit) {
204  CONTROL_NODE_EXIT("Received terminating signal " << sig);
205 }
206 
207 void ReConfigSignalHandler(const boost::system::error_code &error, int sig,
208  bool force_reinit) {
209  if (error) {
210  LOG(ERROR, "SIGHUP handler ERROR: " << error);
211  return;
212  }
213  LOG(WARN, "Received signal " << sig << " inside ReConfigSignalHandler()");
214  options.ParseReConfig(force_reinit);
215 }
216 
217 int main(int argc, char *argv[]) {
218  // Process options from command-line and configuration file.
219  if (!options.Parse(evm, argc, argv)) {
220  CONTROL_NODE_EXIT("Invalid command line arguments");
221  }
222 
223  srand(unsigned(time(NULL)));
224  std::vector<Signal::SignalHandler> sighup_handlers = boost::assign::list_of
225  (boost::bind(&ReConfigSignalHandler, _1, _2, false));
226  std::vector<Signal::SignalHandler> sigusr1_handlers = boost::assign::list_of
227  (boost::bind(&ReConfigSignalHandler, _1, _2, true));
228  std::vector<Signal::SignalHandler> sigterm_handler = boost::assign::list_of
229  (boost::bind(&SigTermSignalHandler, _1, _2, true));
230  Signal::SignalCallbackMap smap = boost::assign::map_list_of
231  (SIGHUP, sighup_handlers)
232  (SIGUSR1, sigusr1_handlers)
233  (SIGTERM, sigterm_handler);
234  Signal signal(&evm, smap);
235 
236  Logging logging;
237 
239  Module::type module = Module::CONTROL_NODE;
240  string module_name = g_vns_constants.ModuleNames.find(module)->second;
241  std::string log_property_file = options.log_property_file();
242  if (log_property_file.size()) {
243  logging.Init(log_property_file);
244  } else {
245  logging.Init(options.log_file(), options.log_file_size(),
246  options.log_files_count(), options.use_syslog(),
247  options.syslog_facility(), module_name,
249  Sandesh::StringToLevel(options.log_level())));
250  }
251 
252  int num_threads_to_tbb = TaskScheduler::GetDefaultThreadCount() +
254  TaskScheduler::Initialize(num_threads_to_tbb, &evm);
256  options.task_track_run_time());
259 
260  BgpSandeshContext sandesh_context;
261  RegisterSandeshShowIfmapHandlers(&sandesh_context);
262  RegisterSandeshShowXmppExtensions(&sandesh_context);
263  Sandesh::SetLoggingParams(options.log_local(), options.log_category(),
264  options.log_level());
265 
266  // Disable logging -- for test purposes only.
267  if (options.log_disable()) {
268  SetLoggingDisabled(true);
269  }
270 
271  ControlNode::SetSelfIp(options.host_ip());
272 
273  ControlNode::SetTestMode(options.test_mode());
274 
277  boost::scoped_ptr<BgpServer> bgp_server(new BgpServer(&evm));
278  sandesh_context.set_test_mode(ControlNode::GetTestMode());
279  sandesh_context.bgp_server = bgp_server.get();
280  bgp_server->set_gr_helper_disable(options.gr_helper_bgp_disable());
281  bgp_server->set_mvpn_ipv4_enable(options.mvpn_ipv4_enable());
282 
283  ConnectionStateManager::GetInstance();
284 
285  DB config_db(TaskScheduler::GetInstance()->GetTaskId("db::IFMapTable"));
286  DBGraph config_graph;
287  IFMapServer ifmap_server(&config_db, &config_graph, evm.io_service());
288 
290  ConfigJsonParser>();
291 
292  boost::scoped_ptr<ConfigClientManager> config_client_manager_ptr(
294  ConfigStaticObjectFactory::Create<ConfigJsonParserBase>(),
295  options.hostname(),
296  module_name,
297  options.configdb_options()));
298  ConfigClientManager *config_client_manager = config_client_manager_ptr.get();
299  ConfigJsonParser *json_parser = static_cast<ConfigJsonParser *>(
300  config_client_manager->config_json_parser());
301  json_parser->ifmap_server_set(&ifmap_server);
302  IFMap_Initialize(&ifmap_server, json_parser);
303  ifmap_server.set_config_manager(config_client_manager);
304 
305  BgpIfmapConfigManager *config_manager =
306  static_cast<BgpIfmapConfigManager *>(bgp_server->config_manager());
307  config_manager->Initialize(&config_db, &config_graph, options.hostname());
308  ControlNode::SetHostname(options.hostname());
309  BgpConfigParser parser(&config_db);
310  parser.Parse(FileRead(options.bgp_config_file().c_str()));
311 
312  boost::system::error_code ec;
313  IpAddress bgp_ip_address = AddressFromString(options.host_ip(), &ec);
314  if (ec) {
315  CONTROL_NODE_EXIT("BGP IP Address " << options.host_ip() <<
316  " conversion error: " << ec.message());
317  }
318  bgp_server->rtarget_group_mgr()->Initialize();
319  bgp_server->session_manager()->Initialize(options.bgp_port(),
320  bgp_ip_address);
321 
322  // Create Xmpp Server.
323  XmppChannelConfig xmpp_cfg(false);
324  xmpp_cfg.dscp_value = bgp_server->global_qos()->control_dscp();
325  XmppServer *xmpp_server = CreateXmppServer(&evm, &options, &xmpp_cfg);
326  if (xmpp_server == NULL) {
327  CONTROL_NODE_EXIT("XmppServer creation failed");
328  }
329 
330  // Create BGP and IFMap channel managers.
331  boost::scoped_ptr<BgpXmppChannelManager> bgp_peer_manager(
332  new BgpXmppChannelManager(xmpp_server, bgp_server.get()));
333  sandesh_context.xmpp_peer_manager = bgp_peer_manager.get();
334  IFMapChannelManager ifmap_channel_mgr(xmpp_server, &ifmap_server);
335  ifmap_server.set_ifmap_channel_manager(&ifmap_channel_mgr);
336 
337  XmppSandeshContext xmpp_sandesh_context;
338  xmpp_sandesh_context.xmpp_server = xmpp_server;
339  Sandesh::set_module_context("XMPP", &xmpp_sandesh_context);
340  IFMapSandeshContext ifmap_sandesh_context(&ifmap_server);
341  Sandesh::set_module_context("IFMap", &ifmap_sandesh_context);
342 
343  // Determine if the number of connections is as expected. At the moment,
344  // consider connections to collector, cassandra and rabbit servers
345  //
346  // 1. Collector client
347  // 2. Cassandra Server
348  // 3. AMQP Server
349  std::vector<ConnectionTypeName> expected_connections;
350  expected_connections = boost::assign::list_of
351  (ConnectionTypeName(g_process_info_constants.ConnectionTypeNames.find(
352  ConnectionType::DATABASE)->second, "Cassandra"))
353  (ConnectionTypeName(g_process_info_constants.ConnectionTypeNames.find(
354  ConnectionType::DATABASE)->second, "RabbitMQ"))
355  (ConnectionTypeName(g_process_info_constants.ConnectionTypeNames.find(
356  ConnectionType::COLLECTOR)->second, ""))
357  .convert_to_container<vector<\
358  ConnectionTypeName> >();
359 
360  if (!options.collectors_configured()) {
361  LOG(INFO, "Collectors are not configured!");
362  expected_connections.pop_back();
363  }
364 
365  ConnectionStateManager::GetInstance()->Init(
366  *evm.io_service(), options.hostname(),
367  module_name, g_vns_constants.INSTANCE_ID_DEFAULT,
368  boost::bind(&ControlNodeGetProcessStateCb,
369  bgp_server.get(), config_client_manager, _1, _2, _3,
370  expected_connections), "ObjectBgpRouter");
371 
372  NodeType::type node_type =
373  g_vns_constants.Module2NodeType.find(module)->second;
374  bool success;
375  if (options.collectors_configured()) {
376  success = Sandesh::InitGenerator(
377  module_name,
378  options.hostname(),
379  g_vns_constants.NodeTypeNames.find(node_type)->second,
380  g_vns_constants.INSTANCE_ID_DEFAULT,
381  &evm,
382  options.http_server_port(),
383  options.randomized_collector_server_list(),
384  &sandesh_context,
386  options.sandesh_config());
387  } else {
388  success = Sandesh::InitGenerator(
389  g_vns_constants.ModuleNames.find(module)->second,
390  options.hostname(),
391  g_vns_constants.NodeTypeNames.find(node_type)->second,
392  g_vns_constants.INSTANCE_ID_DEFAULT,
393  &evm,
394  options.http_server_port(),
395  &sandesh_context,
397  options.sandesh_config());
398  }
399  if (!success) {
400  Sandesh::Uninit();
401  CONTROL_NODE_EXIT("Sandesh initialization failed");
402  }
403 
404  // Set BuildInfo.
406  bgp_server.get(),
407  bgp_peer_manager.get(),
408  &ifmap_server, BuildInfo);
409 
410  options.set_config_client_manager(config_client_manager);
411  config_client_manager->Initialize();
412 
413  // Event loop.
414  evm.Run();
415 
416  signal.Terminate();
417  ShutdownServers(&bgp_peer_manager);
419  return 0;
420 }
boost::asio::ip::address IpAddress
Definition: address.h:13
IpAddress AddressFromString(const std::string &ip_address_str, boost::system::error_code *ec)
void RegisterSandeshShowIfmapHandlers(BgpSandeshContext *bsc)
void RegisterSandeshShowXmppExtensions(BgpSandeshContext *bsc)
void Initialize(DB *db, DBGraph *db_graph, const std::string &localname)
static void Initialize()
Definition: bgp_server.cc:556
RoutingInstanceMgr * routing_instance_mgr()
Definition: bgp_server.h:106
void set_gr_helper_disable(bool gr_helper_disable)
Definition: bgp_server.h:303
bool HasSelfConfiguration() const
Definition: bgp_server.cc:576
void Shutdown()
Definition: bgp_server.cc:568
static void Terminate()
Definition: bgp_server.cc:560
bool admin_down() const
Definition: bgp_server.h:209
ConfigJsonParserBase * config_json_parser()
void ifmap_server_set(IFMapServer *ifmap_server)
static std::string GetProcessState(bool bgpHasSelfConfiguration, bool bgpIsAdminDown, bool configEndOfRibComputed, process::ProcessState::type *state, std::string *message)
static void SetSelfIp(std::string ip)
Definition: control_node.h:34
static void SetTestMode(const bool flag)
Definition: control_node.h:35
static void StartControlNodeInfoLogger(EventManager &evm, uint64_t period_msecs, const BgpServer *server, const BgpXmppChannelManager *xmpp_channel_mgr, const IFMapServer *ifmap_server, const string &build_info)
static void Shutdown()
static void SetHostname(const std::string name)
Definition: control_node.h:29
static void SetProgramName(const char *name)
Definition: control_node.h:32
static void SetDefaultSchedulingPolicy()
Definition: control_node.cc:19
static bool GetTestMode()
Definition: control_node.h:36
Definition: db.h:24
boost::asio::io_context * io_service()
Definition: event_manager.h:42
void Initialize()
DB * database()
Definition: ifmap_server.h:82
DBGraph * graph()
Definition: ifmap_server.h:83
A class providing basic control over logging capabilities in OpenSDN control plane.
Definition: logging.h:43
void Init()
Performs basic initialization of the logging system ( log4cplus).
Definition: logging.cc:31
static void Uninit(void)
static void set_module_context(const std::string &module_name, SandeshContext *context)
Definition: sandesh.cc:958
static bool InitGenerator(const std::string &module, const std::string &source, const std::string &node_type, const std::string &instance_id, EventManager *evm, unsigned short http_port, const std::vector< std::string > &collectors, SandeshContext *client_context=NULL, DerivedStats ds=DerivedStats(), const SandeshConfig &config=SandeshConfig())
Definition: sandesh.cc:272
std::map< std::string, std::map< std::string, std::string > > DerivedStats
Definition: cpp/sandesh.h:150
static void Uninit()
Definition: sandesh.cc:342
static void SetLoggingParams(bool enable_local_log, std::string category, std::string level, bool enable_trace_print=false, bool enable_flow_log=false, bool enable_session_syslog=false)
Definition: sandesh.cc:370
static SandeshLevel::type StringToLevel(std::string level)
Definition: sandesh.cc:862
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:304
static int GetDefaultThreadCount()
Definition: task.cc:436
void SetTrackRunTime(bool value)
Definition: task.h:422
static void Initialize(uint32_t thread_count=0, EventManager *evm=NULL)
Definition: task.cc:485
static TaskScheduler * GetInstance()
Definition: task.cc:554
bool IsEmpty(bool running_only=false)
Returns true if there are no tasks running and/or enqueued If running_only is true,...
Definition: task.cc:828
static void DeleteServer(TcpServer *server)
Definition: tcp_server.cc:658
std::string FromAddr
Definition: xmpp_config.h:21
boost::asio::ip::tcp::endpoint endpoint
Definition: xmpp_config.h:24
std::string path_to_ca_cert
Definition: xmpp_config.h:30
std::string path_to_server_cert
Definition: xmpp_config.h:28
std::string path_to_server_priv_key
Definition: xmpp_config.h:29
static const char * kControlNodeJID
Definition: xmpp_init.h:17
size_t ConnectionCount() const
Definition: xmpp_server.cc:405
void Shutdown()
Definition: xmpp_server.cc:339
virtual bool Initialize(short port)
Definition: xmpp_server.cc:300
#define CONTROL_NODE_EXIT(message)
Definition: control_node.h:20
static Options options
static void IFMap_Initialize(IFMapServer *server, ConfigJsonParser *json_parser)
void SigTermSignalHandler(const boost::system::error_code &error, int sig, bool force_reinit)
static EventManager evm
void ReConfigSignalHandler(const boost::system::error_code &error, int sig, bool force_reinit)
static string FileRead(const char *filename)
static void ShutdownServers(boost::scoped_ptr< BgpXmppChannelManager > *channel_manager)
static void ControlNodeGetProcessStateCb(const BgpServer *bgp_server, const ConfigClientManager *config_client_manager, const std::vector< ConnectionInfo > &cinfos, ProcessState::type &state, std::string &message, std::vector< ConnectionTypeName > expected_connections)
static void WaitForIdle()
static XmppServer * CreateXmppServer(EventManager *evm, Options *options, XmppChannelConfig *xmpp_cfg)
uint8_t type
Definition: load_balance.h:2
void SetLoggingDisabled(bool flag)
Definition: logging.cc:59
#define LOG(_Level, _Msg)
Definition: logging.h:34
void GetProcessStateCb(const vector< ConnectionInfo > &cinfos, ProcessState::type &state, string &message, const vector< ConnectionTypeName > &expected_connections)
std::pair< std::string, std::string > ConnectionTypeName
log4cplus::LogLevel SandeshLevelTolog4Level(SandeshLevel::type slevel)
Definition: sandesh.cc:396
BgpXmppChannelManager * xmpp_peer_manager
Definition: bgp_sandesh.h:47
BgpServer * bgp_server
Definition: bgp_sandesh.h:46
void set_test_mode(bool test_mode)
Definition: bgp_sandesh.h:62
static void LinkImpl()
Definition: factory.h:68
XmppServer * xmpp_server
Definition: xmpp_sandesh.h:16
const std::string BuildInfo