corosync
totemconfig.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006-2022 Red Hat, Inc.
4 *
5 * All rights reserved.
6 *
7 * Author: Steven Dake (sdake@redhat.com)
8 * Jan Friesse (jfriesse@redhat.com)
9 * Chrissie Caulfield (ccaulfie@redhat.com)
10 *
11 * This software licensed under BSD license, the text of which follows:
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * - Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * - Neither the name of the MontaVista Software, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include <config.h>
39
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43#include <errno.h>
44#include <unistd.h>
45#include <sys/socket.h>
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <ifaddrs.h>
50#include <netdb.h>
51#include <netinet/in.h>
52#include <arpa/inet.h>
53#include <sys/param.h>
54#include <sys/utsname.h>
55
56#include <corosync/swab.h>
57#include <qb/qblist.h>
58#include <qb/qbdefs.h>
59#include <libknet.h>
61#include <corosync/config.h>
62#include <corosync/logsys.h>
63#include <corosync/icmap.h>
64
65#include "util.h"
66#include "totemconfig.h"
67
68#define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
69#define TOKEN_TIMEOUT 3000
70#define TOKEN_WARNING 75
71#define TOKEN_COEFFICIENT 650
72#define JOIN_TIMEOUT 50
73#define MERGE_TIMEOUT 200
74#define DOWNCHECK_TIMEOUT 1000
75#define FAIL_TO_RECV_CONST 2500
76#define SEQNO_UNCHANGED_CONST 30
77#define MINIMUM_TIMEOUT (int)(1000/HZ)*3
78#define MINIMUM_TIMEOUT_HOLD (int)(MINIMUM_TIMEOUT * 0.8 - (1000/HZ))
79#define MAX_NETWORK_DELAY 50
80#define WINDOW_SIZE 50
81#define MAX_MESSAGES 17
82#define MISS_COUNT_CONST 5
83#define BLOCK_UNLISTED_IPS 1
84#define CANCEL_TOKEN_HOLD_ON_RETRANSMIT 0
85/* This constant is not used for knet */
86#define UDP_NETMTU 1500
87
88/* Currently all but PONG_COUNT match the defaults in libknet.h */
89#define KNET_PING_INTERVAL 1000
90#define KNET_PING_TIMEOUT 2000
91#define KNET_PING_PRECISION 2048
92#define KNET_PONG_COUNT 2
93#define KNET_PMTUD_INTERVAL 30
94#define KNET_MTU 0
95#define KNET_DEFAULT_TRANSPORT KNET_TRANSPORT_UDP
96
97#define DEFAULT_PORT 5405
98
99static char error_string_response[768];
100
101static void add_totem_config_notification(struct totem_config *totem_config);
102
103static void *totem_get_param_by_name(struct totem_config *totem_config, const char *param_name)
104{
105 if (strcmp(param_name, "totem.token") == 0)
107 if (strcmp(param_name, "totem.token_warning") == 0)
109 if (strcmp(param_name, "totem.token_retransmit") == 0)
111 if (strcmp(param_name, "totem.hold") == 0)
113 if (strcmp(param_name, "totem.token_retransmits_before_loss_const") == 0)
115 if (strcmp(param_name, "totem.join") == 0)
116 return &totem_config->join_timeout;
117 if (strcmp(param_name, "totem.send_join") == 0)
119 if (strcmp(param_name, "totem.consensus") == 0)
121 if (strcmp(param_name, "totem.merge") == 0)
123 if (strcmp(param_name, "totem.downcheck") == 0)
125 if (strcmp(param_name, "totem.fail_recv_const") == 0)
127 if (strcmp(param_name, "totem.seqno_unchanged_const") == 0)
129 if (strcmp(param_name, "totem.heartbeat_failures_allowed") == 0)
131 if (strcmp(param_name, "totem.max_network_delay") == 0)
133 if (strcmp(param_name, "totem.window_size") == 0)
134 return &totem_config->window_size;
135 if (strcmp(param_name, "totem.max_messages") == 0)
136 return &totem_config->max_messages;
137 if (strcmp(param_name, "totem.miss_count_const") == 0)
139 if (strcmp(param_name, "totem.knet_pmtud_interval") == 0)
141 if (strcmp(param_name, "totem.knet_mtu") == 0)
142 return &totem_config->knet_mtu;
143 if (strcmp(param_name, "totem.knet_compression_threshold") == 0)
145 if (strcmp(param_name, "totem.knet_compression_level") == 0)
147 if (strcmp(param_name, "totem.knet_compression_model") == 0)
149 if (strcmp(param_name, "totem.block_unlisted_ips") == 0)
151 if (strcmp(param_name, "totem.cancel_token_hold_on_retransmit") == 0)
153
154 return NULL;
155}
156
157/*
158 * Read key_name from icmap. If key is not found or key_name == delete_key or if allow_zero is false
159 * and readed value is zero, default value is used and stored into totem_config.
160 */
161static void totem_volatile_config_set_uint32_value (struct totem_config *totem_config, icmap_map_t map,
162 const char *key_name, const char *deleted_key, unsigned int default_value,
164{
166
167 if (icmap_get_uint32_r(map, key_name, totem_get_param_by_name(totem_config, key_name)) != CS_OK ||
168 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0) ||
169 (!allow_zero_value && *(uint32_t *)totem_get_param_by_name(totem_config, key_name) == 0)) {
170 *(uint32_t *)totem_get_param_by_name(totem_config, key_name) = default_value;
171 }
172
173 /*
174 * Store totem_config value to cmap runtime section
175 */
176 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
177 /*
178 * This shouldn't happen
179 */
180 return ;
181 }
182
183 strcpy(runtime_key_name, "runtime.config.");
184 strcat(runtime_key_name, key_name);
185
186 icmap_set_uint32_r(map, runtime_key_name, *(uint32_t *)totem_get_param_by_name(totem_config, key_name));
187}
188
189static void totem_volatile_config_set_int32_value (struct totem_config *totem_config, icmap_map_t map,
190 const char *key_name, const char *deleted_key, int default_value,
192{
194
195 if (icmap_get_int32_r(map, key_name, totem_get_param_by_name(totem_config, key_name)) != CS_OK ||
196 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0) ||
197 (!allow_zero_value && *(int32_t *)totem_get_param_by_name(totem_config, key_name) == 0)) {
198 *(int32_t *)totem_get_param_by_name(totem_config, key_name) = default_value;
199 }
200
201 /*
202 * Store totem_config value to cmap runtime section
203 */
204 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
205 /*
206 * This shouldn't happen
207 */
208 return ;
209 }
210
211 strcpy(runtime_key_name, "runtime.config.");
212 strcat(runtime_key_name, key_name);
213
214 icmap_set_int32_r(map, runtime_key_name, *(int32_t *)totem_get_param_by_name(totem_config, key_name));
215}
216
217static void totem_volatile_config_set_string_value (struct totem_config *totem_config, icmap_map_t map,
218 const char *key_name, const char *deleted_key, const char *default_value)
219{
221 int res;
222 char *new_config_value;
223 const void *config_value;
224
225 config_value = totem_get_param_by_name(totem_config, key_name);
226
227 res = icmap_get_string_r(map, key_name, (char **)&new_config_value);
228 if (res != CS_OK ||
229 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0)) {
230
231 /* Slightly pointless use of strncpy but it keeps coverity happy */
233 } else {
235 }
236 if (res == CS_OK) {
238 }
239
240 /*
241 * Store totem_config value to cmap runtime section
242 */
243 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
244 /*
245 * This shouldn't happen
246 */
247 return ;
248 }
249
250 strcpy(runtime_key_name, "runtime.config.");
251 strcat(runtime_key_name, key_name);
252
254}
255
256/*
257 * Read string value stored in key_name from icmap, use it as a boolean (yes/no) type, convert it
258 * to integer value (1/0) and store into totem_config.
259 *
260 * If key is not found or key_name == delete_key default value is used
261 * and stored into totem_config.
262 */
263static void totem_volatile_config_set_boolean_value (struct totem_config *totem_config, icmap_map_t map,
264 const char *key_name, const char *deleted_key, unsigned int default_value)
265{
267 char *str;
268 int val;
269
270 str = NULL;
272
273 if ((deleted_key != NULL && strcmp(deleted_key, key_name) == 0) ||
274 (icmap_get_string_r(map, key_name, &str) != CS_OK)) {
275 /*
276 * Do nothing. str is NULL (icmap_get_string ether not called or
277 * not changed str).
278 */
279 } else {
280 if (strcmp(str, "yes") == 0) {
281 val = 1;
282 } else if (strcmp(str, "no") == 0) {
283 val = 0;
284 }
285 free(str);
286 }
287
288 /*
289 * Store totem_config value to cmap runtime section
290 */
291 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
292 /*
293 * This shouldn't happen
294 */
295 return ;
296 }
297
298 strcpy(runtime_key_name, "runtime.config.");
299 strcat(runtime_key_name, key_name);
300
301 *(uint32_t *)totem_get_param_by_name(totem_config, key_name) = val;
302
304}
305
306/*
307 * Read and validate config values from cmap and store them into totem_config. If key doesn't exists,
308 * default value is stored. deleted_key is name of key beeing processed by delete operation
309 * from cmap. It is considered as non existing even if it can be read. Can be NULL.
310 */
312{
314
315 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.token_retransmits_before_loss_const", deleted_key,
317
318 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.token", deleted_key, TOKEN_TIMEOUT, 0);
319
320 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.token_warning", deleted_key, TOKEN_WARNING, 1);
321
324 icmap_get_uint32_r(temp_map, "totem.token_coefficient", &u32);
326
327 /*
328 * Store totem_config value to cmap runtime section
329 */
330 icmap_set_uint32_r(temp_map, "runtime.config.totem.token", totem_config->token_timeout);
331 }
332
333 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.max_network_delay", deleted_key, MAX_NETWORK_DELAY, 0);
334
335 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.window_size", deleted_key, WINDOW_SIZE, 0);
336
337 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.max_messages", deleted_key, MAX_MESSAGES, 0);
338
339 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.miss_count_const", deleted_key, MISS_COUNT_CONST, 0);
340 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.knet_pmtud_interval", deleted_key, KNET_PMTUD_INTERVAL, 0);
341 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.knet_mtu", deleted_key, KNET_MTU, 0);
342
343 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.token_retransmit", deleted_key,
345
346 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.hold", deleted_key,
347 (int)(totem_config->token_retransmit_timeout * 0.8 - (1000/HZ)), 0);
348
349 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.join", deleted_key, JOIN_TIMEOUT, 0);
350
351 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.consensus", deleted_key,
352 (int)(float)(1.2 * totem_config->token_timeout), 0);
353
354 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.merge", deleted_key, MERGE_TIMEOUT, 0);
355
356 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.downcheck", deleted_key, DOWNCHECK_TIMEOUT, 0);
357
358 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.fail_recv_const", deleted_key, FAIL_TO_RECV_CONST, 0);
359
360 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.seqno_unchanged_const", deleted_key,
362
363 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.send_join", deleted_key, 0, 1);
364
365 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.heartbeat_failures_allowed", deleted_key, 0, 1);
366
367 totem_volatile_config_set_uint32_value(totem_config, temp_map, "totem.knet_compression_threshold", deleted_key, 0, 1);
368
369 totem_volatile_config_set_int32_value(totem_config, temp_map, "totem.knet_compression_level", deleted_key, 0, 1);
370
371 totem_volatile_config_set_string_value(totem_config, temp_map, "totem.knet_compression_model", deleted_key, "none");
372
373 totem_volatile_config_set_boolean_value(totem_config, temp_map, "totem.block_unlisted_ips", deleted_key,
375
376 totem_volatile_config_set_boolean_value(totem_config, temp_map, "totem.cancel_token_hold_on_retransmit",
378}
379
383 const char **error_string)
384{
385 /* Static just to keep them off the stack */
386 static char local_error_reason[512];
387 static char addr_str_buf[INET6_ADDRSTRLEN];
388 const char *error_reason = local_error_reason;
390 char *name_str;
391 int i, j, num_configured, members;
393
396 "The max_network_delay parameter (%d ms) may not be less than (%d ms).",
398 goto parse_error;
399 }
400
403 "The token timeout parameter (%d ms) may not be less than (%d ms).",
405 goto parse_error;
406 }
407
408 // coverity[NO_EFFECT:SUPPRESS] clarify bounds of token_warning values and defensive programming
411 "The token warning parameter (%d%%) must be between 0 (disabled) and 100.",
413 goto parse_error;
414 }
415
417 if (icmap_get_uint32_r(temp_map, "totem.token_retransmit", &tmp_config_value) == CS_OK) {
419 "The token retransmit timeout parameter (%d ms) may not be less than (%d ms).",
421 goto parse_error;
422 } else {
424 "Not appropriate token or token_retransmits_before_loss_const value set");
425 goto parse_error;
426 }
427 }
428
431 "The token hold timeout parameter (%d ms) may not be less than (%d ms).",
433 goto parse_error;
434 }
435
438 "The join timeout parameter (%d ms) may not be less than (%d ms).",
440 goto parse_error;
441 }
442
445 "The consensus timeout parameter (%d ms) may not be less than (%d ms).",
447 goto parse_error;
448 }
449
452 "The consensus timeout parameter (%d ms) may not be less than join timeout (%d ms).",
454 goto parse_error;
455 }
456
459 "The merge timeout parameter (%d ms) may not be less than (%d ms).",
461 goto parse_error;
462 }
463
466 "The downcheck timeout parameter (%d ms) may not be less than (%d ms).",
468 goto parse_error;
469 }
470
471 /* Check that we have nodelist 'name' if there is more than one link */
472 num_configured = 0;
473 members = -1;
474 for (i = 0; i < INTERFACE_MAX; i++) {
476 if (num_configured == 0) {
478 }
480 }
481 }
482
483 if (num_configured > 1) {
484 /*
485 * This assert is here just to make compiler happy
486 */
487 assert(members != -1);
488 for (i=0; i < members; i++) {
489 snprintf(name_key, sizeof(name_key), "nodelist.node.%d.name", i);
490
493 "for a multi-link configuration, all nodes must have a 'name' attribute");
494 goto parse_error;
495 }
496
497 free(name_str);
498 }
499
500 for (i=0; i < INTERFACE_MAX; i++) {
502 continue;
503 }
506 "Not all nodes have the same number of links");
507 goto parse_error;
508 }
509 }
510 }
511
512 /* Verify that all nodes on the same link have the same IP family */
513 for (i=0; i < INTERFACE_MAX; i++) {
514 for (j=1; j<totem_config->interfaces[i].member_count; j++) {
520 sizeof(addr_str_buf));
521
523 "Nodes for link %d have different IP families "
524 "(compared %s with %s)", i,
527 goto parse_error;
528 }
529 }
530 }
531 }
532
533 return 0;
534
536 snprintf (error_string_response, sizeof(error_string_response),
537 "parse error in config: %s\n", error_reason);
538 *error_string = error_string_response;
539 return (-1);
540
541}
542
543static int totem_get_crypto(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
544{
545 char *str;
546 const char *tmp_cipher;
547 const char *tmp_hash;
548 const char *tmp_model;
549 char *crypto_model_str;
550 int res = 0;
551
552#ifdef ENABLE_UNENCRYPTED
553 tmp_hash = "none";
554 tmp_cipher = "none";
555#else
556 tmp_hash = "sha256";
557 tmp_cipher = "aes256";
558#endif
559 tmp_model = "none";
560
562 if (icmap_get_string_r(map, "totem.crypto_model", &crypto_model_str) == CS_OK) {
564 } else {
565 tmp_model = "nss";
566 }
567
568 if (icmap_get_string_r(map, "totem.secauth", &str) == CS_OK) {
569 tmp_hash = "none";
570 tmp_cipher = "none";
571
572 if (strcmp(str, "on") == 0) {
573 tmp_cipher = "aes256";
574 tmp_hash = "sha256";
575 }
576 free(str);
577 }
578
579 if (icmap_get_string_r(map, "totem.crypto_cipher", &str) == CS_OK) {
580 if (strcmp(str, "none") == 0) {
581 tmp_cipher = "none";
582 }
583 if (strcmp(str, "aes256") == 0) {
584 tmp_cipher = "aes256";
585 }
586 if (strcmp(str, "aes192") == 0) {
587 tmp_cipher = "aes192";
588 }
589 if (strcmp(str, "aes128") == 0) {
590 tmp_cipher = "aes128";
591 }
592 free(str);
593 }
594
595 if (icmap_get_string_r(map, "totem.crypto_hash", &str) == CS_OK) {
596 if (strcmp(str, "none") == 0) {
597 tmp_hash = "none";
598 }
599 if (strcmp(str, "md5") == 0) {
600 tmp_hash = "md5";
601 }
602 if (strcmp(str, "sha1") == 0) {
603 tmp_hash = "sha1";
604 }
605 if (strcmp(str, "sha256") == 0) {
606 tmp_hash = "sha256";
607 }
608 if (strcmp(str, "sha384") == 0) {
609 tmp_hash = "sha384";
610 }
611 if (strcmp(str, "sha512") == 0) {
612 tmp_hash = "sha512";
613 }
614 free(str);
615 }
616
617#ifdef ENABLE_UNENCRYPTED
618 if ((strcmp(tmp_cipher, "none") != 0) &&
619 (strcmp(tmp_hash, "none") == 0)) {
620 *error_string = "crypto_cipher requires crypto_hash with value other than none";
621 res = -1;
622
624 }
625#else
626 if (strcmp(tmp_cipher, "none") == 0 || strcmp(tmp_hash, "none") == 0) {
627 *error_string = "corosync is compiled to require enabled encryption";
628 res = -1;
629
631 }
632#endif
633
634 if (strcmp(tmp_model, "none") == 0) {
635 /*
636 * Shouldn't happen because it is handled by coroparse
637 */
638 *error_string = "invalid crypto_model";
639 res = -1;
640
642 }
643
648 }
649
652
655
658
661
662 return (res);
663}
664
665static int nodelist_byname(icmap_map_t map, const char *find_name, int strip_domain)
666{
668 const char *iter_key;
670 int res = 0;
671 unsigned int node_pos;
672 char *name;
673 unsigned int namelen;
674
675 iter = icmap_iter_init_r(map, "nodelist.node.");
676 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
677 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, name_str);
678 if (res != 2) {
679 continue;
680 }
681 /* ring0_addr is allowed as a fallback */
682 if (strcmp(name_str, "name") && strcmp(name_str, "ring0_addr")) {
683 continue;
684 }
685 if (icmap_get_string_r(map, iter_key, &name) != CS_OK) {
686 continue;
687 }
688 namelen = strlen(name);
689
690 if (strip_domain) {
691 char *dot;
692 dot = strchr(name, '.');
693 if (dot) {
694 namelen = dot - name;
695 }
696 }
697 if (strncmp(find_name, name, namelen) == 0 &&
700 return node_pos;
701 }
702 }
704 return -1;
705}
706
707/* Compare two addresses - only address part (sin_addr/sin6_addr) is checked */
708static int ipaddr_equal(const struct sockaddr *addr1, const struct sockaddr *addr2)
709{
710 int addrlen = 0;
711 const void *addr1p, *addr2p;
712
713 if (addr1->sa_family != addr2->sa_family)
714 return 0;
715
716 switch (addr1->sa_family) {
717 case AF_INET:
718 addrlen = sizeof(struct in_addr);
719 addr1p = &((struct sockaddr_in *)addr1)->sin_addr;
720 addr2p = &((struct sockaddr_in *)addr2)->sin_addr;
721 break;
722 case AF_INET6:
723 addrlen = sizeof(struct in6_addr);
724 addr1p = &((struct sockaddr_in6 *)addr1)->sin6_addr;
725 addr2p = &((struct sockaddr_in6 *)addr2)->sin6_addr;
726 break;
727 default:
728 assert(0);
729 }
730
731 return (memcmp(addr1p, addr2p, addrlen) == 0);
732}
733
734
735/* Finds the local node and returns its position in the nodelist.
736 * Uses nodelist.local_node_pos as a cache to save effort
737 */
738static int find_local_node(icmap_map_t map, int use_cache)
739{
740 char nodename2[PATH_MAX];
743 const char *iter_key;
744 unsigned int cached_pos;
745 char *dot = NULL;
746 const char *node;
747 struct ifaddrs *ifa, *ifa_list;
748 struct sockaddr *sa;
749 int found = 0;
750 int node_pos = -1;
751 int res;
752 struct utsname utsname;
753
754 /* Check for cached value first */
755 if (use_cache) {
756 if (icmap_get_uint32("nodelist.local_node_pos", &cached_pos) == CS_OK) {
757 return cached_pos;
758 }
759 }
760
761 res = uname(&utsname);
762 if (res < 0) {
763 return -1;
764 }
765 node = utsname.nodename;
766
767 /* 1. Exact match */
768 node_pos = nodelist_byname(map, node, 0);
769 if (node_pos > -1) {
770 found = 1;
771 goto ret_found;
772 }
773
774 /* 2. Try to match with increasingly more
775 * specific versions of it
776 */
778 dot = strrchr(nodename2, '.');
779 while (dot) {
780 *dot = '\0';
781
782 node_pos = nodelist_byname(map, nodename2, 0);
783 if (node_pos > -1) {
784 found = 1;
785 goto ret_found;
786 }
787 dot = strrchr(nodename2, '.');
788 }
789
790 node_pos = nodelist_byname(map, nodename2, 1);
791 if (node_pos > -1) {
792 found = 1;
793 goto ret_found;
794 }
795
796 /*
797 * The corosync.conf name may not be related to uname at all,
798 * they may match a hostname on some network interface.
799 */
800 if (getifaddrs(&ifa_list))
801 return -1;
802
803 for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
804 socklen_t salen = 0;
805
806 /* Restore this */
808 sa = ifa->ifa_addr;
809 if (!sa) {
810 continue;
811 }
812 if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) {
813 continue;
814 }
815
816 if (sa->sa_family == AF_INET) {
817 salen = sizeof(struct sockaddr_in);
818 }
819 if (sa->sa_family == AF_INET6) {
820 salen = sizeof(struct sockaddr_in6);
821 }
822
823 if (getnameinfo(sa, salen,
824 nodename2, sizeof(nodename2),
825 NULL, 0, 0) == 0) {
826
827 node_pos = nodelist_byname(map, nodename2, 0);
828 if (node_pos > -1) {
829 found = 1;
830 goto out;
831 }
832
833 /* Truncate this name and try again */
834 dot = strchr(nodename2, '.');
835 if (dot) {
836 *dot = '\0';
837
838 node_pos = nodelist_byname(map, nodename2, 0);
839 if (node_pos > -1) {
840 found = 1;
841 goto out;
842 }
843 }
844 }
845
846 /* See if it's the IP address that's in corosync.conf */
847 if (getnameinfo(sa, sizeof(*sa),
848 nodename2, sizeof(nodename2),
849 NULL, 0, NI_NUMERICHOST))
850 continue;
851
852 node_pos = nodelist_byname(map, nodename2, 0);
853 if (node_pos > -1) {
854 found = 1;
855 goto out;
856 }
857 }
858
859 out:
860 if (found) {
862 goto ret_found;
863 }
864
865 /*
866 * This section covers the usecase where the nodename specified in cluster.conf
867 * is an alias specified in /etc/hosts. For example:
868 * <ipaddr> hostname alias1 alias2
869 * and <clusternode name="alias2">
870 * the above calls use uname and getnameinfo does not return aliases.
871 * here we take the name specified in cluster.conf, resolve it to an address
872 * and then compare against all known local ip addresses.
873 * if we have a match, we found our nodename. In theory this chunk of code
874 * could replace all the checks above, but let's avoid any possible regressions
875 * and use it as last.
876 */
877
878 iter = icmap_iter_init_r(map, "nodelist.node.");
879 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
880 char *dbnodename = NULL;
881 struct addrinfo hints;
882 struct addrinfo *result = NULL, *rp = NULL;
883
884 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, name_str);
885 if (res != 2) {
886 continue;
887 }
888 /* 'ring0_addr' is allowed as a fallback, but 'name' will be found first
889 * because the names are in alpha order.
890 */
891 if (strcmp(name_str, "name") && strcmp(name_str, "ring0_addr")) {
892 continue;
893 }
895 continue;
896 }
897
898 memset(&hints, 0, sizeof(struct addrinfo));
899 hints.ai_family = AF_UNSPEC;
900 hints.ai_socktype = SOCK_DGRAM;
901 hints.ai_flags = 0;
902 hints.ai_protocol = IPPROTO_UDP;
903
905 continue;
906 }
907
908 for (rp = result; rp != NULL; rp = rp->ai_next) {
909 for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
910 if (ifa->ifa_addr &&
911 ipaddr_equal(rp->ai_addr, ifa->ifa_addr)) {
913 found = 1;
914 goto out2;
915 }
916 }
917 }
918
920 }
921out2:
924
926 if (found) {
927 res = icmap_set_uint32_r(map, "nodelist.local_node_pos", node_pos);
928 }
929
930 return node_pos;
931}
932
933static enum totem_ip_version_enum totem_config_get_ip_version(struct totem_config *totem_config)
934{
936 char *str;
937
939
940#ifdef ENABLE_UDPU
943 }
944#endif
945
946 if (icmap_get_string("totem.ip_version", &str) == CS_OK) {
947 if (strcmp(str, "ipv4") == 0) {
949 }
950 if (strcmp(str, "ipv6") == 0) {
952 }
953 if (strcmp(str, "ipv6-4") == 0) {
955 }
956 if (strcmp(str, "ipv4-6") == 0) {
958 }
959 free(str);
960 }
961
962 return (res);
963}
964
965#ifdef ENABLE_UDPU
966static uint16_t generate_cluster_id (const char *cluster_name)
967{
968 int i;
969 int value = 0;
970
971 for (i = 0; i < strlen(cluster_name); i++) {
972 value <<= 1;
973 value += cluster_name[i];
974 }
975
976 return (value & 0xFFFF);
977}
978
979static int get_cluster_mcast_addr (
980 const char *cluster_name,
981 unsigned int linknumber,
982 enum totem_ip_version_enum ip_version,
983 struct totem_ip_address *res)
984{
986 char addr[INET6_ADDRSTRLEN + 1];
987 int err;
988
989 if (cluster_name == NULL) {
990 return (-1);
991 }
992
993 clusterid = generate_cluster_id(cluster_name) + linknumber;
994 memset (res, 0, sizeof(*res));
995
996 switch (ip_version) {
999 snprintf(addr, sizeof(addr), "239.192.%d.%d", clusterid >> 8, clusterid % 0xFF);
1000 break;
1001 case TOTEM_IP_VERSION_6:
1003 snprintf(addr, sizeof(addr), "ff15::%x", clusterid);
1004 break;
1005 default:
1006 /*
1007 * Unknown family
1008 */
1009 return (-1);
1010 }
1011
1012 err = totemip_parse (res, addr, ip_version);
1013
1014 return (err);
1015}
1016#endif
1017
1018static unsigned int generate_nodeid(
1019 struct totem_config *totem_config,
1020 char *addr)
1021{
1022 unsigned int nodeid;
1024
1025 /* AF_INET hard-coded here because auto-generated nodeids
1026 are only for IPv4 */
1028 return -1;
1029
1030 memcpy (&nodeid, &totemip.addr, sizeof (unsigned int));
1031
1032#if __BYTE_ORDER == __LITTLE_ENDIAN
1033 nodeid = swab32 (nodeid);
1034#endif
1035
1037 nodeid &= 0x7FFFFFFF;
1038 }
1039 return nodeid;
1040}
1041
1042static int check_for_duplicate_nodeids(
1043 struct totem_config *totem_config,
1044 const char **error_string)
1045{
1048 const char *iter_key;
1049 int res = 0;
1050 int retval = 0;
1052 char *ring0_addr=NULL;
1053 char *ring0_addr1=NULL;
1054 unsigned int node_pos;
1055 unsigned int node_pos1;
1056 unsigned int last_node_pos = -1;
1057 unsigned int nodeid;
1058 unsigned int nodeid1;
1059 int autogenerated;
1060
1061 iter = icmap_iter_init("nodelist.node.");
1062 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1063 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
1064 if (res != 2) {
1065 continue;
1066 }
1067
1068 /*
1069 * This relies on the fact the icmap keys are always returned in order
1070 * so all of the keys for a node will be grouped together. We're basically
1071 * just running the code below once for each node.
1072 */
1073 if (last_node_pos == node_pos) {
1074 continue;
1075 }
1077
1078 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
1079 autogenerated = 0;
1080
1081 /* Generated nodeids are only allowed for UDP/UDPU so ring0_addr is valid here */
1083
1084 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos);
1086 continue;
1087 }
1088
1089 /* Generate nodeid so we can check that auto-generated nodeids don't clash either */
1090 nodeid = generate_nodeid(totem_config, ring0_addr);
1091 if (nodeid == -1) {
1092 continue;
1093 }
1094 autogenerated = 1;
1095 }
1096
1097 node_pos1 = 0;
1098 subiter = icmap_iter_init("nodelist.node.");
1099 while (((iter_key = icmap_iter_next(subiter, NULL, NULL)) != NULL) && (node_pos1 < node_pos)) {
1100 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos1, tmp_key);
1101 if ((res != 2) || (node_pos1 >= node_pos)) {
1102 continue;
1103 }
1104
1105 if (strcmp(tmp_key, "nodeid") != 0) {
1106 continue;
1107 }
1108
1109 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos1);
1111
1112 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos1);
1114 continue;
1115 }
1116 nodeid1 = generate_nodeid(totem_config, ring0_addr1);
1117 if (nodeid1 == -1) {
1118 continue;
1119 }
1120 }
1121
1122 if (nodeid == nodeid1) {
1123 retval = -1;
1124 snprintf (error_string_response, sizeof(error_string_response),
1125 "Nodeid %u%s%s%s appears twice in corosync.conf", nodeid,
1126 autogenerated?"(autogenerated from ":"",
1128 autogenerated?")":"");
1129 *error_string = error_string_response;
1130 break;
1131 }
1132 }
1134 }
1136 return retval;
1137}
1138
1139
1140/*
1141 * This needs to be done last of all. It would be nice to do it when reading the
1142 * interface params, but the totem params need to have them to be read first. We
1143 * need both, so this is a way round that circular dependancy.
1144 */
1174
1175/*
1176 * Compute difference between two set of totem interface arrays and commit it.
1177 * set1 and set2
1178 * are changed so for same ring, ip existing in both set1 and set2 are cleared
1179 * (set to 0), and ips which are only in set1 or set2 remains untouched.
1180 * totempg_node_add/remove is called.
1181 */
1182static int compute_and_set_totempg_interfaces(struct totem_interface *set1,
1183 struct totem_interface *set2)
1184{
1187 int res = 0;
1188
1190
1191 for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
1192 if (!set1[ring_no].configured && !set2[ring_no].configured) {
1193 continue;
1194 }
1195
1196 for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
1197 for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
1198 /*
1199 * For current ring_no remove all set1 items existing
1200 * in set2
1201 */
1202 if (memcmp(&set1[ring_no].member_list[set1_pos],
1203 &set2[ring_no].member_list[set2_pos],
1204 sizeof(struct totem_ip_address)) == 0) {
1205 memset(&set1[ring_no].member_list[set1_pos], 0,
1206 sizeof(struct totem_ip_address));
1207 memset(&set2[ring_no].member_list[set2_pos], 0,
1208 sizeof(struct totem_ip_address));
1209 }
1210 }
1211 }
1212 }
1213
1214 for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
1215 for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
1216 /*
1217 * All items which remain in set1 and don't exist in set2 any more
1218 * have to be removed.
1219 */
1220 if (memcmp(&set1[ring_no].member_list[set1_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
1222 "removing dynamic member %s for ring %u",
1223 totemip_print(&set1[ring_no].member_list[set1_pos]),
1224 ring_no);
1225
1227 }
1228 }
1229 if (!set2[ring_no].configured) {
1230 continue;
1231 }
1232 for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
1233 /*
1234 * All items which remain in set2 and don't exist in set1 are new nodes
1235 * and have to be added.
1236 */
1237 if (memcmp(&set2[ring_no].member_list[set2_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
1239 "adding dynamic member %s for ring %u",
1240 totemip_print(&set2[ring_no].member_list[set2_pos]),
1241 ring_no);
1242
1243 if (totempg_member_add(&set2[ring_no].member_list[set2_pos], ring_no)) {
1244 res = -1;
1245 }
1246 }
1247 }
1248 }
1249 return res;
1250}
1251
1252/*
1253 * Configure parameters for links
1254 */
1255static void configure_link_params(struct totem_config *totem_config, icmap_map_t map)
1256{
1257 int i;
1259 char *addr_string;
1260 int err;
1261 int local_node_pos = find_local_node(map, 0);
1262
1263 for (i = 0; i<INTERFACE_MAX; i++) {
1265 continue;
1266 }
1267
1268 log_printf(LOGSYS_LEVEL_DEBUG, "Configuring link %d params\n", i);
1269
1270 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring%u_addr", local_node_pos, i);
1272 continue;
1273 }
1274
1276 if (err != 0) {
1277 continue;
1278 }
1280
1281 /* In case this is a new link, fill in the defaults if there was no interface{} section for it */
1284
1285 /* knet_ping_interval & knet_ping_timeout are set later once we know all the other params */
1294 }
1295}
1296
1297
1298static void configure_totem_links(struct totem_config *totem_config, icmap_map_t map)
1299{
1300 int i;
1301
1302 for (i = 0; i<INTERFACE_MAX; i++) {
1304 continue;
1305 }
1306
1307 log_printf(LOGSYS_LEVEL_INFO, "Configuring link %d\n", i);
1308
1310 }
1311}
1312
1313/* Check for differences in config that can't be done on-the-fly and print an error */
1314static int check_things_have_not_changed(struct totem_config *totem_config, const char **error_string)
1315{
1316 int i,j,k;
1317 const char *ip_str;
1319 int changed = 0;
1320
1321 for (i = 0; i<INTERFACE_MAX; i++) {
1327 "New config has different knet transport for link %d. Internal value was NOT changed.\n", i);
1328 changed = 1;
1329 }
1330
1331 /* Check each nodeid in the new configuration and make sure its IP address on this link has not changed */
1332 for (j=0; j < totem_config->interfaces[i].member_count; j++) {
1333 for (k=0; k < totem_config->orig_interfaces[i].member_count; k++) {
1334
1337
1338 /* Found our nodeid - check the IP address */
1341 sizeof(struct totem_ip_address))) {
1342
1344
1345 /* if ip_str is NULL then the old address was invalid and is allowed to change */
1346 if (ip_str) {
1347 strncpy(addr_buf, ip_str, sizeof(addr_buf));
1348 addr_buf[sizeof(addr_buf) - 1] = '\0';
1350 "new config has different address for link %d (addr changed from %s to %s). Internal value was NOT changed.\n",
1352 changed = 1;
1353 }
1354 }
1355 }
1356 }
1357 }
1358 }
1359 }
1360
1361 if (changed) {
1362 snprintf (error_string_response, sizeof(error_string_response),
1363 "To reconfigure an interface it must be deleted and recreated. A working interface needs to be available to corosync at all times");
1364 *error_string = error_string_response;
1365 return -1;
1366 }
1367 return 0;
1368}
1369
1370
1371static int put_nodelist_members_to_config(struct totem_config *totem_config, icmap_map_t map,
1372 int reload, const char **error_string)
1373{
1375 const char *iter_key, *iter_key2;
1376 int res = 0;
1377 unsigned int node_pos;
1380 char *node_addr_str;
1381 int member_count;
1382 unsigned int linknumber = 0;
1383 int i, j;
1384 int last_node_pos = -1;
1385
1386 /* Clear out nodelist so we can put the new one in if needed */
1387 for (i = 0; i < INTERFACE_MAX; i++) {
1388 for (j = 0; j < PROCESSOR_COUNT_MAX; j++) {
1390 }
1392 }
1393
1394 iter = icmap_iter_init_r(map, "nodelist.node.");
1395 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1396 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
1397 if (res != 2) {
1398 continue;
1399 }
1400 /* If it's the same as the last node_pos then skip it */
1401 if (node_pos == last_node_pos) {
1402 continue;
1403 }
1405
1406 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
1408 while ((iter_key2 = icmap_iter_next(iter2, NULL, NULL)) != NULL) {
1409 unsigned int nodeid;
1410
1411 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
1413 nodeid = 0;
1414 }
1415
1416 res = sscanf(iter_key2, "nodelist.node.%u.ring%u%s", &node_pos, &linknumber, tmp_key2);
1417 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
1418 continue;
1419 }
1420 if (linknumber >= INTERFACE_MAX) {
1421 snprintf (error_string_response, sizeof(error_string_response),
1422 "parse error in config: interface ring number %u is bigger than allowed maximum %u\n",
1423 linknumber, INTERFACE_MAX - 1);
1424 *error_string = error_string_response;
1425
1428 return (-1);
1429 }
1430
1432 continue;
1433 }
1434
1435#ifdef ENABLE_UDPU
1436 /* Generate nodeids if they are not provided and transport is UDP/U */
1437 if (!nodeid &&
1440 char *str;
1441
1442 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos);
1443 if (icmap_get_string_r(map, tmp_key, &str) == CS_OK) {
1444 nodeid = generate_nodeid(totem_config, str);
1445 if (nodeid == -1) {
1446 sprintf(error_string_response,
1447 "An IPV6 network requires that a node ID be specified "
1448 "for address '%s'.", node_addr_str);
1449 *error_string = error_string_response;
1450 free(str);
1451
1452 return (-1);
1453 }
1454
1456 "Generated nodeid = " CS_PRI_NODE_ID " for %s", nodeid, str);
1457
1458 free(str);
1459 /*
1460 * Put nodeid back to nodelist to make cfgtool work
1461 */
1462 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
1463 /*
1464 * Not critical
1465 */
1467 }
1468 }
1469#endif
1470
1472 sprintf(error_string_response,
1473 "Knet requires an explicit nodeid to be specified "
1474 "for address '%s'.", node_addr_str);
1475 *error_string = error_string_response;
1476
1477 return (-1);
1478 }
1479
1481 sprintf(error_string_response,
1482 "Knet requires nodeid to be less than %u "
1483 "for address '%s'.", KNET_MAX_HOST, node_addr_str);
1484 *error_string = error_string_response;
1485
1486 return (-1);
1487 }
1488
1489 member_count = totem_config->interfaces[linknumber].member_count;
1490 res = totemip_parse(&totem_config->interfaces[linknumber].member_list[member_count],
1492 if (res == 0) {
1493 totem_config->interfaces[linknumber].member_list[member_count].nodeid = nodeid;
1494 totem_config->interfaces[linknumber].member_count++;
1495 totem_config->interfaces[linknumber].configured = 1;
1496 } else {
1497 sprintf(error_string_response, "failed to parse node address '%s'\n", node_addr_str);
1498 *error_string = error_string_response;
1499
1500 memset(&totem_config->interfaces[linknumber].member_list[member_count], 0,
1501 sizeof(struct totem_ip_address));
1502
1506 return -1;
1507 }
1508
1510 }
1511
1513 }
1514
1516
1517 configure_link_params(totem_config, map);
1518 if (reload) {
1519 log_printf(LOGSYS_LEVEL_DEBUG, "About to reconfigure links from nodelist.\n");
1520
1521 if (check_things_have_not_changed(totem_config, error_string) == -1) {
1522 return -1;
1523 }
1524 }
1525 return 0;
1526}
1527
1528static void config_convert_nodelist_to_interface(icmap_map_t map, struct totem_config *totem_config)
1529{
1530 int res = 0;
1531 int node_pos;
1534 char *node_addr_str;
1535 unsigned int linknumber = 0;
1537 const char *iter_key;
1538
1539 node_pos = find_local_node(map, 1);
1540 if (node_pos > -1) {
1541 /*
1542 * We found node, so create interface section
1543 */
1544 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
1546 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1547 res = sscanf(iter_key, "nodelist.node.%u.ring%u%s", &node_pos, &linknumber, tmp_key2);
1548 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
1549 continue ;
1550 }
1551
1553 continue;
1554 }
1555
1556 snprintf(tmp_key2, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", linknumber);
1559 }
1561 }
1562}
1563
1564static int get_interface_params(struct totem_config *totem_config, icmap_map_t map,
1565 const char **error_string, uint64_t *warnings,
1566 int reload)
1567{
1568 int res = 0;
1569 unsigned int linknumber = 0;
1570 int member_count = 0;
1571 int i;
1573 const char *iter_key;
1574 const char *member_iter_key;
1577 uint8_t u8;
1578 uint32_t u32;
1579 char *str;
1580 char *cluster_name = NULL;
1581 int ret = 0;
1582
1583 if (reload) {
1584 for (i=0; i<INTERFACE_MAX; i++) {
1585 /*
1586 * Set back to defaults things that might have been configured and
1587 * now have been taken out of corosync.conf. These won't be caught by the
1588 * code below which only looks at interface{} sections that actually exist.
1589 */
1595 }
1596 }
1597 if (icmap_get_string_r(map, "totem.cluster_name", &cluster_name) != CS_OK) {
1599 }
1600
1601 iter = icmap_iter_init_r(map, "totem.interface.");
1602 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1603 res = sscanf(iter_key, "totem.interface.%[^.].%s", linknumber_key, tmp_key);
1604 if (res != 2) {
1605 continue;
1606 }
1607
1608#ifdef ENABLE_UDPU
1609 if (strcmp(tmp_key, "bindnetaddr") != 0 && totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
1610 continue;
1611 }
1612#endif
1613
1614 member_count = 0;
1615 linknumber = atoi(linknumber_key);
1616
1617 if (linknumber >= INTERFACE_MAX) {
1618 snprintf (error_string_response, sizeof(error_string_response),
1619 "parse error in config: interface ring number %u is bigger than allowed maximum %u\n",
1620 linknumber, INTERFACE_MAX - 1);
1621
1622 *error_string = error_string_response;
1623 ret = -1;
1624 goto out;
1625 }
1626
1627 /* These things are only valid for the initial read */
1628 if (!reload) {
1629 /*
1630 * Get the bind net address
1631 */
1632 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", linknumber);
1633
1634 if (icmap_get_string_r(map, tmp_key, &str) == CS_OK) {
1637
1638 if (res) {
1639 sprintf(error_string_response, "failed to parse bindnet address '%s'\n", str);
1640 *error_string = error_string_response;
1641 free(str);
1642
1643 ret = -1;
1644 goto out;
1645 }
1646
1647 free(str);
1648 }
1649
1650 /*
1651 * Get interface multicast address
1652 */
1653 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", linknumber);
1654 if (icmap_get_string_r(map, tmp_key, &str) == CS_OK) {
1657
1658 if (res) {
1659 sprintf(error_string_response, "failed to parse mcast address '%s'\n", str);
1660 *error_string = error_string_response;
1661 free(str);
1662
1663 ret = -1;
1664 goto out;
1665 }
1666
1667 free(str);
1668 }
1669#ifdef ENABLE_UDPU
1671 /*
1672 * User not specified address -> autogenerate one from cluster_name key
1673 * (if available). Return code is intentionally ignored, because
1674 * udpu doesn't need mcastaddr and validity of mcastaddr for udp is
1675 * checked later anyway.
1676 */
1678
1681 } else if (totem_config->interfaces[0].bindnet.family == AF_INET6) {
1683 }
1684
1685 (void)get_cluster_mcast_addr (cluster_name,
1686 linknumber,
1688 &totem_config->interfaces[linknumber].mcast_addr);
1689 }
1690#endif
1691
1692 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", linknumber);
1693 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1694 if (strcmp (str, "yes") == 0) {
1696 }
1697 free(str);
1698 }
1699 }
1700
1701 /* These things are only valid for the initial read OR a newly-defined link */
1702 if (!reload || (totem_config->interfaces[linknumber].configured == 0)) {
1703
1704 /*
1705 * Get mcast port
1706 */
1707 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", linknumber);
1710 totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + (2 * linknumber);
1711 } else {
1712 totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + linknumber;
1713 }
1714 }
1715
1716 /*
1717 * Get the TTL
1718 */
1719 totem_config->interfaces[linknumber].ttl = 1;
1720
1721 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", linknumber);
1722
1723 if (icmap_get_uint8_r(map, tmp_key, &u8) == CS_OK) {
1724 totem_config->interfaces[linknumber].ttl = u8;
1725 }
1726
1728 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_transport", linknumber);
1729 if (icmap_get_string_r(map, tmp_key, &str) == CS_OK) {
1730#ifdef KNET_TRANSPORT_SCTP
1731 if (strcmp(str, "sctp") == 0) {
1733 log_printf(LOGSYS_LEVEL_WARNING, "WARNING SCTP transport is deprecated and will be removed in a future release.\n");
1734 } else
1735#endif
1736 if (strcmp(str, "udp") == 0) {
1738 }
1739 else {
1740#ifdef KNET_TRANSPORT_SCTP
1741 *error_string = "Unrecognised knet_transport. expected 'udp' or 'sctp'";
1742#else
1743 *error_string = "Unrecognised knet_transport. only 'udp' is supported";
1744#endif
1745 ret = -1;
1746 goto out;
1747 }
1748 }
1749 }
1750 totem_config->interfaces[linknumber].configured = 1;
1751
1752 /*
1753 * Get the knet link params
1754 */
1756 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_link_priority", linknumber);
1757
1758 if (icmap_get_uint8_r(map, tmp_key, &u8) == CS_OK) {
1760 }
1761
1762 totem_config->interfaces[linknumber].knet_ping_interval = 0; /* real default applied later */
1763 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_interval", linknumber);
1764 if (icmap_get_uint32_r(map, tmp_key, &u32) == CS_OK) {
1766 }
1767 totem_config->interfaces[linknumber].knet_ping_timeout = 0; /* real default applied later */
1768 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_timeout", linknumber);
1769 if (icmap_get_uint32_r(map, tmp_key, &u32) == CS_OK) {
1771 }
1773 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_precision", linknumber);
1774 if (icmap_get_uint32_r(map, tmp_key, &u32) == CS_OK) {
1776 }
1778 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_pong_count", linknumber);
1779 if (icmap_get_uint32_r(map, tmp_key, &u32) == CS_OK) {
1781 }
1782
1783 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.", linknumber);
1786 if (member_count == 0) {
1787 if (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK) {
1788 free(str);
1790 break;
1791 } else {
1793 }
1794 }
1795
1797 res = totemip_parse (&totem_config->interfaces[linknumber].member_list[member_count++],
1799 if (res) {
1800 sprintf(error_string_response, "failed to parse node address '%s'\n", str);
1801 *error_string = error_string_response;
1802
1804 free(str);
1805 ret = -1;
1806 goto out;
1807 }
1808
1809 free(str);
1810 }
1811 }
1813
1814 totem_config->interfaces[linknumber].member_count = member_count;
1815
1816 }
1817
1818out:
1821
1822 return (ret);
1823}
1824
1826 struct totem_config *totem_config,
1827 const char **error_string,
1829{
1830 int res = 0;
1831 char *str, *ring0_addr_str;
1833 int i;
1834 int local_node_pos;
1835 uint32_t u32;
1836
1837 *warnings = 0;
1838
1839 memset (totem_config, 0, sizeof (struct totem_config));
1841 if (totem_config->interfaces == 0) {
1842 *error_string = "Out of memory trying to allocate ethernet interface storage area";
1843 return -1;
1844 }
1845
1847 if (icmap_get_string("totem.transport", &str) == CS_OK) {
1848#ifdef ENABLE_UDPU
1849 if (strcmp (str, "udpu") == 0) {
1851 } else if (strcmp (str, "udp") == 0) {
1853 } else
1854#endif
1855 if (strcmp (str, "knet") == 0) {
1857 } else {
1858#ifdef ENABLE_UDPU
1859 *error_string = "Invalid transport type. Should be udpu, udp or knet";
1860#else
1861 *error_string = "Invalid transport type. Should be knet";
1862#endif
1863 free(str);
1864 return -1;
1865 }
1866
1867 free(str);
1868 }
1869
1872
1873 strcpy (totem_config->link_mode, "passive");
1874
1875 icmap_get_uint32("totem.version", (uint32_t *)&totem_config->version);
1876
1877 /* initial crypto load */
1878 if (totem_get_crypto(totem_config, icmap_get_global_map(), error_string) != 0) {
1879 return -1;
1880 }
1882 return -1;
1883 }
1886
1887 if (icmap_get_string("totem.link_mode", &str) == CS_OK) {
1889 *error_string = "totem.link_mode is too long";
1890 free(str);
1891
1892 return -1;
1893 }
1895 free(str);
1896 }
1897
1898 if (icmap_get_uint32("totem.nodeid", &u32) == CS_OK) {
1900 }
1901
1903 if (icmap_get_string("totem.clear_node_high_bit", &str) == CS_OK) {
1904 if (strcmp (str, "yes") == 0) {
1906 }
1907 free(str);
1908 }
1909
1910 icmap_get_uint32("totem.threads", &totem_config->threads);
1911
1912 icmap_get_uint32("totem.netmtu", &totem_config->net_mtu);
1913
1914 totem_config->ip_version = totem_config_get_ip_version(totem_config);
1915
1916 if (icmap_get_string("totem.interface.0.bindnetaddr", &str) != CS_OK) {
1917 /*
1918 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
1919 */
1920 config_convert_nodelist_to_interface(icmap_get_global_map(), totem_config);
1921 } else {
1922 if (icmap_get_string("nodelist.node.0.ring0_addr", &ring0_addr_str) == CS_OK) {
1923 /*
1924 * Both bindnetaddr and ring0_addr are set.
1925 * Log warning information, and use nodelist instead
1926 */
1928
1929 config_convert_nodelist_to_interface(icmap_get_global_map(), totem_config);
1930
1932 }
1933
1934 free(str);
1935 }
1936
1937 /*
1938 * Broadcast option is global but set in interface section,
1939 * so reset before processing interfaces.
1940 */
1942
1943 res = get_interface_params(totem_config, icmap_get_global_map(), error_string, warnings, 0);
1944 if (res < 0) {
1945 return res;
1946 }
1947
1948 /*
1949 * Use broadcast is global, so if set, make sure to fill mcast addr correctly
1950 * broadcast is only supported for UDP so just do interface 0;
1951 */
1954 "255.255.255.255", TOTEM_IP_VERSION_4);
1955 }
1956
1957 totem_config->ip_dscp = 0;
1958 (void)icmap_get_uint8("totem.ip_dscp", &totem_config->ip_dscp);
1959
1960#ifdef ENABLE_UDPU
1961 /*
1962 * Store automatically generated items back to icmap only for UDP
1963 */
1965 uint16_t u16;
1966
1967 for (i = 0; i < INTERFACE_MAX; i++) {
1969 continue;
1970 }
1971 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", i);
1972 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1973 free(str);
1974 } else {
1977 }
1978
1979 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", i);
1980 if (icmap_get_uint16(tmp_key, &u16) != CS_OK) {
1982 }
1983 }
1984 }
1985#endif
1986
1987 /*
1988 * Store mcastport value to cmap runtime section for KNET
1989 */
1991 for (i = 0; i < INTERFACE_MAX; i++) {
1993 continue;
1994 }
1995 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "runtime.config.totem.interface.%u.mcastport", i);
1997 }
1998 }
1999
2000 /*
2001 * Check existence of nodelist
2002 */
2003 if ((icmap_get_string("nodelist.node.0.name", &str) == CS_OK) ||
2004 (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK)) {
2005 free(str);
2006 /*
2007 * find local node
2008 */
2009 local_node_pos = find_local_node(icmap_get_global_map(), 1);
2010 if (local_node_pos != -1) {
2011
2013
2014 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", local_node_pos);
2016
2017
2019 *error_string = "Knet requires an explicit nodeid for the local node";
2020 return -1;
2021 }
2022
2023#ifdef ENABLE_UDPU
2026
2027 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", local_node_pos);
2029
2030 totem_config->node_id = generate_nodeid(totem_config, str);
2031 if (totem_config->node_id == -1) {
2032 *error_string = "An IPV6 network requires that a node ID be specified";
2033
2034 free(str);
2035 return (-1);
2036 }
2037
2039
2040 free(str);
2041 }
2042#endif
2043
2044 /* Users must not change this */
2045 icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
2046 }
2047
2048 if (put_nodelist_members_to_config(totem_config, icmap_get_global_map(), 0, error_string)) {
2049 return -1;
2050 }
2051 }
2052
2053 /*
2054 * Get things that might change in the future (and can depend on totem_config->interfaces);
2055 */
2057
2059
2060 /* This is now done in the totemknet interface callback */
2061 /* configure_totem_links(totem_config, icmap_get_global_map()); */
2062
2063 add_totem_config_notification(totem_config);
2064
2065 return 0;
2066}
2067
2068
2070 struct totem_config *totem_config,
2071 const char **error_string)
2072{
2073 static char local_error_reason[512];
2074 char parse_error[512];
2075 const char *error_reason = local_error_reason;
2076 int i;
2077 uint32_t u32;
2078 int num_configured = 0;
2079 unsigned int interface_max = INTERFACE_MAX;
2080
2081 for (i = 0; i < INTERFACE_MAX; i++) {
2084 }
2085 }
2086 if (num_configured == 0) {
2087 error_reason = "No interfaces defined";
2088 goto parse_error;
2089 }
2090
2091 /* Check we found a local node name */
2092 if (icmap_get_uint32("nodelist.local_node_pos", &u32) != CS_OK) {
2093 error_reason = "No valid name found for local host";
2094 goto parse_error;
2095 }
2096
2097 for (i = 0; i < INTERFACE_MAX; i++) {
2098 /*
2099 * Some error checking of parsed data to make sure its valid
2100 */
2101
2103
2105 continue;
2106 }
2107
2108 memset (&null_addr, 0, sizeof (struct totem_ip_address));
2109
2110#ifdef ENABLE_UDPU
2113 sizeof (struct totem_ip_address)) == 0) {
2115 "No multicast address specified for interface %u", i);
2116 goto parse_error;
2117 }
2118#endif
2119
2120 if (totem_config->interfaces[i].ip_port == 0) {
2122 "No multicast port specified for interface %u", i);
2123 goto parse_error;
2124 }
2125
2126 if (totem_config->interfaces[i].ttl > 255) {
2128 "Invalid TTL (should be 0..255) for interface %u", i);
2129 goto parse_error;
2130 }
2131#ifdef ENABLE_UDPU
2133 totem_config->interfaces[i].ttl != 1) {
2134#else
2135 if (totem_config->interfaces[i].ttl != 1) {
2136#endif
2138 "Can only set ttl on multicast transport types for interface %u", i);
2139 goto parse_error;
2140 }
2143 "Invalid link priority (should be 0..255) for interface %u", i);
2144 goto parse_error;
2145 }
2149 "Can only set link priority on knet transport type for interface %u", i);
2150 goto parse_error;
2151 }
2152
2154 totem_config->node_id == 0) {
2156 "An IPV6 network requires that a node ID be specified for interface %u", i);
2157 goto parse_error;
2158 }
2159
2160#ifdef ENABLE_UDPU
2164 "Multicast address family does not match bind address family for interface %u", i);
2165 goto parse_error;
2166 }
2167
2170 "mcastaddr is not a correct multicast address for interface %u", i);
2171 goto parse_error;
2172 }
2173 }
2174#endif
2175 }
2176
2177 if (totem_config->version != 2) {
2178 error_reason = "This totem parser can only parse version 2 configurations.";
2179 goto parse_error;
2180 }
2181
2183 return (-1);
2184 }
2185
2186 if (check_for_duplicate_nodeids(totem_config, error_string) == -1) {
2187 return (-1);
2188 }
2189
2190 /*
2191 * KNET Link values validation
2192 */
2193 if (strcmp (totem_config->link_mode, "active") &&
2194 strcmp (totem_config->link_mode, "rr") &&
2195 strcmp (totem_config->link_mode, "passive")) {
2197 "The Knet link mode \"%s\" specified is invalid. It must be active, passive or rr.\n", totem_config->link_mode);
2198 goto parse_error;
2199 }
2200
2201 /* Only Knet does multiple interfaces */
2203 interface_max = 1;
2204 }
2205
2208 "%d is too many configured interfaces for non-Knet transport.",
2211 goto parse_error;
2212 }
2213
2214 /* Only knet allows crypto */
2216 if ((strcmp(totem_config->crypto_cipher_type, "none") != 0) ||
2217 (strcmp(totem_config->crypto_hash_type, "none") != 0)) {
2218
2220 "crypto_cipher & crypto_hash are only valid for the Knet transport.");
2222 goto parse_error;
2223 }
2224 }
2225
2226 if (totem_config->net_mtu == 0) {
2229 }
2230 else {
2232 }
2233 }
2234
2235 return 0;
2236
2238 snprintf (error_string_response, sizeof(error_string_response),
2239 "parse error in config: %s\n", error_reason);
2240 *error_string = error_string_response;
2241 return (-1);
2242
2243}
2244
2245static int read_keyfile (
2246 const char *key_location,
2247 struct totem_config *totem_config,
2248 const char **error_string)
2249{
2250 int fd;
2251 int res;
2252 int saved_errno;
2253 char error_str[100];
2254 const char *error_ptr;
2255
2256 fd = open (key_location, O_RDONLY);
2257 if (fd == -1) {
2259 snprintf (error_string_response, sizeof(error_string_response),
2260 "Could not open %s: %s\n",
2262 goto parse_error;
2263 }
2264
2267 close (fd);
2268
2269 if (res == -1) {
2271 snprintf (error_string_response, sizeof(error_string_response),
2272 "Could not read %s: %s\n",
2274 goto parse_error;
2275 }
2276
2278 snprintf (error_string_response, sizeof(error_string_response),
2279 "Could only read %d bits of minimum %u bits from %s.\n",
2281 goto parse_error;
2282 }
2283
2285
2286 return 0;
2287
2289 *error_string = error_string_response;
2290 return (-1);
2291}
2292
2294 struct totem_config *totem_config,
2296 const char **error_string)
2297{
2298 int got_key = 0;
2299 char *key_location = NULL;
2300 int res;
2301 size_t key_len;
2303 size_t old_key_len;
2304
2305 /* Take a copy so we can see if it has changed */
2308
2311
2312 if (strcmp(totem_config->crypto_cipher_type, "none") == 0 &&
2313 strcmp(totem_config->crypto_hash_type, "none") == 0) {
2314 return (0);
2315 }
2316
2317 /* cmap may store the location of the key file */
2318 if (icmap_get_string_r(map, "totem.keyfile", &key_location) == CS_OK) {
2319 res = read_keyfile(key_location, totem_config, error_string);
2321 if (res) {
2322 goto key_error;
2323 }
2324 got_key = 1;
2325 } else { /* Or the key itself may be in the cmap */
2326 if (icmap_get_r(map, "totem.key", NULL, &key_len, NULL) == CS_OK) {
2327 if (key_len > sizeof(totem_config->private_key)) {
2328 sprintf(error_string_response, "key is too long");
2329 goto key_error;
2330 }
2332 sprintf(error_string_response, "key is too short");
2333 goto key_error;
2334 }
2335 if (icmap_get_r(map, "totem.key", totem_config->private_key, &key_len, NULL) == CS_OK) {
2337 got_key = 1;
2338 } else {
2339 sprintf(error_string_response, "can't load private key");
2340 goto key_error;
2341 }
2342 }
2343 }
2344
2345 /* In desperation we read the default filename */
2346 if (!got_key) {
2347 res = read_keyfile(COROSYSCONFDIR "/authkey", totem_config, error_string);
2348 if (res)
2349 goto key_error;
2350 }
2351
2355 }
2356
2357 return (0);
2358
2359key_error:
2360 *error_string = error_string_response;
2361 return (-1);
2362
2363}
2364
2366{
2367 if (totem_get_crypto(totem_config, map, error_string) != 0) {
2368 return -1;
2369 }
2371 return -1;
2372 }
2373 return 0;
2374}
2375
2376static void debug_dump_totem_config(const struct totem_config *totem_config)
2377{
2378
2379 log_printf(LOGSYS_LEVEL_DEBUG, "Token Timeout (%d ms) retransmit timeout (%d ms)",
2383 log_printf(LOGSYS_LEVEL_DEBUG, "Token warning every %d ms (%d%% of Token Timeout)",
2385 if (token_warning_ms < totem_config->token_retransmit_timeout)
2387 "The token warning interval (%d ms) is less than the token retransmit timeout (%d ms) "
2388 "which can lead to spurious token warnings. Consider increasing the token_warning parameter.",
2390
2391 } else
2392 log_printf(LOGSYS_LEVEL_DEBUG, "Token warnings disabled");
2393 log_printf(LOGSYS_LEVEL_DEBUG, "token hold (%d ms) retransmits before loss (%d retrans)",
2395 log_printf(LOGSYS_LEVEL_DEBUG, "join (%d ms) send_join (%d ms) consensus (%d ms) merge (%d ms)",
2398 log_printf(LOGSYS_LEVEL_DEBUG, "downcheck (%d ms) fail to recv const (%d msgs)",
2401 "seqno unchanged const (%d rotations) Maximum network MTU %d",
2404 "window size per rotation (%d messages) maximum messages per rotation (%d messages)",
2406 log_printf(LOGSYS_LEVEL_DEBUG, "missed count const (%d messages)", totem_config->miss_count_const);
2407 log_printf(LOGSYS_LEVEL_DEBUG, "heartbeat_failures_allowed (%d)",
2409 log_printf(LOGSYS_LEVEL_DEBUG, "max_network_delay (%d ms)", totem_config->max_network_delay);
2410}
2411
2412
2413static void totem_change_notify(
2414 int32_t event,
2415 const char *key_name,
2418 void *user_data)
2419{
2420 struct totem_config *totem_config = (struct totem_config *)user_data;
2421 uint32_t *param;
2423 const char *deleted_key = NULL;
2424 const char *error_string;
2425
2426 /*
2427 * If a full reload is in progress then don't do anything until it's done and
2428 * can reconfigure it all atomically
2429 */
2430 if (icmap_get_uint8("config.reload_in_progress", &reloading) == CS_OK && reloading)
2431 return;
2432
2433 param = totem_get_param_by_name((struct totem_config *)user_data, key_name);
2434 /*
2435 * Process change only if changed key is found in totem_config (-> param is not NULL)
2436 * or for special key token_coefficient. token_coefficient key is not stored in
2437 * totem_config, but it is used for computation of token timeout.
2438 */
2439 if (!param && strcmp(key_name, "totem.token_coefficient") != 0)
2440 return;
2441
2442 /*
2443 * Values other than UINT32 are not supported, or needed (yet)
2444 */
2445 switch (event) {
2446 case ICMAP_TRACK_DELETE:
2447 deleted_key = key_name;
2448 break;
2449 case ICMAP_TRACK_ADD:
2450 case ICMAP_TRACK_MODIFY:
2451 deleted_key = NULL;
2452 break;
2453 default:
2454 break;
2455 }
2456
2458 log_printf(LOGSYS_LEVEL_DEBUG, "Totem related config key changed. Dumping actual totem config.");
2459 debug_dump_totem_config(totem_config);
2462 /*
2463 * TODO: Consider corosync exit and/or load defaults for volatile
2464 * values. For now, log error seems to be enough
2465 */
2466 }
2467}
2468
2469
2471 struct totem_config *totem_config,
2473 const char **error_string)
2474{
2475 uint64_t warnings = 0LL;
2476
2477 get_interface_params(totem_config, map, error_string, &warnings, 1);
2478 if (put_nodelist_members_to_config (totem_config, map, 1, error_string)) {
2479 return -1;
2480 }
2481
2482 log_printf(LOGSYS_LEVEL_DEBUG, "Configuration reloaded. Dumping actual totem config.");
2483 debug_dump_totem_config(totem_config);
2484
2485 /* Reinstate the local_node_pos */
2486 (void)find_local_node(map, 0);
2487
2488 return 0;
2489}
2490
2492 struct totem_config *totem_config,
2494{
2495 int res;
2497
2498 new_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
2501
2502 /* Set link parameters including local_ip */
2503 configure_totem_links(totem_config, map);
2504
2505 /* Add & remove nodes & link properties */
2506 res = compute_and_set_totempg_interfaces(totem_config->orig_interfaces, new_interfaces);
2507
2508 /* Does basic global params (like compression) */
2510
2512
2513 /*
2514 * On a reload this return is ignored because it's too late to do anything about it,
2515 * but errors are reported back via cmap.
2516 */
2517 return res;
2518
2519}
2520
2521static void add_totem_config_notification(struct totem_config *totem_config)
2522{
2524
2525 icmap_track_add("totem.",
2527 totem_change_notify,
2529 &icmap_track);
2530}
#define COROSYSCONFDIR
Definition config.h:8
#define INTERFACE_MAX
Definition coroapi.h:88
unsigned int nodeid
the ID of the node whose info needs updating
Definition coroapi.h:0
unsigned char addr[TOTEMIP_ADDRLEN]
Definition coroapi.h:2
#define PROCESSOR_COUNT_MAX
Definition coroapi.h:96
#define CS_PRI_NODE_ID
Definition corotypes.h:59
@ CS_OK
Definition corotypes.h:99
uint8_t param
uint32_t value
icmap_iter_t icmap_iter_init_r(const icmap_map_t map, const char *prefix)
icmap_iter_init_r
Definition icmap.c:1088
cs_error_t icmap_get_uint8(const char *key_name, uint8_t *u8)
Definition icmap.c:872
#define ICMAP_TRACK_MODIFY
Definition icmap.h:78
cs_error_t icmap_get_string_r(const icmap_map_t map, const char *key_name, char **str)
Definition icmap.c:739
cs_error_t icmap_get_uint16(const char *key_name, uint16_t *u16)
Definition icmap.c:884
cs_error_t icmap_get_uint32(const char *key_name, uint32_t *u32)
Definition icmap.c:896
cs_error_t icmap_set_ro_access(const char *key_name, int prefix, int ro_access)
Set read-only access for given key (key_name) or prefix, If prefix is set.
Definition icmap.c:1229
cs_error_t icmap_set_uint32_r(const icmap_map_t map, const char *key_name, uint32_t value)
Definition icmap.c:531
cs_error_t icmap_get_uint8_r(const icmap_map_t map, const char *key_name, uint8_t *u8)
Definition icmap.c:806
#define ICMAP_TRACK_DELETE
Definition icmap.h:77
cs_error_t icmap_set_uint16(const char *key_name, uint16_t value)
Definition icmap.c:589
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:1163
cs_error_t icmap_set_string(const char *key_name, const char *value)
Definition icmap.c:631
#define ICMAP_TRACK_PREFIX
Whole prefix is tracked, instead of key only (so "totem." tracking means that "totem....
Definition icmap.h:85
icmap_iter_t icmap_iter_init(const char *prefix)
Initialize iterator with given prefix.
Definition icmap.c:1093
cs_error_t icmap_get_uint16_r(const icmap_map_t map, const char *key_name, uint16_t *u16)
Definition icmap.c:818
cs_error_t icmap_set_int32_r(const icmap_map_t map, const char *key_name, int32_t value)
Definition icmap.c:525
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
icmap_map_t icmap_get_global_map(void)
Return global icmap.
Definition icmap.c:268
qb_map_iter_t * icmap_iter_t
Itterator type.
Definition icmap.h:123
cs_error_t icmap_set_string_r(const icmap_map_t map, const char *key_name, const char *value)
Definition icmap.c:561
void icmap_iter_finalize(icmap_iter_t iter)
Finalize iterator.
Definition icmap.c:1120
cs_error_t icmap_get_int32_r(const icmap_map_t map, const char *key_name, int32_t *i32)
Definition icmap.c:824
cs_error_t icmap_get_r(const icmap_map_t map, const char *key_name, void *value, size_t *value_len, icmap_value_types_t *type)
Same as icmap_get but it's reentrant and operates on given icmap_map.
Definition icmap.c:696
#define ICMAP_KEYNAME_MAXLEN
Maximum length of key in icmap.
Definition icmap.h:48
cs_error_t icmap_get_uint32_r(const icmap_map_t map, const char *key_name, uint32_t *u32)
Definition icmap.c:830
#define ICMAP_TRACK_ADD
Definition icmap.h:76
cs_error_t icmap_get_string(const char *key_name, char **str)
Shortcut for icmap_get for string type.
Definition icmap.c:860
#define LOGSYS_LEVEL_ERROR
Definition logsys.h:72
#define log_printf(level, format, args...)
Definition logsys.h:332
#define LOGSYS_LEVEL_INFO
Definition logsys.h:75
#define LOGSYS_LEVEL_WARNING
Definition logsys.h:73
#define LOGSYS_LEVEL_DEBUG
Definition logsys.h:76
void * user_data
Definition sam.c:127
Structure passed as new_value and old_value in change callback.
Definition icmap.h:91
char crypto_model[CONFIG_STRING_LEN_MAX]
Definition totem.h:230
unsigned int max_messages
Definition totem.h:226
unsigned int heartbeat_failures_allowed
Definition totem.h:220
unsigned int token_timeout
Definition totem.h:188
unsigned int private_key_len
Definition totem.h:183
unsigned int knet_mtu
Definition totem.h:176
unsigned int node_id
Definition totem.h:173
unsigned int broadcast_use
Definition totem.h:228
uint32_t knet_compression_threshold
Definition totem.h:242
unsigned int window_size
Definition totem.h:224
unsigned int downcheck_timeout
Definition totem.h:206
unsigned int miss_count_const
Definition totem.h:248
totem_transport_t transport_number
Definition totem.h:246
struct totem_interface * interfaces
Definition totem.h:171
int crypto_changed
Definition totem.h:238
unsigned int cancel_token_hold_on_retransmit
Definition totem.h:254
unsigned int fail_to_recv_const
Definition totem.h:208
unsigned int clear_node_high_bit
Definition totem.h:174
unsigned int merge_timeout
Definition totem.h:204
struct totem_interface * orig_interfaces
Definition totem.h:172
unsigned char ip_dscp
Definition totem.h:256
int knet_compression_level
Definition totem.h:244
unsigned int net_mtu
Definition totem.h:216
int version
Definition totem.h:166
char knet_compression_model[CONFIG_STRING_LEN_MAX]
Definition totem.h:240
unsigned int block_unlisted_ips
Definition totem.h:252
unsigned int token_retransmits_before_loss_const
Definition totem.h:196
unsigned char private_key[TOTEM_PRIVATE_KEY_LEN_MAX]
Definition totem.h:181
int crypto_index
Definition totem.h:236
unsigned int max_network_delay
Definition totem.h:222
unsigned int seqno_unchanged_const
Definition totem.h:210
unsigned int consensus_timeout
Definition totem.h:202
unsigned int knet_pmtud_interval
Definition totem.h:175
char crypto_cipher_type[CONFIG_STRING_LEN_MAX]
Definition totem.h:232
unsigned int threads
Definition totem.h:218
unsigned int send_join_timeout
Definition totem.h:200
char link_mode[TOTEM_LINK_MODE_BYTES]
Definition totem.h:212
enum totem_ip_version_enum ip_version
Definition totem.h:250
unsigned int token_retransmit_timeout
Definition totem.h:192
char crypto_hash_type[CONFIG_STRING_LEN_MAX]
Definition totem.h:234
unsigned int token_warning
Definition totem.h:190
unsigned int join_timeout
Definition totem.h:198
unsigned int token_hold_timeout
Definition totem.h:194
struct totem_ip_address local_ip
Definition totem.h:86
int knet_ping_timeout
Definition totem.h:93
int knet_link_priority
Definition totem.h:91
uint16_t ip_port
Definition totem.h:87
int knet_ping_interval
Definition totem.h:92
uint8_t configured
Definition totem.h:89
int knet_ping_precision
Definition totem.h:94
int knet_pong_count
Definition totem.h:95
int knet_transport
Definition totem.h:96
int member_count
Definition totem.h:90
struct totem_ip_address bindnet
Definition totem.h:83
struct totem_ip_address member_list[PROCESSOR_COUNT_MAX]
Definition totem.h:97
uint16_t ttl
Definition totem.h:88
struct totem_ip_address mcast_addr
Definition totem.h:85
The totem_ip_address struct.
Definition coroapi.h:111
unsigned int nodeid
Definition coroapi.h:112
unsigned short family
Definition coroapi.h:113
#define swab32(x)
The swab32 macro.
Definition swab.h:51
@ TOTEM_LINK_MODE_BYTES
Definition totem.h:140
@ TOTEM_PRIVATE_KEY_LEN_MAX
Definition totem.h:137
@ TOTEM_PRIVATE_KEY_LEN_MIN
Definition totem.h:136
#define CONFIG_STRING_LEN_MAX
Definition totem.h:54
@ TOTEM_TRANSPORT_UDPU
Definition totem.h:150
@ TOTEM_TRANSPORT_KNET
Definition totem.h:151
@ TOTEM_TRANSPORT_UDP
Definition totem.h:149
#define MINIMUM_TIMEOUT
Definition totemconfig.c:77
#define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST
Definition totemconfig.c:68
#define JOIN_TIMEOUT
Definition totemconfig.c:72
#define DEFAULT_PORT
Definition totemconfig.c:97
#define MAX_MESSAGES
Definition totemconfig.c:81
#define MAX_NETWORK_DELAY
Definition totemconfig.c:79
#define KNET_PONG_COUNT
Definition totemconfig.c:92
#define KNET_PMTUD_INTERVAL
Definition totemconfig.c:93
#define MINIMUM_TIMEOUT_HOLD
Definition totemconfig.c:78
#define TOKEN_COEFFICIENT
Definition totemconfig.c:71
#define SEQNO_UNCHANGED_CONST
Definition totemconfig.c:76
void totem_volatile_config_read(struct totem_config *totem_config, icmap_map_t temp_map, const char *deleted_key)
int totem_config_read(struct totem_config *totem_config, const char **error_string, uint64_t *warnings)
#define MISS_COUNT_CONST
Definition totemconfig.c:82
int totemconfig_commit_new_params(struct totem_config *totem_config, icmap_map_t map)
int totem_volatile_config_validate(struct totem_config *totem_config, icmap_map_t temp_map, const char **error_string)
#define TOKEN_WARNING
Definition totemconfig.c:70
#define KNET_MTU
Definition totemconfig.c:94
int totem_reread_crypto_config(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
#define MERGE_TIMEOUT
Definition totemconfig.c:73
#define KNET_PING_PRECISION
Definition totemconfig.c:91
int totem_config_validate(struct totem_config *totem_config, const char **error_string)
#define BLOCK_UNLISTED_IPS
Definition totemconfig.c:83
#define KNET_DEFAULT_TRANSPORT
Definition totemconfig.c:95
#define UDP_NETMTU
Definition totemconfig.c:86
#define CANCEL_TOKEN_HOLD_ON_RETRANSMIT
Definition totemconfig.c:84
#define FAIL_TO_RECV_CONST
Definition totemconfig.c:75
void totem_calc_knet_ping_timers(struct totem_config *totem_config, icmap_map_t temp_map)
#define WINDOW_SIZE
Definition totemconfig.c:80
#define DOWNCHECK_TIMEOUT
Definition totemconfig.c:74
#define TOKEN_TIMEOUT
Definition totemconfig.c:69
int totemconfig_configure_new_params(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
int totem_config_keyread(struct totem_config *totem_config, icmap_map_t map, const char **error_string)
#define TOTEM_CONFIG_BINDNETADDR_NODELIST_SET
Definition totemconfig.h:48
#define TOTEM_CONFIG_WARNING_TOTEM_NODEID_SET
Definition totemconfig.h:47
#define TOTEM_CONFIG_WARNING_MEMBERS_IGNORED
Definition totemconfig.h:45
#define TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED
Definition totemconfig.h:46
int totemip_parse(struct totem_ip_address *totemip, const char *addr, enum totem_ip_version_enum ip_version)
Definition totemip.c:306
const char * totemip_print(const struct totem_ip_address *addr)
Definition totemip.c:256
totem_ip_version_enum
Definition totemip.h:70
@ TOTEM_IP_VERSION_6_4
Definition totemip.h:74
@ TOTEM_IP_VERSION_4
Definition totemip.h:71
@ TOTEM_IP_VERSION_6
Definition totemip.h:72
@ TOTEM_IP_VERSION_4_6
Definition totemip.h:73
int totemip_is_mcast(struct totem_ip_address *addr)
Definition totemip.c:134
int totempg_iface_set(struct totem_ip_address *interface_addr, unsigned short ip_port, unsigned int iface_no)
Definition totempg.c:1444
int totempg_reconfigure(void)
Definition totempg.c:1576
int totempg_member_remove(const struct totem_ip_address *member, int ring_no)
Definition totempg.c:1569
int totempg_member_add(const struct totem_ip_address *member, int ring_no)
Definition totempg.c:1562