corosync  3.1.10
exec/cfg.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005-2006 MontaVista Software, Inc.
3  * Copyright (c) 2006-2018 Red Hat, Inc.
4  *
5  * All rights reserved.
6  *
7  * Author: Steven Dake (sdake@redhat.com)
8  *
9  * This software licensed under BSD license, the text of which follows:
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  *
14  * - Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  * - Redistributions in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  * - Neither the name of the MontaVista Software, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived from this
21  * software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 
38 #ifdef HAVE_ALLOCA_H
39 #include <alloca.h>
40 #endif
41 
42 #include <sys/types.h>
43 #include <sys/uio.h>
44 #include <sys/socket.h>
45 #include <sys/un.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stddef.h>
53 #include <limits.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <assert.h>
57 
58 #include <corosync/corotypes.h>
59 #include <qb/qbipc_common.h>
60 #include <corosync/cfg.h>
61 #include <qb/qblist.h>
62 #include <qb/qbutil.h>
63 #include <corosync/mar_gen.h>
64 #include <corosync/totem/totemip.h>
65 #include <corosync/totem/totem.h>
66 #include <corosync/ipc_cfg.h>
67 #include <corosync/logsys.h>
68 #include <corosync/coroapi.h>
69 #include <corosync/icmap.h>
70 #include <corosync/corodefs.h>
71 
72 #include "totemconfig.h"
73 #include "totemknet.h"
74 #include "service.h"
75 #include "main.h"
76 
77 LOGSYS_DECLARE_SUBSYS ("CFG");
78 
85 };
86 
87 /* in milliseconds */
88 #define DEFAULT_SHUTDOWN_TIMEOUT 5000
89 
90 static struct qb_list_head trackers_list;
91 
92 /*
93  * Variables controlling a requested shutdown
94  */
95 static corosync_timer_handle_t shutdown_timer;
96 static struct cfg_info *shutdown_con;
97 static uint32_t shutdown_flags;
98 static int shutdown_yes;
99 static int shutdown_no;
100 static int shutdown_expected;
101 
102 struct cfg_info
103 {
104  struct qb_list_head list;
105  void *conn;
108 };
109 
110 static void cfg_confchg_fn (
111  enum totem_configuration_type configuration_type,
112  const unsigned int *member_list, size_t member_list_entries,
113  const unsigned int *left_list, size_t left_list_entries,
114  const unsigned int *joined_list, size_t joined_list_entries,
115  const struct memb_ring_id *ring_id);
116 
117 static char *cfg_exec_init_fn (struct corosync_api_v1 *corosync_api_v1);
118 
119 static struct corosync_api_v1 *api;
120 
121 static int cfg_lib_init_fn (void *conn);
122 
123 static int cfg_lib_exit_fn (void *conn);
124 
125 static void message_handler_req_exec_cfg_ringreenable (
126  const void *message,
127  unsigned int nodeid);
128 
129 static void message_handler_req_exec_cfg_killnode (
130  const void *message,
131  unsigned int nodeid);
132 
133 static void message_handler_req_exec_cfg_shutdown (
134  const void *message,
135  unsigned int nodeid);
136 
137 static void message_handler_req_exec_cfg_reload_config (
138  const void *message,
139  unsigned int nodeid);
140 
141 static void message_handler_req_exec_cfg_reconfig_crypto (
142  const void *message,
143  unsigned int nodeid);
144 
145 static void exec_cfg_killnode_endian_convert (void *msg);
146 
147 static void message_handler_req_lib_cfg_ringstatusget (
148  void *conn,
149  const void *msg);
150 
151 static void message_handler_req_lib_cfg_nodestatusget (
152  void *conn,
153  const void *msg);
154 
155 static void message_handler_req_lib_cfg_ringreenable (
156  void *conn,
157  const void *msg);
158 
159 static void message_handler_req_lib_cfg_killnode (
160  void *conn,
161  const void *msg);
162 
163 static void message_handler_req_lib_cfg_tryshutdown (
164  void *conn,
165  const void *msg);
166 
167 static void message_handler_req_lib_cfg_replytoshutdown (
168  void *conn,
169  const void *msg);
170 
171 static void message_handler_req_lib_cfg_trackstart (
172  void *conn,
173  const void *msg);
174 
175 static void message_handler_req_lib_cfg_trackstop (
176  void *conn,
177  const void *msg);
178 
179 static void message_handler_req_lib_cfg_get_node_addrs (
180  void *conn,
181  const void *msg);
182 
183 static void message_handler_req_lib_cfg_local_get (
184  void *conn,
185  const void *msg);
186 
187 static void message_handler_req_lib_cfg_reload_config (
188  void *conn,
189  const void *msg);
190 
191 static void message_handler_req_lib_cfg_reopen_log_files (
192  void *conn,
193  const void *msg);
194 
195 /*
196  * Service Handler Definition
197  */
198 static struct corosync_lib_handler cfg_lib_engine[] =
199 {
200  { /* 0 */
201  .lib_handler_fn = message_handler_req_lib_cfg_ringstatusget,
202  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
203  },
204  { /* 1 */
205  .lib_handler_fn = message_handler_req_lib_cfg_ringreenable,
206  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
207  },
208  { /* 2 */
209  .lib_handler_fn = message_handler_req_lib_cfg_killnode,
210  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
211  },
212  { /* 3 */
213  .lib_handler_fn = message_handler_req_lib_cfg_tryshutdown,
214  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
215  },
216  { /* 4 */
217  .lib_handler_fn = message_handler_req_lib_cfg_replytoshutdown,
218  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
219  },
220  { /* 5 */
221  .lib_handler_fn = message_handler_req_lib_cfg_get_node_addrs,
222  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
223  },
224  { /* 6 */
225  .lib_handler_fn = message_handler_req_lib_cfg_local_get,
226  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
227  },
228  { /* 7 */
229  .lib_handler_fn = message_handler_req_lib_cfg_reload_config,
230  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
231  },
232  { /* 8 */
233  .lib_handler_fn = message_handler_req_lib_cfg_reopen_log_files,
234  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
235  },
236  { /* 9 */
237  .lib_handler_fn = message_handler_req_lib_cfg_nodestatusget,
238  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
239  },
240  { /* 10 */
241  .lib_handler_fn = message_handler_req_lib_cfg_trackstart,
242  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
243  },
244  { /* 11 */
245  .lib_handler_fn = message_handler_req_lib_cfg_trackstop,
246  .flow_control = CS_LIB_FLOW_CONTROL_REQUIRED
247  },
248 
249 };
250 
251 static struct corosync_exec_handler cfg_exec_engine[] =
252 {
253  { /* 0 */
254  .exec_handler_fn = message_handler_req_exec_cfg_ringreenable,
255  },
256  { /* 1 */
257  .exec_handler_fn = message_handler_req_exec_cfg_killnode,
258  .exec_endian_convert_fn = exec_cfg_killnode_endian_convert
259  },
260  { /* 2 */
261  .exec_handler_fn = message_handler_req_exec_cfg_shutdown,
262  },
263  { /* 3 */
264  .exec_handler_fn = message_handler_req_exec_cfg_reload_config,
265  },
266  { /* 4 */
267  .exec_handler_fn = message_handler_req_exec_cfg_reconfig_crypto,
268  }
269 };
270 
271 /*
272  * Exports the interface for the service
273  */
275  .name = "corosync configuration service",
276  .id = CFG_SERVICE,
277  .priority = 1,
278  .private_data_size = sizeof(struct cfg_info),
279  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED,
280  .allow_inquorate = CS_LIB_ALLOW_INQUORATE,
281  .lib_init_fn = cfg_lib_init_fn,
282  .lib_exit_fn = cfg_lib_exit_fn,
283  .lib_engine = cfg_lib_engine,
284  .lib_engine_count = sizeof (cfg_lib_engine) / sizeof (struct corosync_lib_handler),
285  .exec_init_fn = cfg_exec_init_fn,
286  .exec_engine = cfg_exec_engine,
287  .exec_engine_count = sizeof (cfg_exec_engine) / sizeof (struct corosync_exec_handler),
288  .confchg_fn = cfg_confchg_fn
289 };
290 
292 {
293  return (&cfg_service_engine);
294 }
295 
297  struct qb_ipc_request_header header __attribute__((aligned(8)));
298  mar_message_source_t source __attribute__((aligned(8)));
299 };
300 
302  struct qb_ipc_request_header header __attribute__((aligned(8)));
303  mar_message_source_t source __attribute__((aligned(8)));
304 };
305 
307  struct qb_ipc_request_header header __attribute__((aligned(8)));
308  mar_uint32_t phase __attribute__((aligned(8)));
309 };
310 
312  struct qb_ipc_request_header header __attribute__((aligned(8)));
313  mar_uint32_t nodeid __attribute__((aligned(8)));
314  mar_name_t reason __attribute__((aligned(8)));
315 };
316 
318  struct qb_ipc_request_header header __attribute__((aligned(8)));
319 };
320 
321 /* IMPL */
322 
323 static char *cfg_exec_init_fn (
325 {
326  api = corosync_api_v1;
327 
328  qb_list_init(&trackers_list);
329  return (NULL);
330 }
331 
332 static void cfg_confchg_fn (
333  enum totem_configuration_type configuration_type,
334  const unsigned int *member_list, size_t member_list_entries,
335  const unsigned int *left_list, size_t left_list_entries,
336  const unsigned int *joined_list, size_t joined_list_entries,
337  const struct memb_ring_id *ring_id)
338 {
339 }
340 
341 /*
342  * Tell other nodes we are shutting down
343  */
344 static int send_shutdown(void)
345 {
347  struct iovec iovec;
348 
349  ENTER();
350  req_exec_cfg_shutdown.header.size =
351  sizeof (struct req_exec_cfg_shutdown);
354 
355  iovec.iov_base = (char *)&req_exec_cfg_shutdown;
356  iovec.iov_len = sizeof (struct req_exec_cfg_shutdown);
357 
358  assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
359 
360  LEAVE();
361  return 0;
362 }
363 
364 static void send_test_shutdown(void *only_conn, void *exclude_conn, int status)
365 {
367  struct qb_list_head *iter;
368 
369  ENTER();
370  res_lib_cfg_testshutdown.header.size = sizeof(struct res_lib_cfg_testshutdown);
372  res_lib_cfg_testshutdown.header.error = status;
373  res_lib_cfg_testshutdown.flags = shutdown_flags;
374 
375  if (only_conn) {
376  TRACE1("sending testshutdown to only %p", only_conn);
378  sizeof(res_lib_cfg_testshutdown));
379  } else {
380  qb_list_for_each(iter, &trackers_list) {
381  struct cfg_info *ci = qb_list_entry(iter, struct cfg_info, list);
382 
383  if (ci->conn != exclude_conn) {
384  TRACE1("sending testshutdown to %p", ci->tracker_conn);
386  sizeof(res_lib_cfg_testshutdown));
387  }
388  }
389  }
390  LEAVE();
391 }
392 
393 static void check_shutdown_status(void)
394 {
395  ENTER();
396 
397  /*
398  * Shutdown client might have gone away
399  */
400  if (!shutdown_con) {
401  LEAVE();
402  return;
403  }
404 
405  /*
406  * All replies safely gathered in ?
407  */
408  if (shutdown_yes + shutdown_no >= shutdown_expected) {
410 
411  api->timer_delete(shutdown_timer);
412 
413  if (shutdown_yes >= shutdown_expected ||
414  shutdown_flags == CFG_SHUTDOWN_FLAG_REGARDLESS) {
415  TRACE1("shutdown confirmed");
416 
417  res_lib_cfg_tryshutdown.header.size = sizeof(struct res_lib_cfg_tryshutdown);
419  res_lib_cfg_tryshutdown.header.error = CS_OK;
420 
421  /*
422  * Tell originator that shutdown was confirmed
423  */
424  api->ipc_response_send(shutdown_con->conn, &res_lib_cfg_tryshutdown,
425  sizeof(res_lib_cfg_tryshutdown));
426  shutdown_con = NULL;
427 
428  /*
429  * Tell other nodes we are going down
430  */
431  send_shutdown();
432 
433  }
434  else {
435 
436  TRACE1("shutdown cancelled");
437  res_lib_cfg_tryshutdown.header.size = sizeof(struct res_lib_cfg_tryshutdown);
439  res_lib_cfg_tryshutdown.header.error = CS_ERR_BUSY;
440 
441  /*
442  * Tell originator that shutdown was cancelled
443  */
444  api->ipc_response_send(shutdown_con->conn, &res_lib_cfg_tryshutdown,
445  sizeof(res_lib_cfg_tryshutdown));
446  shutdown_con = NULL;
447  }
448 
449  log_printf(LOGSYS_LEVEL_DEBUG, "shutdown decision is: (yes count: %d, no count: %d) flags=%x",
450  shutdown_yes, shutdown_no, shutdown_flags);
451  }
452  LEAVE();
453 }
454 
455 
456 /*
457  * Not all nodes responded to the shutdown (in time)
458  */
459 static void shutdown_timer_fn(void *arg)
460 {
461  ENTER();
462 
463  /*
464  * Mark undecideds as "NO"
465  */
466  shutdown_no = shutdown_expected;
467  check_shutdown_status();
468 
469  send_test_shutdown(NULL, NULL, CS_ERR_TIMEOUT);
470  LEAVE();
471 }
472 
473 static void remove_ci_from_shutdown(struct cfg_info *ci)
474 {
475  ENTER();
476 
477  /*
478  * If the controlling shutdown process has quit, then cancel the
479  * shutdown session
480  */
481  if (ci == shutdown_con) {
482  shutdown_con = NULL;
483  api->timer_delete(shutdown_timer);
484  }
485 
486  if (!qb_list_empty(&ci->list)) {
487  qb_list_del(&ci->list);
488  qb_list_init(&ci->list);
489 
490  /*
491  * Remove our option
492  */
493  if (shutdown_con) {
494  if (ci->shutdown_reply == SHUTDOWN_REPLY_YES)
495  shutdown_yes--;
496  if (ci->shutdown_reply == SHUTDOWN_REPLY_NO)
497  shutdown_no--;
498  }
499 
500  /*
501  * If we are leaving, then that's an implicit YES to shutdown
502  */
503  ci->shutdown_reply = SHUTDOWN_REPLY_YES;
504  shutdown_yes++;
505 
506  check_shutdown_status();
507  }
508  LEAVE();
509 }
510 
511 
512 int cfg_lib_exit_fn (void *conn)
513 {
514  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
515 
516  ENTER();
517  remove_ci_from_shutdown(ci);
518  LEAVE();
519  return (0);
520 }
521 
522 static int cfg_lib_init_fn (void *conn)
523 {
524  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
525 
526  ENTER();
527  qb_list_init(&ci->list);
528  LEAVE();
529 
530  return (0);
531 }
532 
533 /*
534  * Executive message handlers
535  */
536 static void message_handler_req_exec_cfg_ringreenable (
537  const void *message,
538  unsigned int nodeid)
539 {
540  ENTER();
541 
542  LEAVE();
543 }
544 
545 static void exec_cfg_killnode_endian_convert (void *msg)
546 {
548  (struct req_exec_cfg_killnode *)msg;
549  ENTER();
550 
551  swab_mar_name_t(&req_exec_cfg_killnode->reason);
552  LEAVE();
553 }
554 
555 
556 static void message_handler_req_exec_cfg_killnode (
557  const void *message,
558  unsigned int nodeid)
559 {
560  const struct req_exec_cfg_killnode *req_exec_cfg_killnode = message;
561  cs_name_t reason;
562 
563  ENTER();
564  log_printf(LOGSYS_LEVEL_DEBUG, "request to kill node " CS_PRI_NODE_ID " (us=" CS_PRI_NODE_ID ")",
565  req_exec_cfg_killnode->nodeid, api->totem_nodeid_get());
566  if (req_exec_cfg_killnode->nodeid == api->totem_nodeid_get()) {
567  marshall_from_mar_name_t(&reason, &req_exec_cfg_killnode->reason);
568  log_printf(LOGSYS_LEVEL_NOTICE, "Killed by node " CS_PRI_NODE_ID " : %s",
569  nodeid, reason.value);
571  }
572  LEAVE();
573 }
574 
575 /*
576  * Self shutdown
577  */
578 static void message_handler_req_exec_cfg_shutdown (
579  const void *message,
580  unsigned int nodeid)
581 {
582  ENTER();
583 
584  log_printf(LOGSYS_LEVEL_NOTICE, "Node " CS_PRI_NODE_ID " was shut down by sysadmin", nodeid);
585  if (nodeid == api->totem_nodeid_get()) {
586  api->shutdown_request();
587  }
588  LEAVE();
589 }
590 
591 /* strcmp replacement that can handle NULLs */
592 static int nullcheck_strcmp(const char* left, const char *right)
593 {
594  if (!left && right)
595  return -1;
596  if (left && !right)
597  return 1;
598 
599  if (!left && !right)
600  return 0;
601 
602  return strcmp(left, right);
603 }
604 
605 /*
606  * If a key has changed value in the new file, then warn the user and remove it from the temp_map
607  */
608 static void delete_and_notify_if_changed(icmap_map_t temp_map, const char *key_name)
609 {
610  if (!(icmap_key_value_eq(temp_map, key_name, icmap_get_global_map(), key_name))) {
611  if (icmap_delete_r(temp_map, key_name) == CS_OK) {
612  log_printf(LOGSYS_LEVEL_NOTICE, "Modified entry '%s' in corosync.conf cannot be changed at run-time", key_name);
613  }
614  }
615 }
616 /*
617  * Remove any keys from the new config file that in the new corosync.conf but that
618  * cannot be changed at run time. A log message will be issued for each
619  * entry that the user wants to change but they cannot.
620  *
621  * Add more here as needed.
622  */
623 static void remove_ro_entries(icmap_map_t temp_map)
624 {
625 #ifndef HAVE_KNET_CRYPTO_RECONF
626  delete_and_notify_if_changed(temp_map, "totem.secauth");
627  delete_and_notify_if_changed(temp_map, "totem.crypto_hash");
628  delete_and_notify_if_changed(temp_map, "totem.crypto_cipher");
629  delete_and_notify_if_changed(temp_map, "totem.keyfile");
630  delete_and_notify_if_changed(temp_map, "totem.key");
631 #endif
632  delete_and_notify_if_changed(temp_map, "totem.version");
633  delete_and_notify_if_changed(temp_map, "totem.threads");
634  delete_and_notify_if_changed(temp_map, "totem.ip_version");
635  delete_and_notify_if_changed(temp_map, "totem.ip_dscp");
636  delete_and_notify_if_changed(temp_map, "totem.netmtu");
637  delete_and_notify_if_changed(temp_map, "totem.interface.bindnetaddr");
638  delete_and_notify_if_changed(temp_map, "totem.interface.mcastaddr");
639  delete_and_notify_if_changed(temp_map, "totem.interface.broadcast");
640  delete_and_notify_if_changed(temp_map, "totem.interface.mcastport");
641  delete_and_notify_if_changed(temp_map, "totem.interface.ttl");
642  delete_and_notify_if_changed(temp_map, "totem.transport");
643  delete_and_notify_if_changed(temp_map, "totem.cluster_name");
644  delete_and_notify_if_changed(temp_map, "quorum.provider");
645  delete_and_notify_if_changed(temp_map, "system.move_to_root_cgroup");
646  delete_and_notify_if_changed(temp_map, "system.allow_knet_handle_fallback");
647  delete_and_notify_if_changed(temp_map, "system.sched_rr");
648  delete_and_notify_if_changed(temp_map, "system.priority");
649  delete_and_notify_if_changed(temp_map, "system.qb_ipc_type");
650  delete_and_notify_if_changed(temp_map, "system.state_dir");
651 }
652 
653 /*
654  * Remove entries that exist in the global map, but not in the temp_map, this will
655  * cause delete notifications to be sent to any listeners.
656  *
657  * NOTE: This routine depends entirely on the keys returned by the iterators
658  * being in alpha-sorted order.
659  */
660 static void remove_deleted_entries(icmap_map_t temp_map, const char *prefix)
661 {
662  icmap_iter_t old_iter;
663  icmap_iter_t new_iter;
664  const char *old_key, *new_key;
665  int ret;
666 
667  old_iter = icmap_iter_init(prefix);
668  new_iter = icmap_iter_init_r(temp_map, prefix);
669 
670  old_key = icmap_iter_next(old_iter, NULL, NULL);
671  new_key = icmap_iter_next(new_iter, NULL, NULL);
672 
673  while (old_key || new_key) {
674  ret = nullcheck_strcmp(old_key, new_key);
675  if ((ret < 0 && old_key) || !new_key) {
676  /*
677  * new_key is greater, a line (or more) has been deleted
678  * Continue until old is >= new
679  */
680  do {
681  /* Remove it from icmap & send notifications */
682  icmap_delete(old_key);
683 
684  old_key = icmap_iter_next(old_iter, NULL, NULL);
685  ret = nullcheck_strcmp(old_key, new_key);
686  } while (ret < 0 && old_key);
687  }
688  else if ((ret > 0 && new_key) || !old_key) {
689  /*
690  * old_key is greater, a line (or more) has been added
691  * Continue until new is >= old
692  *
693  * we don't need to do anything special with this like tell
694  * icmap. That will happen when we copy the values over
695  */
696  do {
697  new_key = icmap_iter_next(new_iter, NULL, NULL);
698  ret = nullcheck_strcmp(old_key, new_key);
699  } while (ret > 0 && new_key);
700  }
701  if (ret == 0) {
702  new_key = icmap_iter_next(new_iter, NULL, NULL);
703  old_key = icmap_iter_next(old_iter, NULL, NULL);
704  }
705  }
706  icmap_iter_finalize(new_iter);
707  icmap_iter_finalize(old_iter);
708 }
709 
710 /*
711  * Reload configuration file
712  */
713 static void message_handler_req_exec_cfg_reload_config (
714  const void *message,
715  unsigned int nodeid)
716 {
719  struct totem_config new_config;
720  icmap_map_t temp_map;
721  const char *error_string;
722  int res = CS_OK;
723 
724  ENTER();
725 
726  log_printf(LOGSYS_LEVEL_NOTICE, "Config reload requested by node " CS_PRI_NODE_ID, nodeid);
727 
728  // Clear this out in case it all goes well
729  icmap_delete("config.reload_error_message");
730 
731  icmap_set_uint8("config.totemconfig_reload_in_progress", 1);
732 
733  /* Make sure there is no rubbish in this that might be checked, even on error */
734  memset(&new_config, 0, sizeof(new_config));
735  /*
736  * Set up a new hashtable as a staging area.
737  */
738  if ((res = icmap_init_r(&temp_map)) != CS_OK) {
739  log_printf(LOGSYS_LEVEL_ERROR, "Unable to create temporary icmap. config file reload cancelled\n");
740  goto reload_fini_nomap;
741  }
742 
743  /*
744  * Load new config into the temporary map
745  */
746  res = coroparse_configparse(temp_map, &error_string);
747  if (res == -1) {
748  log_printf (LOGSYS_LEVEL_ERROR, "Unable to reload config file: %s", error_string);
749  res = CS_ERR_INVALID_PARAM;
750  goto reload_fini_nofree;
751  }
752 
753  /* Signal start of the reload process */
754  icmap_set_uint8("config.reload_in_progress", 1);
755 
756  /* Detect deleted entries and remove them from the main icmap hashtable */
757  remove_deleted_entries(temp_map, "logging.");
758  remove_deleted_entries(temp_map, "totem.");
759  remove_deleted_entries(temp_map, "nodelist.");
760  remove_deleted_entries(temp_map, "quorum.");
761  remove_deleted_entries(temp_map, "uidgid.config.");
762  remove_deleted_entries(temp_map, "nozzle.");
763 
764  /* Remove entries that cannot be changed */
765  remove_ro_entries(temp_map);
766 
767  /* Take a copy of the current setup so we can check what has changed */
768  memset(&new_config, 0, sizeof(new_config));
769  new_config.orig_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
770  assert(new_config.orig_interfaces != NULL);
771 
772  totempg_get_config(&new_config);
773  new_config.crypto_changed = 0;
774 
775  new_config.interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
776  assert(new_config.interfaces != NULL);
777  memset(new_config.interfaces, 0, sizeof (struct totem_interface) * INTERFACE_MAX);
778 
779  /* For UDP[U] the configuration on link0 is static (apart from the nodelist) and only read at
780  startup. So preserve it here */
781  if ( (new_config.transport_number == TOTEM_TRANSPORT_UDP) ||
782  (new_config.transport_number == TOTEM_TRANSPORT_UDPU)) {
783  memcpy(&new_config.interfaces[0], &new_config.orig_interfaces[0],
784  sizeof(struct totem_interface));
785  }
786 
787  /* Calculate new node and interface definitions */
788  if (totemconfig_configure_new_params(&new_config, temp_map, &error_string) == -1) {
789  log_printf (LOGSYS_LEVEL_ERROR, "Cannot configure new interface definitions: %s\n", error_string);
790  res = CS_ERR_INVALID_PARAM;
791  goto reload_fini;
792  }
793 
794  /* Read from temp_map into new_config */
795  totem_volatile_config_read(&new_config, temp_map, NULL);
796 
797  /* Get updated crypto parameters. Will set a flag in new_config if things have changed */
798  if (totem_reread_crypto_config(&new_config, temp_map, &error_string) == -1) {
799  log_printf (LOGSYS_LEVEL_ERROR, "Crypto configuration is not valid: %s\n", error_string);
800  res = CS_ERR_INVALID_PARAM;
801  goto reload_fini;
802  }
803 
804  /* Validate dynamic parameters */
805  if (totem_volatile_config_validate(&new_config, temp_map, &error_string) == -1) {
806  log_printf (LOGSYS_LEVEL_ERROR, "Configuration is not valid: %s\n", error_string);
807  res = CS_ERR_INVALID_PARAM;
808  goto reload_fini;
809  }
810 
811  /* Save this here so we can get at it for the later phases of crypto change */
812  if (new_config.crypto_changed) {
813 #ifndef HAVE_KNET_CRYPTO_RECONF
814  new_config.crypto_changed = 0;
815  log_printf (LOGSYS_LEVEL_ERROR, "Crypto reconfiguration is not supported by the linked version of knet\n");
816  res = CS_ERR_INVALID_PARAM;
817  goto reload_fini;
818 #endif
819  }
820 
821  /*
822  * Copy new keys into live config.
823  */
824  if ( (res = icmap_copy_map(icmap_get_global_map(), temp_map)) != CS_OK) {
825  log_printf (LOGSYS_LEVEL_ERROR, "Error making new config live. cmap database may be inconsistent\n");
826  /* Return res from icmap */
827  goto reload_fini;
828  }
829 
830  /* Copy into live system */
831  totempg_put_config(&new_config);
832  totemconfig_commit_new_params(&new_config, temp_map);
833 
834 reload_fini:
835  /* All done - let clients know */
836  icmap_set_int32("config.reload_status", res);
837  icmap_set_uint8("config.totemconfig_reload_in_progress", 0);
838  icmap_set_uint8("config.reload_in_progress", 0);
839 
840  /* Finished with the temporary storage */
841  free(new_config.interfaces);
842  free(new_config.orig_interfaces);
843 
844 reload_fini_nofree:
845  icmap_fini_r(temp_map);
846 
847 reload_fini_nomap:
848 
849  /* If crypto was changed, now it's loaded on all nodes we can enable it.
850  * Each node sends its own PHASE message so we're not relying on the leader
851  * node to survive the transition
852  */
853  if (new_config.crypto_changed) {
855  struct iovec iovec;
856 
857  req_exec_cfg_crypto_reconfig.header.size =
858  sizeof (struct req_exec_cfg_crypto_reconfig);
862 
863  iovec.iov_base = (char *)&req_exec_cfg_crypto_reconfig;
864  iovec.iov_len = sizeof (struct req_exec_cfg_crypto_reconfig);
865 
866  assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
867  }
868 
869  /* All done, return result to the caller if it was on this system */
870  if (nodeid == api->totem_nodeid_get()) {
873  res_lib_cfg_reload_config.header.error = res;
874  api->ipc_response_send(req_exec_cfg_reload_config->source.conn,
876  sizeof(res_lib_cfg_reload_config));
877  api->ipc_refcnt_dec(req_exec_cfg_reload_config->source.conn);;
878  }
879 
880  LEAVE();
881 }
882 
883 /* Handle the phases of crypto reload
884  * The first time we are called is after the new crypto config has been loaded
885  * but not activated.
886  *
887  * 1 - activate the new crypto configuration
888  * 2 - clear out the old configuration
889  */
890 static void message_handler_req_exec_cfg_reconfig_crypto (
891  const void *message,
892  unsigned int nodeid)
893 {
895 
896  /* Got our own reconfig message */
897  if (nodeid == api->totem_nodeid_get()) {
898  log_printf (LOGSYS_LEVEL_DEBUG, "Crypto reconfiguration phase %d", req_exec_cfg_crypto_reconfig->phase);
899 
900  /* Do the deed */
901  totempg_crypto_reconfigure_phase(req_exec_cfg_crypto_reconfig->phase);
902 
903  /* Move to the next phase if not finished */
904  if (req_exec_cfg_crypto_reconfig->phase < CRYPTO_RECONFIG_PHASE_CLEANUP) {
905  struct req_exec_cfg_crypto_reconfig req_exec_cfg_crypto_reconfig2;
906  struct iovec iovec;
907 
908  req_exec_cfg_crypto_reconfig2.header.size =
909  sizeof (struct req_exec_cfg_crypto_reconfig);
910  req_exec_cfg_crypto_reconfig2.header.id = SERVICE_ID_MAKE (CFG_SERVICE,
912  req_exec_cfg_crypto_reconfig2.phase = CRYPTO_RECONFIG_PHASE_CLEANUP;
913 
914  iovec.iov_base = (char *)&req_exec_cfg_crypto_reconfig2;
915  iovec.iov_len = sizeof (struct req_exec_cfg_crypto_reconfig);
916 
917  assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
918  }
919  }
920 }
921 
922 
923 /*
924  * Library Interface Implementation
925  */
926 static void message_handler_req_lib_cfg_ringstatusget (
927  void *conn,
928  const void *msg)
929 {
931  struct totem_ip_address interfaces[INTERFACE_MAX];
932  unsigned int iface_count;
933  char **status;
934  const char *totem_ip_string;
935  char ifname[CFG_INTERFACE_NAME_MAX_LEN];
936  unsigned int iface_ids[INTERFACE_MAX];
937  unsigned int i;
938  cs_error_t res = CS_OK;
939 
940  ENTER();
941 
943  res_lib_cfg_ringstatusget.header.size = sizeof (struct res_lib_cfg_ringstatusget);
944 
945  api->totem_ifaces_get (
946  api->totem_nodeid_get(),
947  iface_ids,
948  interfaces,
950  &status,
951  &iface_count);
952 
953  assert(iface_count <= CFG_MAX_INTERFACES);
954 
955  res_lib_cfg_ringstatusget.interface_count = iface_count;
956 
957  for (i = 0; i < iface_count; i++) {
958  totem_ip_string
959  = (const char *)api->totem_ip_print (&interfaces[i]);
960 
961  if (!totem_ip_string) {
962  totem_ip_string="";
963  }
964 
965  /* Allow for i/f number at the start */
966  if (strlen(totem_ip_string) >= CFG_INTERFACE_NAME_MAX_LEN-3) {
967  log_printf(LOGSYS_LEVEL_ERROR, "String representation of interface %u is too long", i);
968  res = CS_ERR_NAME_TOO_LONG;
969  goto send_response;
970  }
971  snprintf(ifname, sizeof(ifname), "%d %s", iface_ids[i], totem_ip_string);
972 
973  if (strlen(status[i]) >= CFG_INTERFACE_STATUS_MAX_LEN) {
974  log_printf(LOGSYS_LEVEL_ERROR, "Status string for interface %u is too long", i);
975  res = CS_ERR_NAME_TOO_LONG;
976  goto send_response;
977  }
978 
979  strcpy ((char *)&res_lib_cfg_ringstatusget.interface_status[i],
980  status[i]);
981  strcpy ((char *)&res_lib_cfg_ringstatusget.interface_name[i],
982  ifname);
983  }
984 
985 send_response:
986  res_lib_cfg_ringstatusget.header.error = res;
987  api->ipc_response_send (
988  conn,
990  sizeof (struct res_lib_cfg_ringstatusget));
991 
992  LEAVE();
993 }
994 
995 
996 static void message_handler_req_lib_cfg_nodestatusget (
997  void *conn,
998  const void *msg)
999 {
1002  void *res_lib_cfg_nodestatusget_ptr = NULL;
1003  size_t res_lib_cfg_nodestatusget_size;
1004  struct req_lib_cfg_nodestatusget *req_lib_cfg_nodestatusget = (struct req_lib_cfg_nodestatusget *)msg;
1005  struct totem_node_status node_status;
1006  int i;
1007 
1008  ENTER();
1009 
1010  memset(&node_status, 0, sizeof(node_status));
1011  if (totempg_nodestatus_get(req_lib_cfg_nodestatusget->nodeid, &node_status) != 0) {
1012  res_lib_cfg_nodestatusget_ptr = &res_lib_cfg_nodestatusget_version;
1013  res_lib_cfg_nodestatusget_size = sizeof(res_lib_cfg_nodestatusget_version);
1014 
1017  res_lib_cfg_nodestatusget_version.header.size = res_lib_cfg_nodestatusget_size;
1018 
1019  goto ipc_response_send;
1020  }
1021 
1022  /* Currently only one structure version supported */
1023  switch (req_lib_cfg_nodestatusget->version) {
1024  case CFG_NODE_STATUS_V1:
1025  res_lib_cfg_nodestatusget_ptr = &res_lib_cfg_nodestatusget_v1;
1026  res_lib_cfg_nodestatusget_size = sizeof(res_lib_cfg_nodestatusget_v1);
1027 
1028  res_lib_cfg_nodestatusget_v1.header.error = CS_OK;
1030  res_lib_cfg_nodestatusget_v1.header.size = res_lib_cfg_nodestatusget_size;
1031 
1032  res_lib_cfg_nodestatusget_v1.node_status.version = CFG_NODE_STATUS_V1;
1033  res_lib_cfg_nodestatusget_v1.node_status.nodeid = req_lib_cfg_nodestatusget->nodeid;
1034  res_lib_cfg_nodestatusget_v1.node_status.reachable = node_status.reachable;
1035  res_lib_cfg_nodestatusget_v1.node_status.remote = node_status.remote;
1036  res_lib_cfg_nodestatusget_v1.node_status.external = node_status.external;
1037  res_lib_cfg_nodestatusget_v1.node_status.onwire_min = node_status.onwire_min;
1038  res_lib_cfg_nodestatusget_v1.node_status.onwire_max = node_status.onwire_max;
1039  res_lib_cfg_nodestatusget_v1.node_status.onwire_ver = node_status.onwire_ver;
1040 
1041  for (i=0; i < KNET_MAX_LINK; i++) {
1042  res_lib_cfg_nodestatusget_v1.node_status.link_status[i].enabled = node_status.link_status[i].enabled;
1043  res_lib_cfg_nodestatusget_v1.node_status.link_status[i].connected = node_status.link_status[i].connected;
1044  res_lib_cfg_nodestatusget_v1.node_status.link_status[i].dynconnected = node_status.link_status[i].dynconnected;
1045  res_lib_cfg_nodestatusget_v1.node_status.link_status[i].mtu = node_status.link_status[i].mtu;
1046  memcpy(res_lib_cfg_nodestatusget_v1.node_status.link_status[i].src_ipaddr,
1047  node_status.link_status[i].src_ipaddr, CFG_MAX_HOST_LEN);
1048  memcpy(res_lib_cfg_nodestatusget_v1.node_status.link_status[i].dst_ipaddr,
1049  node_status.link_status[i].dst_ipaddr, CFG_MAX_HOST_LEN);
1050  }
1051  break;
1052  default:
1053  /*
1054  * Unsupported version requested
1055  */
1056  res_lib_cfg_nodestatusget_ptr = &res_lib_cfg_nodestatusget_version;
1057  res_lib_cfg_nodestatusget_size = sizeof(res_lib_cfg_nodestatusget_version);
1058 
1061  res_lib_cfg_nodestatusget_version.header.size = res_lib_cfg_nodestatusget_size;
1062  break;
1063  }
1064 
1065 ipc_response_send:
1066  api->ipc_response_send (
1067  conn,
1068  res_lib_cfg_nodestatusget_ptr,
1069  res_lib_cfg_nodestatusget_size);
1070 
1071  LEAVE();
1072 }
1073 
1074 static void message_handler_req_lib_cfg_trackstart (
1075  void *conn,
1076  const void *msg)
1077 {
1078  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
1080 
1081  ENTER();
1082 
1083  /*
1084  * We only do shutdown tracking at the moment
1085  */
1086  if (qb_list_empty(&ci->list)) {
1087  qb_list_add(&ci->list, &trackers_list);
1088  ci->tracker_conn = conn;
1089 
1090  if (shutdown_con) {
1091  /*
1092  * Shutdown already in progress, ask the newcomer's opinion
1093  */
1094  ci->shutdown_reply = SHUTDOWN_REPLY_UNKNOWN;
1095  shutdown_expected++;
1096  send_test_shutdown(conn, NULL, CS_OK);
1097  }
1098  }
1099 
1103 
1105  sizeof(res_lib_cfg_trackstart));
1106 
1107  LEAVE();
1108 }
1109 
1110 static void message_handler_req_lib_cfg_trackstop (
1111  void *conn,
1112  const void *msg)
1113 {
1114  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
1116 
1117  ENTER();
1118  remove_ci_from_shutdown(ci);
1119 
1120  res_lib_cfg_trackstop.header.size = sizeof(struct res_lib_cfg_trackstop);
1123 
1125  sizeof(res_lib_cfg_trackstop));
1126  LEAVE();
1127 }
1128 
1129 static void message_handler_req_lib_cfg_ringreenable (
1130  void *conn,
1131  const void *msg)
1132 {
1134  ENTER();
1135 
1137  res_lib_cfg_ringreenable.header.size = sizeof (struct res_lib_cfg_ringreenable);
1139  api->ipc_response_send (
1140  conn, &res_lib_cfg_ringreenable,
1141  sizeof (struct res_lib_cfg_ringreenable));
1142 
1143  LEAVE();
1144 }
1145 
1146 static void message_handler_req_lib_cfg_killnode (
1147  void *conn,
1148  const void *msg)
1149 {
1150  const struct req_lib_cfg_killnode *req_lib_cfg_killnode = msg;
1152  struct req_exec_cfg_killnode req_exec_cfg_killnode;
1153  struct iovec iovec;
1154  char key_name[ICMAP_KEYNAME_MAXLEN];
1155  char tmp_key[ICMAP_KEYNAME_MAXLEN + 1];
1156  icmap_map_t map;
1157  icmap_iter_t iter;
1158  const char *iter_key;
1159  uint32_t nodeid;
1160  char *status_str = NULL;
1161  int match_nodeid_flag = 0;
1162  cs_error_t error = CS_OK;
1163 
1164  ENTER();
1165 
1166  map = icmap_get_global_map();
1167  iter = icmap_iter_init_r(map, "runtime.members.");
1168  while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1169  if (sscanf(iter_key, "runtime.members.%u.%s", &nodeid, key_name) != 2) {
1170  continue;
1171  }
1172  if (strcmp(key_name, "status") != 0) {
1173  continue;
1174  }
1175  if (nodeid != req_lib_cfg_killnode->nodeid) {
1176  continue;
1177  }
1178  match_nodeid_flag = 1;
1179  snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "runtime.members.%u.status", nodeid);
1180  if (icmap_get_string_r(map, tmp_key, &status_str) != CS_OK) {
1181  error = CS_ERR_LIBRARY;
1182  goto send_response;
1183  }
1184  if (strcmp(status_str, "joined") != 0) {
1185  error = CS_ERR_NOT_EXIST;
1186  goto send_response;
1187  }
1188  break;
1189  }
1190 
1191  if (!match_nodeid_flag) {
1192  error = CS_ERR_NOT_EXIST;
1193  goto send_response;
1194  }
1195 
1196  req_exec_cfg_killnode.header.size =
1197  sizeof (struct req_exec_cfg_killnode);
1198  req_exec_cfg_killnode.header.id = SERVICE_ID_MAKE (CFG_SERVICE,
1200  req_exec_cfg_killnode.nodeid = req_lib_cfg_killnode->nodeid;
1201  marshall_to_mar_name_t(&req_exec_cfg_killnode.reason, &req_lib_cfg_killnode->reason);
1202 
1203  iovec.iov_base = (char *)&req_exec_cfg_killnode;
1204  iovec.iov_len = sizeof (struct req_exec_cfg_killnode);
1205 
1206  (void)api->totem_mcast (&iovec, 1, TOTEM_SAFE);
1207 
1208 send_response:
1209  res_lib_cfg_killnode.header.size = sizeof(struct res_lib_cfg_killnode);
1211  res_lib_cfg_killnode.header.error = error;
1212 
1214  sizeof(res_lib_cfg_killnode));
1215 
1216  free(status_str);
1217  icmap_iter_finalize(iter);
1218  LEAVE();
1219 }
1220 
1221 
1222 static void message_handler_req_lib_cfg_tryshutdown (
1223  void *conn,
1224  const void *msg)
1225 {
1226  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
1228  struct qb_list_head *iter;
1229 
1230  ENTER();
1231 
1232  if (req_lib_cfg_tryshutdown->flags == CFG_SHUTDOWN_FLAG_IMMEDIATE) {
1234 
1235  /*
1236  * Tell other nodes
1237  */
1238  send_shutdown();
1239 
1240  res_lib_cfg_tryshutdown.header.size = sizeof(struct res_lib_cfg_tryshutdown);
1242  res_lib_cfg_tryshutdown.header.error = CS_OK;
1244  sizeof(res_lib_cfg_tryshutdown));
1245 
1246  LEAVE();
1247  return;
1248  }
1249 
1250  /*
1251  * Shutdown in progress, return an error
1252  */
1253  if (shutdown_con) {
1255 
1256  res_lib_cfg_tryshutdown.header.size = sizeof(struct res_lib_cfg_tryshutdown);
1258  res_lib_cfg_tryshutdown.header.error = CS_ERR_EXIST;
1259 
1261  sizeof(res_lib_cfg_tryshutdown));
1262 
1263 
1264  LEAVE();
1265 
1266  return;
1267  }
1268 
1269  ci->conn = conn;
1270  shutdown_con = (struct cfg_info *)api->ipc_private_data_get (conn);
1271  shutdown_flags = req_lib_cfg_tryshutdown->flags;
1272  shutdown_yes = 0;
1273  shutdown_no = 0;
1274 
1275  /*
1276  * Count the number of listeners
1277  */
1278  shutdown_expected = 0;
1279 
1280  qb_list_for_each(iter, &trackers_list) {
1281  struct cfg_info *testci = qb_list_entry(iter, struct cfg_info, list);
1282  /*
1283  * It is assumed that we will allow shutdown
1284  */
1285  if (testci != ci) {
1287  shutdown_expected++;
1288  }
1289  }
1290 
1291  /*
1292  * If no-one is listening for events then we can just go down now
1293  */
1294  if (shutdown_expected == 0) {
1296 
1297  res_lib_cfg_tryshutdown.header.size = sizeof(struct res_lib_cfg_tryshutdown);
1299  res_lib_cfg_tryshutdown.header.error = CS_OK;
1300 
1301  /*
1302  * Tell originator that shutdown was confirmed
1303  */
1305  sizeof(res_lib_cfg_tryshutdown));
1306 
1307  send_shutdown();
1308  LEAVE();
1309  return;
1310  }
1311  else {
1312  unsigned int shutdown_timeout = DEFAULT_SHUTDOWN_TIMEOUT;
1313 
1314  /*
1315  * Look for a shutdown timeout in configuration map
1316  */
1317  icmap_get_uint32("cfg.shutdown_timeout", &shutdown_timeout);
1318 
1319  /*
1320  * Start the timer. If we don't get a full set of replies before this goes
1321  * off we'll cancel the shutdown
1322  */
1323  api->timer_add_duration((unsigned long long)shutdown_timeout*QB_TIME_NS_IN_MSEC, NULL,
1324  shutdown_timer_fn, &shutdown_timer);
1325 
1326  /*
1327  * Tell the users we would like to shut down
1328  */
1329  send_test_shutdown(NULL, conn, CS_OK);
1330  }
1331 
1332  /*
1333  * We don't sent a reply to the caller here.
1334  * We send it when we know if we can shut down or not
1335  */
1336 
1337  LEAVE();
1338 }
1339 
1340 static void message_handler_req_lib_cfg_replytoshutdown (
1341  void *conn,
1342  const void *msg)
1343 {
1344  struct cfg_info *ci = (struct cfg_info *)api->ipc_private_data_get (conn);
1347  int status = CS_OK;
1348 
1349  ENTER();
1350  if (!shutdown_con) {
1351  status = CS_ERR_ACCESS;
1352  goto exit_fn;
1353  }
1354 
1355  if (req_lib_cfg_replytoshutdown->response) {
1356  shutdown_yes++;
1357  ci->shutdown_reply = SHUTDOWN_REPLY_YES;
1358  }
1359  else {
1360  shutdown_no++;
1361  ci->shutdown_reply = SHUTDOWN_REPLY_NO;
1362  }
1363  check_shutdown_status();
1364 
1365 exit_fn:
1366  res_lib_cfg_replytoshutdown.header.error = status;
1369 
1371  sizeof(res_lib_cfg_replytoshutdown));
1372 
1373  LEAVE();
1374 }
1375 
1376 static void message_handler_req_lib_cfg_get_node_addrs (void *conn,
1377  const void *msg)
1378 {
1379  struct totem_ip_address node_ifs[INTERFACE_MAX];
1380  unsigned int iface_ids[INTERFACE_MAX];
1381  char **status;
1382  unsigned int num_interfaces = 0;
1383  int ret = CS_OK;
1384  int i;
1385  int live_addrs = 0;
1388  size_t res_lib_cfg_get_node_addrs_size;
1389  unsigned int nodeid = req_lib_cfg_get_node_addrs->nodeid;
1390  char *addr_buf;
1391 
1392  if (nodeid == 0)
1393  nodeid = api->totem_nodeid_get();
1394 
1395  if (api->totem_ifaces_get(nodeid, iface_ids, node_ifs, INTERFACE_MAX, &status, &num_interfaces)) {
1396  ret = CS_ERR_EXIST;
1397  num_interfaces = 0;
1398  }
1399 
1400  res_lib_cfg_get_node_addrs_size = sizeof(struct res_lib_cfg_get_node_addrs) + (num_interfaces * TOTEMIP_ADDRLEN);
1401  res_lib_cfg_get_node_addrs = alloca(res_lib_cfg_get_node_addrs_size);
1402  memset(res_lib_cfg_get_node_addrs, 0, res_lib_cfg_get_node_addrs_size);
1403 
1404  res_lib_cfg_get_node_addrs->header.size = res_lib_cfg_get_node_addrs_size;
1405  res_lib_cfg_get_node_addrs->header.id = MESSAGE_RES_CFG_GET_NODE_ADDRS;
1406  res_lib_cfg_get_node_addrs->header.error = ret;
1407  if (num_interfaces) {
1408  res_lib_cfg_get_node_addrs->family = node_ifs[0].family;
1409  for (i = 0, addr_buf = (char *)res_lib_cfg_get_node_addrs->addrs;
1410  i < num_interfaces; i++) {
1411  if (node_ifs[i].family) {
1412  memcpy(addr_buf, node_ifs[i].addr, TOTEMIP_ADDRLEN);
1413  live_addrs++;
1414  addr_buf += TOTEMIP_ADDRLEN;
1415  }
1416  }
1417  res_lib_cfg_get_node_addrs->num_addrs = live_addrs;
1418  } else {
1419  res_lib_cfg_get_node_addrs->header.error = CS_ERR_NOT_EXIST;
1420  }
1421  api->ipc_response_send(conn, res_lib_cfg_get_node_addrs, res_lib_cfg_get_node_addrs->header.size);
1422 }
1423 
1424 static void message_handler_req_lib_cfg_local_get (void *conn, const void *msg)
1425 {
1427 
1428  res_lib_cfg_local_get.header.size = sizeof(res_lib_cfg_local_get);
1430  res_lib_cfg_local_get.header.error = CS_OK;
1431  res_lib_cfg_local_get.local_nodeid = api->totem_nodeid_get ();
1432 
1434  sizeof(res_lib_cfg_local_get));
1435 }
1436 
1437 static void message_handler_req_lib_cfg_reload_config (void *conn, const void *msg)
1438 {
1439  struct req_exec_cfg_reload_config req_exec_cfg_reload_config;
1440  struct iovec iovec;
1441 
1442  ENTER();
1443 
1444  req_exec_cfg_reload_config.header.size =
1445  sizeof (struct req_exec_cfg_reload_config);
1446  req_exec_cfg_reload_config.header.id = SERVICE_ID_MAKE (CFG_SERVICE,
1448  api->ipc_source_set (&req_exec_cfg_reload_config.source, conn);
1449  api->ipc_refcnt_inc(conn);
1450 
1451  iovec.iov_base = (char *)&req_exec_cfg_reload_config;
1452  iovec.iov_len = sizeof (struct req_exec_cfg_reload_config);
1453 
1454  assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
1455 
1456  LEAVE();
1457 }
1458 
1459 static void message_handler_req_lib_cfg_reopen_log_files (void *conn, const void *msg)
1460 {
1462  cs_error_t res;
1463 
1464  ENTER();
1465 
1466  log_printf(LOGSYS_LEVEL_DEBUG, "Reopening logging files\n");
1467 
1468  res = logsys_reopen_log_files();
1469 
1472  res_lib_cfg_reopen_log_files.header.error = res;
1473  api->ipc_response_send(conn,
1476 
1477  LEAVE();
1478 }
struct qb_ipc_request_header header __attribute__((aligned(8)))
void *(* ipc_private_data_get)(void *conn)
Definition: coroapi.h:256
const char * name
Definition: coroapi.h:491
The res_lib_cfg_reopen_log_files struct.
Definition: ipc_cfg.h:256
void(* timer_delete)(corosync_timer_handle_t timer_handle)
Definition: coroapi.h:241
int(* timer_add_duration)(unsigned long long nanoseconds_in_future, void *data, void(*timer_nf)(void *data), corosync_timer_handle_t *handle)
Definition: coroapi.h:229
const char * icmap_iter_next(icmap_iter_t iter, size_t *value_len, icmap_value_types_t *type)
Return next item in iterator iter.
Definition: icmap.c:1099
#define CFG_INTERFACE_STATUS_MAX_LEN
Definition: ipc_cfg.h:43
struct qb_list_head list
Definition: exec/cfg.c:104
cs_error_t icmap_copy_map(icmap_map_t dst_map, const icmap_map_t src_map)
Copy content of src_map icmap to dst_map icmap.
Definition: icmap.c:1302
The res_lib_cfg_replytoshutdown struct.
Definition: ipc_cfg.h:186
The res_lib_cfg_testshutdown struct.
Definition: ipc_cfg.h:193
The totem_ip_address struct.
Definition: coroapi.h:111
The corosync_service_engine struct.
Definition: coroapi.h:490
void icmap_iter_finalize(icmap_iter_t iter)
Finalize iterator.
Definition: icmap.c:1120
void(* shutdown_request)(void)
Definition: coroapi.h:429
cs_error_t logsys_reopen_log_files(void)
Definition: logsys.c:875
uint8_t value[CS_MAX_NAME_LENGTH]
Definition: corotypes.h:68
int coroparse_configparse(icmap_map_t config_map, const char **error_string)
Definition: coroparse.c:260
#define corosync_fatal_error(err)
Definition: coroapi.h:424
int(* ipc_response_send)(void *conn, const void *msg, size_t mlen)
Definition: coroapi.h:258
LOGSYS_DECLARE_SUBSYS("CFG")
#define CS_PRI_NODE_ID
Definition: corotypes.h:59
int totempg_crypto_reconfigure_phase(cfg_message_crypto_reconfig_phase_t phase)
Definition: totempg.c:1574
The res_lib_cfg_nodestatusget struct.
Definition: ipc_cfg.h:125
int icmap_key_value_eq(const icmap_map_t map1, const char *key_name1, const icmap_map_t map2, const char *key_name2)
Compare value of key with name key_name1 in map1 with key with name key_name2 in map2.
Definition: icmap.c:389
totem_configuration_type
The totem_configuration_type enum.
Definition: coroapi.h:132
int(* totem_ifaces_get)(unsigned int nodeid, unsigned int *interface_ids, struct totem_ip_address *interfaces, unsigned int interfaces_size, char ***status, unsigned int *iface_count)
Definition: coroapi.h:282
The res_lib_cfg_get_node_addrs struct.
Definition: ipc_cfg.h:209
The corosync_lib_handler struct.
Definition: coroapi.h:467
void totempg_put_config(struct totem_config *config)
Definition: totempg.c:1615
unsigned char addr[TOTEMIP_ADDRLEN]
Definition: coroapi.h:77
mar_name_t struct
Definition: mar_gen.h:166
The req_lib_cfg_get_node_addrs struct.
Definition: ipc_cfg.h:201
void totempg_get_config(struct totem_config *config)
Definition: totempg.c:1605
The corosync_exec_handler struct.
Definition: coroapi.h:475
void icmap_fini_r(const icmap_map_t map)
Finalize local, reentrant icmap.
Definition: icmap.c:242
icmap_map_t icmap_get_global_map(void)
Return global icmap.
Definition: icmap.c:268
enum cfg_info::@8 shutdown_reply
int(* totem_mcast)(const struct iovec *iovec, unsigned int iov_len, unsigned int guarantee)
Definition: coroapi.h:279
#define log_printf(level, format, args...)
Definition: logsys.h:332
void(* exec_handler_fn)(const void *msg, unsigned int nodeid)
Definition: coroapi.h:476
int totemconfig_commit_new_params(struct totem_config *totem_config, icmap_map_t map)
Definition: totemconfig.c:2444
void * tracker_conn
Definition: exec/cfg.c:106
#define SERVICE_ID_MAKE(a, b)
Definition: coroapi.h:458
#define INTERFACE_MAX
Definition: coroapi.h:88
#define ICMAP_KEYNAME_MAXLEN
Maximum length of key in icmap.
Definition: icmap.h:48
The res_lib_cfg_local_get struct.
Definition: ipc_cfg.h:227
The res_lib_cfg_killnode struct.
Definition: ipc_cfg.h:156
#define TOTEM_SAFE
Definition: coroapi.h:103
unsigned int num_addrs
Definition: ipc_cfg.h:212
unsigned int flags
Definition: ipc_cfg.h:195
The req_lib_cfg_tryshutdown struct.
Definition: ipc_cfg.h:163
unsigned int(* totem_nodeid_get)(void)
Definition: coroapi.h:275
void(* ipc_refcnt_dec)(void *conn)
Definition: coroapi.h:270
struct qb_ipc_request_header header __attribute__((aligned(8)))
The res_lib_cfg_ringreenable struct.
Definition: ipc_cfg.h:140
cs_error_t icmap_get_string_r(const icmap_map_t map, const char *key_name, char **str)
Definition: icmap.c:739
int totem_volatile_config_validate(struct totem_config *totem_config, icmap_map_t temp_map, const char **error_string)
Definition: totemconfig.c:380
#define LOGSYS_LEVEL_ERROR
Definition: logsys.h:72
#define TRACE1(format, args...)
Definition: logsys.h:335
#define CFG_INTERFACE_NAME_MAX_LEN
Definition: ipc_cfg.h:42
cs_error_t icmap_delete(const char *key_name)
Delete key from map.
Definition: icmap.c:657
#define CFG_MAX_HOST_LEN
Definition: cfg.h:169
cs_error_t
The cs_error_t enum.
Definition: corotypes.h:98
#define LOGSYS_LEVEL_DEBUG
Definition: logsys.h:76
The corosync_api_v1 struct.
Definition: coroapi.h:225
The req_lib_cfg_replytoshutdown struct.
Definition: ipc_cfg.h:178
The res_lib_cfg_tryshutdown struct.
Definition: ipc_cfg.h:171
cs_error_t icmap_get_uint32(const char *key_name, uint32_t *u32)
Definition: icmap.c:896
#define DEFAULT_SHUTDOWN_TIMEOUT
Definition: exec/cfg.c:88
#define TOTEMIP_ADDRLEN
Definition: coroapi.h:86
#define CFG_MAX_INTERFACES
Definition: ipc_cfg.h:48
const char *(* totem_ip_print)(const struct totem_ip_address *addr)
Definition: coroapi.h:292
#define ENTER
Definition: logsys.h:333
cs_error_t icmap_set_int32(const char *key_name, int32_t value)
Definition: icmap.c:595
uint32_t mar_uint32_t
Definition: mar_gen.h:53
void totem_volatile_config_read(struct totem_config *totem_config, icmap_map_t temp_map, const char *deleted_key)
Definition: totemconfig.c:311
cfg_message_req_types
Definition: exec/cfg.c:79
The memb_ring_id struct.
Definition: coroapi.h:122
unsigned int flags
Definition: ipc_cfg.h:165
cs_error_t icmap_delete_r(const icmap_map_t map, const char *key_name)
icmap_delete_r
Definition: icmap.c:637
unsigned short family
Definition: coroapi.h:76
struct qb_ipc_response_header header
Definition: ipc_cfg.h:274
The res_lib_cfg_ringstatusget struct.
Definition: ipc_cfg.h:101
int totemconfig_configure_new_params(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
Definition: totemconfig.c:2421
cs_error_t icmap_init_r(icmap_map_t *result)
Initialize additional (local, reentrant) icmap_map.
Definition: icmap.c:188
qb_loop_timer_handle corosync_timer_handle_t
corosync_timer_handle_t
Definition: coroapi.h:74
int totem_reread_crypto_config(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
Definition: totemconfig.c:2316
void * conn
Definition: exec/cfg.c:105
struct corosync_service_engine cfg_service_engine
Definition: exec/cfg.c:274
The req_lib_cfg_nodestatusget struct.
Definition: ipc_cfg.h:111
struct qb_ipc_request_header header __attribute__((aligned(8)))
struct qb_ipc_request_header header __attribute__((aligned(8)))
The res_lib_cfg_reload_config struct.
Definition: ipc_cfg.h:242
#define LOGSYS_LEVEL_NOTICE
Definition: logsys.h:74
cs_error_t icmap_set_uint8(const char *key_name, uint8_t value)
Definition: icmap.c:577
void(* lib_handler_fn)(void *conn, const void *msg)
Definition: coroapi.h:468
struct corosync_service_engine * cfg_get_service_engine_ver0(void)
Definition: exec/cfg.c:291
int(* ipc_dispatch_send)(void *conn, const void *msg, size_t mlen)
Definition: coroapi.h:263
int totempg_nodestatus_get(unsigned int nodeid, struct totem_node_status *node_status)
Definition: totempg.c:1453
unsigned int nodeid
Definition: coroapi.h:75
icmap_iter_t icmap_iter_init_r(const icmap_map_t map, const char *prefix)
icmap_iter_init_r
Definition: icmap.c:1088
icmap_iter_t icmap_iter_init(const char *prefix)
Initialize iterator with given prefix.
Definition: icmap.c:1093
struct memb_ring_id ring_id
Definition: totemsrp.c:264
void(* ipc_source_set)(mar_message_source_t *source, void *conn)
Definition: coroapi.h:252
struct qb_ipc_response_header header
Definition: ipc_cfg.h:266
The req_lib_cfg_killnode struct.
Definition: ipc_cfg.h:147
#define LEAVE
Definition: logsys.h:334
qb_map_iter_t * icmap_iter_t
Itterator type.
Definition: icmap.h:123
The cs_name_t struct.
Definition: corotypes.h:66
The mar_message_source_t struct.
Definition: coroapi.h:50
void(* ipc_refcnt_inc)(void *conn)
Definition: coroapi.h:268