corosync  2.4.2-dirty
exec/cmap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2012 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Jan Friesse (jfriesse@redhat.com)
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * - Neither the name of the Red Hat, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <config.h>
36 
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <poll.h>
44 #include <assert.h>
45 
46 #include <qb/qbloop.h>
47 #include <qb/qbipc_common.h>
48 
49 #include <corosync/corotypes.h>
50 #include <corosync/corodefs.h>
51 #include <corosync/list.h>
52 #include <corosync/mar_gen.h>
53 #include <corosync/ipc_cmap.h>
54 #include <corosync/logsys.h>
55 #include <corosync/coroapi.h>
56 #include <corosync/icmap.h>
57 
58 #include "service.h"
59 
60 LOGSYS_DECLARE_SUBSYS ("CMAP");
61 
62 #define MAX_REQ_EXEC_CMAP_MCAST_ITEMS 32
63 #define ICMAP_VALUETYPE_NOT_EXIST 0
64 
68 };
69 
70 typedef uint64_t cmap_iter_handle_t;
71 typedef uint64_t cmap_track_handle_t;
72 
74  void *conn;
77 };
78 
81 };
82 
86 };
87 
88 static struct corosync_api_v1 *api;
89 
90 static char *cmap_exec_init_fn (struct corosync_api_v1 *corosync_api);
91 static int cmap_exec_exit_fn(void);
92 
93 static int cmap_lib_init_fn (void *conn);
94 static int cmap_lib_exit_fn (void *conn);
95 
96 static void message_handler_req_lib_cmap_set(void *conn, const void *message);
97 static void message_handler_req_lib_cmap_delete(void *conn, const void *message);
98 static void message_handler_req_lib_cmap_get(void *conn, const void *message);
99 static void message_handler_req_lib_cmap_adjust_int(void *conn, const void *message);
100 static void message_handler_req_lib_cmap_iter_init(void *conn, const void *message);
101 static void message_handler_req_lib_cmap_iter_next(void *conn, const void *message);
102 static void message_handler_req_lib_cmap_iter_finalize(void *conn, const void *message);
103 static void message_handler_req_lib_cmap_track_add(void *conn, const void *message);
104 static void message_handler_req_lib_cmap_track_delete(void *conn, const void *message);
105 
106 static void cmap_notify_fn(int32_t event,
107  const char *key_name,
108  struct icmap_notify_value new_val,
109  struct icmap_notify_value old_val,
110  void *user_data);
111 
112 static void message_handler_req_exec_cmap_mcast(
113  const void *message,
114  unsigned int nodeid);
115 
116 static void exec_cmap_mcast_endian_convert(void *message);
117 
118 /*
119  * Reson is subtype of message. argc is number of items in argv array. Argv is array
120  * of strings (key names) which will be send to wire. There can be maximum
121  * MAX_REQ_EXEC_CMAP_MCAST_ITEMS items (for more items, CS_ERR_TOO_MANY_GROUPS
122  * error is returned). If key is not found, item has type ICMAP_VALUETYPE_NOT_EXIST
123  * and length zero.
124  */
125 static cs_error_t cmap_mcast_send(enum cmap_mcast_reason reason, int argc, char *argv[]);
126 
127 static void cmap_sync_init (
128  const unsigned int *trans_list,
129  size_t trans_list_entries,
130  const unsigned int *member_list,
131  size_t member_list_entries,
132  const struct memb_ring_id *ring_id);
133 
134 static int cmap_sync_process (void);
135 static void cmap_sync_activate (void);
136 static void cmap_sync_abort (void);
137 
138 static void cmap_config_version_track_cb(
139  int32_t event,
140  const char *key_name,
141  struct icmap_notify_value new_value,
142  struct icmap_notify_value old_value,
143  void *user_data);
144 
145 /*
146  * Library Handler Definition
147  */
148 static struct corosync_lib_handler cmap_lib_engine[] =
149 {
150  { /* 0 */
151  .lib_handler_fn = message_handler_req_lib_cmap_set,
152  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
153  },
154  { /* 1 */
155  .lib_handler_fn = message_handler_req_lib_cmap_delete,
156  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
157  },
158  { /* 2 */
159  .lib_handler_fn = message_handler_req_lib_cmap_get,
160  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
161  },
162  { /* 3 */
163  .lib_handler_fn = message_handler_req_lib_cmap_adjust_int,
164  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
165  },
166  { /* 4 */
167  .lib_handler_fn = message_handler_req_lib_cmap_iter_init,
168  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
169  },
170  { /* 5 */
171  .lib_handler_fn = message_handler_req_lib_cmap_iter_next,
172  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
173  },
174  { /* 6 */
175  .lib_handler_fn = message_handler_req_lib_cmap_iter_finalize,
176  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
177  },
178  { /* 7 */
179  .lib_handler_fn = message_handler_req_lib_cmap_track_add,
180  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
181  },
182  { /* 8 */
183  .lib_handler_fn = message_handler_req_lib_cmap_track_delete,
184  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
185  },
186 };
187 
188 static struct corosync_exec_handler cmap_exec_engine[] =
189 {
190  { /* 0 - MESSAGE_REQ_EXEC_CMAP_MCAST */
191  .exec_handler_fn = message_handler_req_exec_cmap_mcast,
192  .exec_endian_convert_fn = exec_cmap_mcast_endian_convert
193  },
194 };
195 
197  .name = "corosync configuration map access",
198  .id = CMAP_SERVICE,
199  .priority = 1,
200  .private_data_size = sizeof(struct cmap_conn_info),
201  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED,
202  .allow_inquorate = CS_LIB_ALLOW_INQUORATE,
203  .lib_init_fn = cmap_lib_init_fn,
204  .lib_exit_fn = cmap_lib_exit_fn,
205  .lib_engine = cmap_lib_engine,
206  .lib_engine_count = sizeof (cmap_lib_engine) / sizeof (struct corosync_lib_handler),
207  .exec_init_fn = cmap_exec_init_fn,
208  .exec_exit_fn = cmap_exec_exit_fn,
209  .exec_engine = cmap_exec_engine,
210  .exec_engine_count = sizeof (cmap_exec_engine) / sizeof (struct corosync_exec_handler),
211  .sync_init = cmap_sync_init,
212  .sync_process = cmap_sync_process,
213  .sync_activate = cmap_sync_activate,
214  .sync_abort = cmap_sync_abort
215 };
216 
218 {
219  return (&cmap_service_engine);
220 }
221 
223  mar_name_t key_name __attribute__((aligned(8)));
224  mar_uint8_t value_type __attribute__((aligned(8)));
225  mar_size_t value_len __attribute__((aligned(8)));
226  uint8_t value[] __attribute__((aligned(8)));
227 };
228 
230  struct qb_ipc_request_header header __attribute__((aligned(8)));
231  mar_uint8_t reason __attribute__((aligned(8)));
232  mar_uint8_t no_items __attribute__((aligned(8)));
233  mar_uint8_t reserved1 __attribute__((aligned(8)));
234  mar_uint8_t reserver2 __attribute__((aligned(8)));
235  /*
236  * Following are array of req_exec_cmap_mcast_item alligned to 8 bytes
237  */
238 };
239 
240 static size_t cmap_sync_trans_list_entries = 0;
241 static size_t cmap_sync_member_list_entries = 0;
242 static uint64_t cmap_highest_config_version_received = 0;
243 static uint64_t cmap_my_config_version = 0;
244 static int cmap_first_sync = 1;
245 static icmap_track_t cmap_config_version_track;
246 
247 static void cmap_config_version_track_cb(
248  int32_t event,
249  const char *key_name,
250  struct icmap_notify_value new_value,
251  struct icmap_notify_value old_value,
252  void *user_data)
253 {
254  const char *key = "totem.config_version";
255  cs_error_t ret;
256 
257  ENTER();
258 
259  if (icmap_get_uint64("totem.config_version", &cmap_my_config_version) != CS_OK) {
260  cmap_my_config_version = 0;
261  }
262 
263 
264  ret = cmap_mcast_send(CMAP_MCAST_REASON_NEW_CONFIG_VERSION, 1, (char **)&key);
265  if (ret != CS_OK) {
266  log_printf(LOGSYS_LEVEL_ERROR, "Can't inform other nodes about new config version");
267  }
268 
269  LEAVE();
270 }
271 
272 static int cmap_exec_exit_fn(void)
273 {
274 
275  if (icmap_track_delete(cmap_config_version_track) != CS_OK) {
276  log_printf(LOGSYS_LEVEL_ERROR, "Can't delete config_version icmap tracker");
277  }
278 
279  return 0;
280 }
281 
282 static char *cmap_exec_init_fn (
283  struct corosync_api_v1 *corosync_api)
284 {
285  cs_error_t ret;
286 
287  api = corosync_api;
288 
289  ret = icmap_track_add("totem.config_version",
291  cmap_config_version_track_cb,
292  NULL,
293  &cmap_config_version_track);
294 
295  if (ret != CS_OK) {
296  return ((char *)"Can't add config_version icmap tracker");
297  }
298 
299  return (NULL);
300 }
301 
302 static int cmap_lib_init_fn (void *conn)
303 {
304  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
305 
306  log_printf(LOGSYS_LEVEL_DEBUG, "lib_init_fn: conn=%p", conn);
307 
308  api->ipc_refcnt_inc(conn);
309 
310  memset(conn_info, 0, sizeof(*conn_info));
311  hdb_create(&conn_info->iter_db);
312  hdb_create(&conn_info->track_db);
313 
314  return (0);
315 }
316 
317 static int cmap_lib_exit_fn (void *conn)
318 {
319  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
320  hdb_handle_t iter_handle = 0;
321  icmap_iter_t *iter;
322  hdb_handle_t track_handle = 0;
323  icmap_track_t *track;
324 
325  log_printf(LOGSYS_LEVEL_DEBUG, "exit_fn for conn=%p", conn);
326 
327  hdb_iterator_reset(&conn_info->iter_db);
328  while (hdb_iterator_next(&conn_info->iter_db,
329  (void*)&iter, &iter_handle) == 0) {
330 
331  icmap_iter_finalize(*iter);
332 
333  (void)hdb_handle_put (&conn_info->iter_db, iter_handle);
334  }
335 
336  hdb_destroy(&conn_info->iter_db);
337 
338  hdb_iterator_reset(&conn_info->track_db);
339  while (hdb_iterator_next(&conn_info->track_db,
340  (void*)&track, &track_handle) == 0) {
341 
342  free(icmap_track_get_user_data(*track));
343 
344  icmap_track_delete(*track);
345 
346  (void)hdb_handle_put (&conn_info->track_db, track_handle);
347  }
348  hdb_destroy(&conn_info->track_db);
349 
350  api->ipc_refcnt_dec(conn);
351 
352  return (0);
353 }
354 
355 static void cmap_sync_init (
356  const unsigned int *trans_list,
357  size_t trans_list_entries,
358  const unsigned int *member_list,
359  size_t member_list_entries,
360  const struct memb_ring_id *ring_id)
361 {
362 
363  cmap_sync_trans_list_entries = trans_list_entries;
364  cmap_sync_member_list_entries = member_list_entries;
365  cmap_highest_config_version_received = 0;
366 
367  if (icmap_get_uint64("totem.config_version", &cmap_my_config_version) != CS_OK) {
368  cmap_my_config_version = 0;
369  }
370 }
371 
372 static int cmap_sync_process (void)
373 {
374  const char *key = "totem.config_version";
375  cs_error_t ret;
376 
377  ret = cmap_mcast_send(CMAP_MCAST_REASON_SYNC, 1, (char **)&key);
378 
379  return (ret == CS_OK ? 0 : -1);
380 }
381 
382 static void cmap_sync_activate (void)
383 {
384 
385  if (cmap_sync_trans_list_entries == 0) {
386  log_printf(LOGSYS_LEVEL_DEBUG, "Single node sync -> no action");
387 
388  return ;
389  }
390 
391  if (cmap_first_sync == 1) {
392  cmap_first_sync = 0;
393  } else {
394  log_printf(LOGSYS_LEVEL_DEBUG, "Not first sync -> no action");
395 
396  return ;
397  }
398 
399  if (cmap_my_config_version == 0) {
400  log_printf(LOGSYS_LEVEL_DEBUG, "My config version is 0 -> no action");
401 
402  return ;
403  }
404 
405  if (cmap_highest_config_version_received == 0) {
406  log_printf(LOGSYS_LEVEL_DEBUG, "Other nodes version is 0 -> no action");
407 
408  return ;
409  }
410 
411 
412  if (cmap_highest_config_version_received != cmap_my_config_version) {
414  "Received config version (%"PRIu64") is different than my config version (%"PRIu64")! Exiting",
415  cmap_highest_config_version_received, cmap_my_config_version);
416  api->shutdown_request();
417  return ;
418  }
419 }
420 
421 static void cmap_sync_abort (void)
422 {
423 
424 
425 }
426 
427 static void message_handler_req_lib_cmap_set(void *conn, const void *message)
428 {
429  const struct req_lib_cmap_set *req_lib_cmap_set = message;
431  cs_error_t ret;
432 
433  if (icmap_is_key_ro((char *)req_lib_cmap_set->key_name.value)) {
434  ret = CS_ERR_ACCESS;
435  } else {
436  ret = icmap_set((char *)req_lib_cmap_set->key_name.value, &req_lib_cmap_set->value,
437  req_lib_cmap_set->value_len, req_lib_cmap_set->type);
438  }
439 
440  memset(&res_lib_cmap_set, 0, sizeof(res_lib_cmap_set));
441  res_lib_cmap_set.header.size = sizeof(res_lib_cmap_set);
443  res_lib_cmap_set.header.error = ret;
444 
446 }
447 
448 static void message_handler_req_lib_cmap_delete(void *conn, const void *message)
449 {
450  const struct req_lib_cmap_set *req_lib_cmap_set = message;
452  cs_error_t ret;
453 
454  if (icmap_is_key_ro((char *)req_lib_cmap_set->key_name.value)) {
455  ret = CS_ERR_ACCESS;
456  } else {
457  ret = icmap_delete((char *)req_lib_cmap_set->key_name.value);
458  }
459 
460  memset(&res_lib_cmap_delete, 0, sizeof(res_lib_cmap_delete));
461  res_lib_cmap_delete.header.size = sizeof(res_lib_cmap_delete);
463  res_lib_cmap_delete.header.error = ret;
464 
466 }
467 
468 static void message_handler_req_lib_cmap_get(void *conn, const void *message)
469 {
470  const struct req_lib_cmap_get *req_lib_cmap_get = message;
472  struct res_lib_cmap_get error_res_lib_cmap_get;
473  cs_error_t ret;
474  size_t value_len;
475  size_t res_lib_cmap_get_size;
477  void *value;
478 
479  value_len = req_lib_cmap_get->value_len;
480 
481  res_lib_cmap_get_size = sizeof(*res_lib_cmap_get) + value_len;
482  res_lib_cmap_get = malloc(res_lib_cmap_get_size);
483  if (res_lib_cmap_get == NULL) {
484  ret = CS_ERR_NO_MEMORY;
485  goto error_exit;
486  }
487 
488  memset(res_lib_cmap_get, 0, res_lib_cmap_get_size);
489 
490  if (value_len > 0) {
491  value = res_lib_cmap_get->value;
492  } else {
493  value = NULL;
494  }
495 
496  ret = icmap_get((char *)req_lib_cmap_get->key_name.value,
497  value,
498  &value_len,
499  &type);
500 
501  if (ret != CS_OK) {
502  free(res_lib_cmap_get);
503  goto error_exit;
504  }
505 
506  res_lib_cmap_get->header.size = res_lib_cmap_get_size;
507  res_lib_cmap_get->header.id = MESSAGE_RES_CMAP_GET;
508  res_lib_cmap_get->header.error = ret;
509  res_lib_cmap_get->type = type;
510  res_lib_cmap_get->value_len = value_len;
511 
512  api->ipc_response_send(conn, res_lib_cmap_get, res_lib_cmap_get_size);
513  free(res_lib_cmap_get);
514 
515  return ;
516 
517 error_exit:
518  memset(&error_res_lib_cmap_get, 0, sizeof(error_res_lib_cmap_get));
519  error_res_lib_cmap_get.header.size = sizeof(error_res_lib_cmap_get);
520  error_res_lib_cmap_get.header.id = MESSAGE_RES_CMAP_GET;
521  error_res_lib_cmap_get.header.error = ret;
522 
523  api->ipc_response_send(conn, &error_res_lib_cmap_get, sizeof(error_res_lib_cmap_get));
524 }
525 
526 static void message_handler_req_lib_cmap_adjust_int(void *conn, const void *message)
527 {
528  const struct req_lib_cmap_adjust_int *req_lib_cmap_adjust_int = message;
530  cs_error_t ret;
531 
532  if (icmap_is_key_ro((char *)req_lib_cmap_adjust_int->key_name.value)) {
533  ret = CS_ERR_ACCESS;
534  } else {
535  ret = icmap_adjust_int((char *)req_lib_cmap_adjust_int->key_name.value,
536  req_lib_cmap_adjust_int->step);
537  }
538 
540  res_lib_cmap_adjust_int.header.size = sizeof(res_lib_cmap_adjust_int);
542  res_lib_cmap_adjust_int.header.error = ret;
543 
545 }
546 
547 static void message_handler_req_lib_cmap_iter_init(void *conn, const void *message)
548 {
549  const struct req_lib_cmap_iter_init *req_lib_cmap_iter_init = message;
551  cs_error_t ret;
552  icmap_iter_t iter;
553  icmap_iter_t *hdb_iter;
554  cmap_iter_handle_t handle = 0ULL;
555  const char *prefix;
556  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
557 
558  if (req_lib_cmap_iter_init->prefix.length > 0) {
559  prefix = (char *)req_lib_cmap_iter_init->prefix.value;
560  } else {
561  prefix = NULL;
562  }
563 
564  iter = icmap_iter_init(prefix);
565  if (iter == NULL) {
566  ret = CS_ERR_NO_SECTIONS;
567  goto reply_send;
568  }
569 
570  ret = hdb_error_to_cs(hdb_handle_create(&conn_info->iter_db, sizeof(iter), &handle));
571  if (ret != CS_OK) {
572  goto reply_send;
573  }
574 
575  ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db, handle, (void *)&hdb_iter));
576  if (ret != CS_OK) {
577  goto reply_send;
578  }
579 
580  *hdb_iter = iter;
581 
582  (void)hdb_handle_put (&conn_info->iter_db, handle);
583 
584 reply_send:
585  memset(&res_lib_cmap_iter_init, 0, sizeof(res_lib_cmap_iter_init));
586  res_lib_cmap_iter_init.header.size = sizeof(res_lib_cmap_iter_init);
588  res_lib_cmap_iter_init.header.error = ret;
589  res_lib_cmap_iter_init.iter_handle = handle;
590 
592 }
593 
594 static void message_handler_req_lib_cmap_iter_next(void *conn, const void *message)
595 {
596  const struct req_lib_cmap_iter_next *req_lib_cmap_iter_next = message;
598  cs_error_t ret;
599  icmap_iter_t *iter;
600  size_t value_len = 0;
601  icmap_value_types_t type = 0;
602  const char *res = NULL;
603  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
604 
605  ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db,
606  req_lib_cmap_iter_next->iter_handle, (void *)&iter));
607  if (ret != CS_OK) {
608  goto reply_send;
609  }
610 
611  res = icmap_iter_next(*iter, &value_len, &type);
612  if (res == NULL) {
613  ret = CS_ERR_NO_SECTIONS;
614  }
615 
616  (void)hdb_handle_put (&conn_info->iter_db, req_lib_cmap_iter_next->iter_handle);
617 
618 reply_send:
619  memset(&res_lib_cmap_iter_next, 0, sizeof(res_lib_cmap_iter_next));
620  res_lib_cmap_iter_next.header.size = sizeof(res_lib_cmap_iter_next);
622  res_lib_cmap_iter_next.header.error = ret;
623 
624  if (res != NULL) {
625  res_lib_cmap_iter_next.value_len = value_len;
627 
628  memcpy(res_lib_cmap_iter_next.key_name.value, res, strlen(res));
629  res_lib_cmap_iter_next.key_name.length = strlen(res);
630  }
631 
633 }
634 
635 static void message_handler_req_lib_cmap_iter_finalize(void *conn, const void *message)
636 {
639  cs_error_t ret;
640  icmap_iter_t *iter;
641  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
642 
643  ret = hdb_error_to_cs(hdb_handle_get(&conn_info->iter_db,
644  req_lib_cmap_iter_finalize->iter_handle, (void *)&iter));
645  if (ret != CS_OK) {
646  goto reply_send;
647  }
648 
649  icmap_iter_finalize(*iter);
650 
651  (void)hdb_handle_destroy(&conn_info->iter_db, req_lib_cmap_iter_finalize->iter_handle);
652 
653  (void)hdb_handle_put (&conn_info->iter_db, req_lib_cmap_iter_finalize->iter_handle);
654 
655 reply_send:
659  res_lib_cmap_iter_finalize.header.error = ret;
660 
662 }
663 
664 static void cmap_notify_fn(int32_t event,
665  const char *key_name,
666  struct icmap_notify_value new_val,
667  struct icmap_notify_value old_val,
668  void *user_data)
669 {
670  struct cmap_track_user_data *cmap_track_user_data = (struct cmap_track_user_data *)user_data;
672  struct iovec iov[3];
673 
675 
676  res_lib_cmap_notify_callback.header.size = sizeof(res_lib_cmap_notify_callback) + new_val.len + old_val.len;
678  res_lib_cmap_notify_callback.header.error = CS_OK;
679 
680  res_lib_cmap_notify_callback.new_value_type = new_val.type;
681  res_lib_cmap_notify_callback.old_value_type = old_val.type;
682  res_lib_cmap_notify_callback.new_value_len = new_val.len;
683  res_lib_cmap_notify_callback.old_value_len = old_val.len;
684  res_lib_cmap_notify_callback.event = event;
685  res_lib_cmap_notify_callback.key_name.length = strlen(key_name);
686  res_lib_cmap_notify_callback.track_inst_handle = cmap_track_user_data->track_inst_handle;
687 
688  memcpy(res_lib_cmap_notify_callback.key_name.value, key_name, strlen(key_name));
689 
690  iov[0].iov_base = (char *)&res_lib_cmap_notify_callback;
691  iov[0].iov_len = sizeof(res_lib_cmap_notify_callback);
692  iov[1].iov_base = (char *)new_val.data;
693  iov[1].iov_len = new_val.len;
694  iov[2].iov_base = (char *)old_val.data;
695  iov[2].iov_len = old_val.len;
696 
697  api->ipc_dispatch_iov_send(cmap_track_user_data->conn, iov, 3);
698 }
699 
700 static void message_handler_req_lib_cmap_track_add(void *conn, const void *message)
701 {
702  const struct req_lib_cmap_track_add *req_lib_cmap_track_add = message;
704  cs_error_t ret;
705  cmap_track_handle_t handle = 0;
706  icmap_track_t track = NULL;
707  icmap_track_t *hdb_track;
708  struct cmap_track_user_data *cmap_track_user_data;
709  const char *key_name;
710 
711  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
712 
713  cmap_track_user_data = malloc(sizeof(*cmap_track_user_data));
714  if (cmap_track_user_data == NULL) {
715  ret = CS_ERR_NO_MEMORY;
716 
717  goto reply_send;
718  }
719  memset(cmap_track_user_data, 0, sizeof(*cmap_track_user_data));
720 
721  if (req_lib_cmap_track_add->key_name.length > 0) {
722  key_name = (char *)req_lib_cmap_track_add->key_name.value;
723  } else {
724  key_name = NULL;
725  }
726 
727  ret = icmap_track_add(key_name,
728  req_lib_cmap_track_add->track_type,
729  cmap_notify_fn,
730  cmap_track_user_data,
731  &track);
732  if (ret != CS_OK) {
733  free(cmap_track_user_data);
734 
735  goto reply_send;
736  }
737 
738  ret = hdb_error_to_cs(hdb_handle_create(&conn_info->track_db, sizeof(track), &handle));
739  if (ret != CS_OK) {
740  free(cmap_track_user_data);
741 
742  goto reply_send;
743  }
744 
745  ret = hdb_error_to_cs(hdb_handle_get(&conn_info->track_db, handle, (void *)&hdb_track));
746  if (ret != CS_OK) {
747  free(cmap_track_user_data);
748 
749  goto reply_send;
750  }
751 
752  *hdb_track = track;
753  cmap_track_user_data->conn = conn;
754  cmap_track_user_data->track_handle = handle;
755  cmap_track_user_data->track_inst_handle = req_lib_cmap_track_add->track_inst_handle;
756 
757  (void)hdb_handle_put (&conn_info->track_db, handle);
758 
759 reply_send:
760  memset(&res_lib_cmap_track_add, 0, sizeof(res_lib_cmap_track_add));
761  res_lib_cmap_track_add.header.size = sizeof(res_lib_cmap_track_add);
763  res_lib_cmap_track_add.header.error = ret;
764  res_lib_cmap_track_add.track_handle = handle;
765 
767 }
768 
769 static void message_handler_req_lib_cmap_track_delete(void *conn, const void *message)
770 {
773  cs_error_t ret;
774  icmap_track_t *track;
775  struct cmap_conn_info *conn_info = (struct cmap_conn_info *)api->ipc_private_data_get (conn);
776  uint64_t track_inst_handle = 0;
777 
778  ret = hdb_error_to_cs(hdb_handle_get(&conn_info->track_db,
779  req_lib_cmap_track_delete->track_handle, (void *)&track));
780  if (ret != CS_OK) {
781  goto reply_send;
782  }
783 
784  track_inst_handle = ((struct cmap_track_user_data *)icmap_track_get_user_data(*track))->track_inst_handle;
785 
786  free(icmap_track_get_user_data(*track));
787 
788  ret = icmap_track_delete(*track);
789 
790  (void)hdb_handle_put (&conn_info->track_db, req_lib_cmap_track_delete->track_handle);
791  (void)hdb_handle_destroy(&conn_info->track_db, req_lib_cmap_track_delete->track_handle);
792 
793 reply_send:
797  res_lib_cmap_track_delete.header.error = ret;
798  res_lib_cmap_track_delete.track_inst_handle = track_inst_handle;
799 
801 }
802 
803 static cs_error_t cmap_mcast_send(enum cmap_mcast_reason reason, int argc, char *argv[])
804 {
805  int i;
806  size_t value_len;
807  icmap_value_types_t value_type;
808  cs_error_t err;
809  size_t item_len;
810  size_t msg_len = 0;
812  struct req_exec_cmap_mcast_item *item = NULL;
813  struct iovec req_exec_cmap_iovec[MAX_REQ_EXEC_CMAP_MCAST_ITEMS + 1];
814 
815  ENTER();
816 
817  if (argc > MAX_REQ_EXEC_CMAP_MCAST_ITEMS) {
818  return (CS_ERR_TOO_MANY_GROUPS);
819  }
820 
821  memset(req_exec_cmap_iovec, 0, sizeof(req_exec_cmap_iovec));
822 
823  for (i = 0; i < argc; i++) {
824  err = icmap_get(argv[i], NULL, &value_len, &value_type);
825  if (err != CS_OK && err != CS_ERR_NOT_EXIST) {
826  goto free_mem;
827  }
828  if (err == CS_ERR_NOT_EXIST) {
829  value_type = ICMAP_VALUETYPE_NOT_EXIST;
830  value_len = 0;
831  }
832 
833  item_len = MAR_ALIGN_UP(sizeof(*item) + value_len, 8);
834 
835  item = malloc(item_len);
836  if (item == NULL) {
837  goto free_mem;
838  }
839  memset(item, 0, item_len);
840 
841  item->value_type = value_type;
842  item->value_len = value_len;
843  item->key_name.length = strlen(argv[i]);
844  strcpy((char *)item->key_name.value, argv[i]);
845 
846  if (value_type != ICMAP_VALUETYPE_NOT_EXIST) {
847  err = icmap_get(argv[i], item->value, &value_len, &value_type);
848  if (err != CS_OK) {
849  goto free_mem;
850  }
851  }
852 
853  req_exec_cmap_iovec[i + 1].iov_base = item;
854  req_exec_cmap_iovec[i + 1].iov_len = item_len;
855  msg_len += item_len;
856 
857  qb_log(LOG_TRACE, "Item %u - type %u, len %zu", i, item->value_type, item->value_len);
858 
859  item = NULL;
860  }
861 
862  memset(&req_exec_cmap_mcast, 0, sizeof(req_exec_cmap_mcast));
863  req_exec_cmap_mcast.header.size = sizeof(req_exec_cmap_mcast) + msg_len;
864  req_exec_cmap_mcast.reason = reason;
865  req_exec_cmap_mcast.no_items = argc;
866  req_exec_cmap_iovec[0].iov_base = &req_exec_cmap_mcast;
867  req_exec_cmap_iovec[0].iov_len = sizeof(req_exec_cmap_mcast);
868 
869  qb_log(LOG_TRACE, "Sending %u items (%u iovec) for reason %u", argc, argc + 1, reason);
870  err = (api->totem_mcast(req_exec_cmap_iovec, argc + 1, TOTEM_AGREED) == 0 ? CS_OK : CS_ERR_MESSAGE_ERROR);
871 
872 free_mem:
873  for (i = 0; i < argc; i++) {
874  free(req_exec_cmap_iovec[i + 1].iov_base);
875  }
876 
877  free(item);
878 
879  LEAVE();
880  return (err);
881 }
882 
883 static struct req_exec_cmap_mcast_item *cmap_mcast_item_find(
884  const void *message,
885  char *key)
886 {
887  const struct req_exec_cmap_mcast *req_exec_cmap_mcast = message;
888  int i;
889  const char *p;
890  struct req_exec_cmap_mcast_item *item;
891  mar_uint16_t key_name_len;
892 
893  p = (const char *)message + sizeof(*req_exec_cmap_mcast);
894 
895  for (i = 0; i < req_exec_cmap_mcast->no_items; i++) {
896  item = (struct req_exec_cmap_mcast_item *)p;
897 
898  key_name_len = item->key_name.length;
899  if (strlen(key) == key_name_len && strcmp((char *)item->key_name.value, key) == 0) {
900  return (item);
901  }
902 
903  p += MAR_ALIGN_UP(sizeof(*item) + item->value_len, 8);
904  }
905 
906  return (NULL);
907 }
908 
909 static void message_handler_req_exec_cmap_mcast_reason_sync_nv(
910  enum cmap_mcast_reason reason,
911  const void *message,
912  unsigned int nodeid)
913 {
914  char member_config_version[ICMAP_KEYNAME_MAXLEN];
915  uint64_t config_version = 0;
916  struct req_exec_cmap_mcast_item *item;
917  mar_size_t value_len;
918 
919  ENTER();
920 
921  item = cmap_mcast_item_find(message, (char *)"totem.config_version");
922  if (item != NULL) {
923  value_len = item->value_len;
924 
925  if (item->value_type == ICMAP_VALUETYPE_NOT_EXIST) {
926  config_version = 0;
927  }
928 
929  if (item->value_type == ICMAP_VALUETYPE_UINT64) {
930  memcpy(&config_version, item->value, value_len);
931  }
932  }
933 
934  qb_log(LOG_TRACE, "Received config version %"PRIu64" from node %x", config_version, nodeid);
935 
936  if (nodeid != api->totem_nodeid_get() &&
937  config_version > cmap_highest_config_version_received) {
938  cmap_highest_config_version_received = config_version;
939  }
940 
941  snprintf(member_config_version, ICMAP_KEYNAME_MAXLEN,
942  "runtime.totem.pg.mrp.srp.members.%u.config_version", nodeid);
943  icmap_set_uint64(member_config_version, config_version);
944 
945  LEAVE();
946 }
947 
948 static void message_handler_req_exec_cmap_mcast(
949  const void *message,
950  unsigned int nodeid)
951 {
952  const struct req_exec_cmap_mcast *req_exec_cmap_mcast = message;
953 
954  ENTER();
955 
956  switch (req_exec_cmap_mcast->reason) {
958  message_handler_req_exec_cmap_mcast_reason_sync_nv(req_exec_cmap_mcast->reason,
959  message, nodeid);
960 
961  break;
963  message_handler_req_exec_cmap_mcast_reason_sync_nv(req_exec_cmap_mcast->reason,
964  message, nodeid);
965 
966  break;
967  default:
968  qb_log(LOG_TRACE, "Received mcast with unknown reason %u", req_exec_cmap_mcast->reason);
969  };
970 
971  LEAVE();
972 }
973 
974 static void exec_cmap_mcast_endian_convert(void *message)
975 {
976  struct req_exec_cmap_mcast *req_exec_cmap_mcast = message;
977  const char *p;
978  int i;
979  struct req_exec_cmap_mcast_item *item;
980  uint16_t u16;
981  uint32_t u32;
982  uint64_t u64;
983  float flt;
984  double dbl;
985 
986  swab_coroipc_request_header_t(&req_exec_cmap_mcast->header);
987 
988  p = (const char *)message + sizeof(*req_exec_cmap_mcast);
989 
990  for (i = 0; i < req_exec_cmap_mcast->no_items; i++) {
991  item = (struct req_exec_cmap_mcast_item *)p;
992 
993  swab_mar_uint16_t(&item->key_name.length);
994  swab_mar_size_t(&item->value_len);
995 
996  switch (item->value_type) {
999  memcpy(&u16, item->value, sizeof(u16));
1000  u16 = swab16(u16);
1001  memcpy(item->value, &u16, sizeof(u16));
1002  break;
1003  case ICMAP_VALUETYPE_INT32:
1005  memcpy(&u32, item->value, sizeof(u32));
1006  u32 = swab32(u32);
1007  memcpy(item->value, &u32, sizeof(u32));
1008  break;
1009  case ICMAP_VALUETYPE_INT64:
1011  memcpy(&u64, item->value, sizeof(u64));
1012  u64 = swab64(u64);
1013  memcpy(item->value, &u64, sizeof(u64));
1014  break;
1015  case ICMAP_VALUETYPE_FLOAT:
1016  memcpy(&flt, item->value, sizeof(flt));
1017  swabflt(&flt);
1018  memcpy(item->value, &flt, sizeof(flt));
1019  break;
1021  memcpy(&dbl, item->value, sizeof(dbl));
1022  swabdbl(&dbl);
1023  memcpy(item->value, &dbl, sizeof(dbl));
1024  break;
1025  }
1026 
1027  p += MAR_ALIGN_UP(sizeof(*item) + item->value_len, 8);
1028  }
1029 }
#define TOTEM_AGREED
Definition: coroapi.h:102
The res_lib_cmap_track_add struct.
Definition: ipc_cmap.h:203
const char * name
Definition: coroapi.h:492
uint64_t track_inst_handle
Definition: exec/cmap.c:76
The res_lib_cmap_iter_finalize struct.
Definition: ipc_cmap.h:186
void * icmap_track_get_user_data(icmap_track_t icmap_track)
Return user data associated with given track.
Definition: icmap.c:1228
#define ICMAP_VALUETYPE_NOT_EXIST
Definition: exec/cmap.c:63
cs_error_t hdb_error_to_cs(int res)
size_t len
Definition: icmap.h:93
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:1103
void(* lib_handler_fn)(void *conn, const void *msg)
Definition: coroapi.h:469
cs_error_t icmap_adjust_int(const char *key_name, int32_t step)
icmap_adjust_int
Definition: icmap.c:987
uint32_t value
The corosync_service_engine struct.
Definition: coroapi.h:491
void icmap_iter_finalize(icmap_iter_t iter)
Finalize iterator.
Definition: icmap.c:1124
struct corosync_service_engine cmap_service_engine
Definition: exec/cmap.c:196
uint64_t cmap_iter_handle_t
Definition: exec/cmap.c:70
cs_error_t icmap_set(const char *key_name, const void *value, size_t value_len, icmap_value_types_t type)
Store value with value_len length and type as key_name name in global icmap.
Definition: icmap.c:501
The res_lib_cmap_iter_next struct.
Definition: ipc_cmap.h:168
#define MAR_ALIGN_UP(addr, size)
Definition: mar_gen.h:44
The res_lib_cmap_adjust_int struct.
Definition: ipc_cmap.h:137
void(* shutdown_request)(void)
Definition: coroapi.h:430
The req_lib_cmap_iter_finalize struct.
Definition: ipc_cmap.h:178
The corosync_lib_handler struct.
Definition: coroapi.h:468
mar_name_t struct
Definition: mar_gen.h:166
cmap_track_handle_t track_handle
Definition: exec/cmap.c:75
The corosync_exec_handler struct.
Definition: coroapi.h:476
The req_lib_cmap_iter_next struct.
Definition: ipc_cmap.h:160
#define log_printf(level, format, args...)
Definition: logsys.h:319
void(* exec_handler_fn)(const void *msg, unsigned int nodeid)
Definition: coroapi.h:477
#define swab64(x)
The swab64 macro.
Definition: swab.h:65
#define MAX_REQ_EXEC_CMAP_MCAST_ITEMS
Definition: exec/cmap.c:62
#define ICMAP_TRACK_DELETE
Definition: icmap.h:77
#define ICMAP_KEYNAME_MAXLEN
Maximum length of key in icmap.
Definition: icmap.h:48
The res_lib_cmap_iter_init struct.
Definition: ipc_cmap.h:152
#define ICMAP_TRACK_MODIFY
Definition: icmap.h:78
void *(* ipc_private_data_get)(void *conn)
Definition: coroapi.h:256
The req_lib_cmap_track_add struct.
Definition: ipc_cmap.h:193
uint64_t cmap_track_handle_t
Definition: exec/cmap.c:71
struct qb_ipc_request_header header __attribute__((aligned(8)))
void * user_data
Definition: sam.c:127
The res_lib_cmap_notify_callback struct.
Definition: ipc_cmap.h:227
mar_uint64_t mar_size_t
mar_size_t
Definition: mar_gen.h:286
const void * data
Definition: icmap.h:94
LOGSYS_DECLARE_SUBSYS("CMAP")
#define ICMAP_TRACK_ADD
Definition: icmap.h:76
icmap_value_types_t type
Definition: icmap.h:92
void(* ipc_refcnt_inc)(void *conn)
Definition: coroapi.h:268
#define LOGSYS_LEVEL_ERROR
Definition: logsys.h:70
Linked list API.
void(* ipc_refcnt_dec)(void *conn)
Definition: coroapi.h:270
cmap_message_req_types
Definition: exec/cmap.c:79
cs_error_t icmap_delete(const char *key_name)
Delete key from map.
Definition: icmap.c:667
cs_error_t icmap_get(const char *key_name, void *value, size_t *value_len, icmap_value_types_t *type)
Retrieve value of key key_name and store it in user preallocated value pointer.
Definition: icmap.c:739
cs_error_t
The cs_error_t enum.
Definition: corotypes.h:94
cs_error_t icmap_track_delete(icmap_track_t icmap_track)
Remove previously added track.
Definition: icmap.c:1212
#define LOGSYS_LEVEL_DEBUG
Definition: logsys.h:74
int(* ipc_dispatch_iov_send)(void *conn, const struct iovec *iov, unsigned int iov_len)
Definition: coroapi.h:265
uint64_t cmap_track_handle_t
Definition: cmap.h:64
struct hdb_handle_database iter_db
Definition: exec/cmap.c:66
uint8_t mar_uint8_t
Definition: mar_gen.h:51
The corosync_api_v1 struct.
Definition: coroapi.h:225
uint16_t mar_uint16_t
Definition: mar_gen.h:52
The res_lib_cmap_track_delete struct.
Definition: ipc_cmap.h:219
#define swab32(x)
The swab32 macro.
Definition: swab.h:51
cs_error_t icmap_set_uint64(const char *key_name, uint64_t value)
Definition: icmap.c:623
int icmap_is_key_ro(const char *key_name)
Check in given key is read only.
Definition: icmap.c:1280
struct corosync_service_engine * cmap_get_service_engine_ver0(void)
Definition: exec/cmap.c:217
int(* totem_mcast)(const struct iovec *iovec, unsigned int iov_len, unsigned int guarantee)
Definition: coroapi.h:281
#define ENTER
Definition: logsys.h:320
The res_lib_cmap_delete struct.
Definition: ipc_cmap.h:102
The req_lib_cmap_iter_init struct.
Definition: ipc_cmap.h:144
int(* ipc_response_send)(void *conn, const void *msg, size_t mlen)
Definition: coroapi.h:258
The req_lib_cmap_track_delete struct.
Definition: ipc_cmap.h:211
qb_handle_t hdb_handle_t
Definition: hdb.h:52
cs_error_t icmap_get_uint64(const char *key_name, uint64_t *u64)
Definition: icmap.c:878
The memb_ring_id struct.
Definition: coroapi.h:122
#define swab16(x)
The swab16 macro.
Definition: swab.h:39
uint64_t cmap_iter_handle_t
Definition: cmap.h:59
mar_name_t key_name __attribute__((aligned(8)))
The res_lib_cmap_set struct.
Definition: ipc_cmap.h:87
The req_lib_cmap_adjust_int struct.
Definition: ipc_cmap.h:128
char type
Definition: totemrrp.c:518
The res_lib_cmap_get struct.
Definition: ipc_cmap.h:118
The req_lib_cmap_set struct.
Definition: ipc_cmap.h:76
unsigned int nodeid
Definition: coroapi.h:75
icmap_iter_t icmap_iter_init(const char *prefix)
Initialize iterator with given prefix.
Definition: icmap.c:1097
struct memb_ring_id ring_id
Definition: totemsrp.c:64
icmap_value_types_t
Possible types of value.
Definition: icmap.h:58
#define hdb_handle_database
Definition: hdb.h:60
unsigned int(* totem_nodeid_get)(void)
Definition: coroapi.h:275
#define LEAVE
Definition: logsys.h:321
cmap_mcast_reason
Definition: exec/cmap.c:83
qb_map_iter_t * icmap_iter_t
Itterator type.
Definition: icmap.h:123
The req_lib_cmap_get struct.
Definition: ipc_cmap.h:109
Structure passed as new_value and old_value in change callback.
Definition: icmap.h:91
cs_error_t icmap_track_add(const char *key_name, int32_t track_type, icmap_notify_fn_t notify_fn, void *user_data, icmap_track_t *icmap_track)
Add tracking function for given key_name.
Definition: icmap.c:1167
struct hdb_handle_database track_db
Definition: exec/cmap.c:67