2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006-2012 Red Hat, Inc.
7 * Author: Steven Dake (sdake@redhat.com)
8 * Jan Friesse (jfriesse@redhat.com)
10 * This software licensed under BSD license, the text of which follows:
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * - Neither the name of the MontaVista Software, Inc. nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGE.
44 #include <sys/socket.h>
45 #include <sys/types.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <sys/param.h>
52 #include <corosync/swab.h>
53 #include <corosync/list.h>
54 #include <qb/qbdefs.h>
55 #include <corosync/totem/totem.h>
56 #include <corosync/config.h>
57 #include <corosync/logsys.h>
58 #include <corosync/icmap.h>
61 #include "totemconfig.h"
63 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
64 #define TOKEN_TIMEOUT 1000
65 #define JOIN_TIMEOUT 50
66 #define MERGE_TIMEOUT 200
67 #define DOWNCHECK_TIMEOUT 1000
68 #define FAIL_TO_RECV_CONST 2500
69 #define SEQNO_UNCHANGED_CONST 30
70 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3
71 #define MAX_NETWORK_DELAY 50
72 #define WINDOW_SIZE 50
73 #define MAX_MESSAGES 17
74 #define MISS_COUNT_CONST 5
75 #define RRP_PROBLEM_COUNT_TIMEOUT 2000
76 #define RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT 10
77 #define RRP_PROBLEM_COUNT_THRESHOLD_MIN 2
78 #define RRP_AUTORECOVERY_CHECK_TIMEOUT 1000
80 #define DEFAULT_PORT 5405
82 static char error_string_response
[512];
84 static void add_totem_config_notification(struct totem_config
*totem_config
);
86 static void totem_volatile_config_read (struct totem_config
*totem_config
)
90 icmap_get_uint32("totem.token", &totem_config
->token_timeout
);
91 icmap_get_uint32("totem.token_retransmit", &totem_config
->token_retransmit_timeout
);
92 icmap_get_uint32("totem.hold", &totem_config
->token_hold_timeout
);
93 icmap_get_uint32("totem.token_retransmits_before_loss_const", &totem_config
->token_retransmits_before_loss_const
);
94 icmap_get_uint32("totem.join", &totem_config
->join_timeout
);
95 icmap_get_uint32("totem.send_join", &totem_config
->send_join_timeout
);
96 icmap_get_uint32("totem.consensus", &totem_config
->consensus_timeout
);
97 icmap_get_uint32("totem.merge", &totem_config
->merge_timeout
);
98 icmap_get_uint32("totem.downcheck", &totem_config
->downcheck_timeout
);
99 icmap_get_uint32("totem.fail_recv_const", &totem_config
->fail_to_recv_const
);
100 icmap_get_uint32("totem.seqno_unchanged_const", &totem_config
->seqno_unchanged_const
);
101 icmap_get_uint32("totem.rrp_token_expired_timeout", &totem_config
->rrp_token_expired_timeout
);
102 icmap_get_uint32("totem.rrp_problem_count_timeout", &totem_config
->rrp_problem_count_timeout
);
103 icmap_get_uint32("totem.rrp_problem_count_threshold", &totem_config
->rrp_problem_count_threshold
);
104 icmap_get_uint32("totem.rrp_problem_count_mcast_threshold", &totem_config
->rrp_problem_count_mcast_threshold
);
105 icmap_get_uint32("totem.rrp_autorecovery_check_timeout", &totem_config
->rrp_autorecovery_check_timeout
);
106 icmap_get_uint32("totem.heartbeat_failures_allowed", &totem_config
->heartbeat_failures_allowed
);
107 icmap_get_uint32("totem.max_network_delay", &totem_config
->max_network_delay
);
108 icmap_get_uint32("totem.window_size", &totem_config
->window_size
);
109 icmap_get_uint32("totem.max_messages", &totem_config
->max_messages
);
110 icmap_get_uint32("totem.miss_count_const", &totem_config
->miss_count_const
);
111 if (icmap_get_string("totem.vsftype", &str
) == CS_OK
) {
112 totem_config
->vsf_type
= str
;
117 static void totem_get_crypto(struct totem_config
*totem_config
)
120 const char *tmp_cipher
;
121 const char *tmp_hash
;
124 tmp_cipher
= "aes256";
126 if (icmap_get_string("totem.secauth", &str
) == CS_OK
) {
127 if (strcmp (str
, "off") == 0) {
134 if (icmap_get_string("totem.crypto_cipher", &str
) == CS_OK
) {
135 if (strcmp(str
, "none") == 0) {
138 if (strcmp(str
, "aes256") == 0) {
139 tmp_cipher
= "aes256";
141 if (strcmp(str
, "aes192") == 0) {
142 tmp_cipher
= "aes192";
144 if (strcmp(str
, "aes128") == 0) {
145 tmp_cipher
= "aes128";
147 if (strcmp(str
, "3des") == 0) {
153 if (icmap_get_string("totem.crypto_hash", &str
) == CS_OK
) {
154 if (strcmp(str
, "none") == 0) {
157 if (strcmp(str
, "md5") == 0) {
160 if (strcmp(str
, "sha1") == 0) {
163 if (strcmp(str
, "sha256") == 0) {
166 if (strcmp(str
, "sha384") == 0) {
169 if (strcmp(str
, "sha512") == 0) {
175 free(totem_config
->crypto_cipher_type
);
176 free(totem_config
->crypto_hash_type
);
178 totem_config
->crypto_cipher_type
= strdup(tmp_cipher
);
179 totem_config
->crypto_hash_type
= strdup(tmp_hash
);
182 static uint16_t generate_cluster_id (const char *cluster_name
)
187 for (i
= 0; i
< strlen(cluster_name
); i
++) {
189 value
+= cluster_name
[i
];
192 return (value
& 0xFFFF);
195 static int get_cluster_mcast_addr (
196 const char *cluster_name
,
197 const struct totem_ip_address
*bindnet
,
198 unsigned int ringnumber
,
200 struct totem_ip_address
*res
)
203 char addr
[INET6_ADDRSTRLEN
+ 1];
206 if (cluster_name
== NULL
) {
210 clusterid
= generate_cluster_id(cluster_name
) + ringnumber
;
211 memset (res
, 0, sizeof(res
));
213 switch (bindnet
->family
) {
215 snprintf(addr
, sizeof(addr
), "239.192.%d.%d", clusterid
>> 8, clusterid
% 0xFF);
218 snprintf(addr
, sizeof(addr
), "ff15::%x", clusterid
);
227 err
= totemip_parse (res
, addr
, ip_version
);
232 static int find_local_node_in_nodelist(struct totem_config
*totem_config
)
235 const char *iter_key
;
238 int local_node_pos
= -1;
239 struct totem_ip_address bind_addr
;
240 int interface_up
, interface_num
;
241 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
243 struct totem_ip_address node_addr
;
245 res
= totemip_iface_check(&totem_config
->interfaces
[0].bindnet
,
246 &bind_addr
, &interface_up
, &interface_num
,
247 totem_config
->clear_node_high_bit
);
252 iter
= icmap_iter_init("nodelist.node.");
253 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
254 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, tmp_key
);
259 if (strcmp(tmp_key
, "ring0_addr") != 0) {
263 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", node_pos
);
264 if (icmap_get_string(tmp_key
, &node_addr_str
) != CS_OK
) {
268 res
= totemip_parse (&node_addr
, node_addr_str
, totem_config
->ip_version
);
274 if (totemip_equal(&bind_addr
, &node_addr
)) {
275 local_node_pos
= node_pos
;
278 icmap_iter_finalize(iter
);
280 return (local_node_pos
);
283 static void put_nodelist_members_to_config(struct totem_config
*totem_config
)
285 icmap_iter_t iter
, iter2
;
286 const char *iter_key
, *iter_key2
;
289 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
290 char tmp_key2
[ICMAP_KEYNAME_MAXLEN
];
293 unsigned int ringnumber
= 0;
295 iter
= icmap_iter_init("nodelist.node.");
296 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
297 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, tmp_key
);
302 if (strcmp(tmp_key
, "ring0_addr") != 0) {
306 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.", node_pos
);
307 iter2
= icmap_iter_init(tmp_key
);
308 while ((iter_key2
= icmap_iter_next(iter2
, NULL
, NULL
)) != NULL
) {
309 res
= sscanf(iter_key2
, "nodelist.node.%u.ring%u%s", &node_pos
, &ringnumber
, tmp_key2
);
310 if (res
!= 3 || strcmp(tmp_key2
, "_addr") != 0) {
314 if (icmap_get_string(iter_key2
, &node_addr_str
) != CS_OK
) {
318 member_count
= totem_config
->interfaces
[ringnumber
].member_count
;
320 res
= totemip_parse(&totem_config
->interfaces
[ringnumber
].member_list
[member_count
],
321 node_addr_str
, totem_config
->ip_version
);
323 totem_config
->interfaces
[ringnumber
].member_count
++;
328 icmap_iter_finalize(iter2
);
331 icmap_iter_finalize(iter
);
334 static void config_convert_nodelist_to_interface(struct totem_config
*totem_config
)
337 const char *iter_key
;
340 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
341 char tmp_key2
[ICMAP_KEYNAME_MAXLEN
];
343 unsigned int ringnumber
= 0;
344 struct list_head addrs
;
345 struct list_head
*list
;
346 struct totem_ip_if_address
*if_addr
;
347 struct totem_ip_address node_addr
;
350 if (totemip_getifaddrs(&addrs
) == -1) {
354 iter
= icmap_iter_init("nodelist.node.");
355 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
356 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, tmp_key
);
361 if (strcmp(tmp_key
, "ring0_addr") != 0) {
365 if (icmap_get_string(iter_key
, &node_addr_str
) != CS_OK
) {
369 if (totemip_parse(&node_addr
, node_addr_str
, totem_config
->ip_version
) == -1) {
376 * Try to find node in if_addrs
379 for (list
= addrs
.next
; list
!= &addrs
; list
= list
->next
) {
380 if_addr
= list_entry(list
, struct totem_ip_if_address
, list
);
382 if (totemip_equal(&node_addr
, &if_addr
->ip_addr
)) {
393 icmap_iter_finalize(iter
);
397 * We found node, so create interface section
399 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.", node_pos
);
400 iter
= icmap_iter_init(tmp_key
);
401 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
402 res
= sscanf(iter_key
, "nodelist.node.%u.ring%u%s", &node_pos
, &ringnumber
, tmp_key2
);
403 if (res
!= 3 || strcmp(tmp_key2
, "_addr") != 0) {
407 if (icmap_get_string(iter_key
, &node_addr_str
) != CS_OK
) {
411 snprintf(tmp_key2
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.bindnetaddr", ringnumber
);
412 icmap_set_string(tmp_key2
, node_addr_str
);
415 icmap_iter_finalize(iter
);
420 extern int totem_config_read (
421 struct totem_config
*totem_config
,
422 const char **error_string
,
427 unsigned int ringnumber
= 0;
428 int member_count
= 0;
429 icmap_iter_t iter
, member_iter
;
430 const char *iter_key
;
431 const char *member_iter_key
;
432 char ringnumber_key
[ICMAP_KEYNAME_MAXLEN
];
433 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
436 char *cluster_name
= NULL
;
443 memset (totem_config
, 0, sizeof (struct totem_config
));
444 totem_config
->interfaces
= malloc (sizeof (struct totem_interface
) * INTERFACE_MAX
);
445 if (totem_config
->interfaces
== 0) {
446 *error_string
= "Out of memory trying to allocate ethernet interface storage area";
450 memset (totem_config
->interfaces
, 0,
451 sizeof (struct totem_interface
) * INTERFACE_MAX
);
453 strcpy (totem_config
->rrp_mode
, "none");
455 icmap_get_uint32("totem.version", (uint32_t *)&totem_config
->version
);
457 totem_get_crypto(totem_config
);
459 if (icmap_get_string("totem.rrp_mode", &str
) == CS_OK
) {
460 strcpy (totem_config
->rrp_mode
, str
);
464 icmap_get_uint32("totem.nodeid", &totem_config
->node_id
);
466 totem_config
->clear_node_high_bit
= 0;
467 if (icmap_get_string("totem.clear_node_high_bit", &str
) == CS_OK
) {
468 if (strcmp (str
, "yes") == 0) {
469 totem_config
->clear_node_high_bit
= 1;
474 icmap_get_uint32("totem.threads", &totem_config
->threads
);
476 icmap_get_uint32("totem.netmtu", &totem_config
->net_mtu
);
478 icmap_get_string("totem.cluster_name", &cluster_name
);
480 totem_config
->ip_version
= AF_INET
;
481 if (icmap_get_string("totem.ip_version", &str
) == CS_OK
) {
482 if (strcmp(str
, "ipv4") == 0) {
483 totem_config
->ip_version
= AF_INET
;
485 if (strcmp(str
, "ipv6") == 0) {
486 totem_config
->ip_version
= AF_INET6
;
492 * Get things that might change in the future
494 totem_volatile_config_read(totem_config
);
496 if (icmap_get_string("totem.interface.0.bindnetaddr", &str
) != CS_OK
) {
498 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
500 config_convert_nodelist_to_interface(totem_config
);
505 iter
= icmap_iter_init("totem.interface.");
506 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
507 res
= sscanf(iter_key
, "totem.interface.%[^.].%s", ringnumber_key
, tmp_key
);
512 if (strcmp(tmp_key
, "bindnetaddr") != 0) {
518 ringnumber
= atoi(ringnumber_key
);
520 if (ringnumber
>= INTERFACE_MAX
) {
521 snprintf (error_string_response
, sizeof(error_string_response
),
522 "parse error in config: interface ring number %u is bigger then allowed maximum %u\n",
523 ringnumber
, INTERFACE_MAX
- 1);
525 *error_string
= error_string_response
;
530 * Get the bind net address
532 if (icmap_get_string(iter_key
, &str
) == CS_OK
) {
533 res
= totemip_parse (&totem_config
->interfaces
[ringnumber
].bindnet
, str
,
534 totem_config
->interfaces
[ringnumber
].mcast_addr
.family
);
539 * Get interface multicast address
541 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastaddr", ringnumber
);
542 if (icmap_get_string(tmp_key
, &str
) == CS_OK
) {
543 res
= totemip_parse (&totem_config
->interfaces
[ringnumber
].mcast_addr
, str
, totem_config
->ip_version
);
547 * User not specified address -> autogenerate one from cluster_name key
550 res
= get_cluster_mcast_addr (cluster_name
,
551 &totem_config
->interfaces
[ringnumber
].bindnet
,
553 totem_config
->ip_version
,
554 &totem_config
->interfaces
[ringnumber
].mcast_addr
);
557 totem_config
->broadcast_use
= 0;
558 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.broadcast", ringnumber
);
559 if (icmap_get_string(tmp_key
, &str
) == CS_OK
) {
560 if (strcmp (str
, "yes") == 0) {
561 totem_config
->broadcast_use
= 1;
563 &totem_config
->interfaces
[ringnumber
].mcast_addr
,
564 "255.255.255.255", totem_config
->ip_version
);
572 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastport", ringnumber
);
573 if (icmap_get_uint16(tmp_key
, &totem_config
->interfaces
[ringnumber
].ip_port
) != CS_OK
) {
574 if (totem_config
->broadcast_use
) {
575 totem_config
->interfaces
[ringnumber
].ip_port
= DEFAULT_PORT
+ (2 * ringnumber
);
577 totem_config
->interfaces
[ringnumber
].ip_port
= DEFAULT_PORT
;
584 totem_config
->interfaces
[ringnumber
].ttl
= 1;
586 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.ttl", ringnumber
);
588 if (icmap_get_uint8(tmp_key
, &u8
) == CS_OK
) {
589 totem_config
->interfaces
[ringnumber
].ttl
= u8
;
592 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.member.", ringnumber
);
593 member_iter
= icmap_iter_init(tmp_key
);
594 while ((member_iter_key
= icmap_iter_next(member_iter
, NULL
, NULL
)) != NULL
) {
595 if (member_count
== 0) {
596 if (icmap_get_string("nodelist.node.0.ring0_addr", &str
) == CS_OK
) {
598 *warnings
|= TOTEM_CONFIG_WARNING_MEMBERS_IGNORED
;
601 *warnings
|= TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED
;
605 if (icmap_get_string(member_iter_key
, &str
) == CS_OK
) {
606 res
= totemip_parse (&totem_config
->interfaces
[ringnumber
].member_list
[member_count
++],
607 str
, totem_config
->ip_version
);
610 icmap_iter_finalize(member_iter
);
612 totem_config
->interfaces
[ringnumber
].member_count
= member_count
;
613 totem_config
->interface_count
++;
615 icmap_iter_finalize(iter
);
618 * Store automatically generated items back to icmap
620 for (i
= 0; i
< totem_config
->interface_count
; i
++) {
621 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastaddr", i
);
622 if (icmap_get_string(tmp_key
, &str
) == CS_OK
) {
625 str
= (char *)totemip_print(&totem_config
->interfaces
[i
].mcast_addr
);
626 icmap_set_string(tmp_key
, str
);
629 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastport", i
);
630 if (icmap_get_uint16(tmp_key
, &u16
) != CS_OK
) {
631 icmap_set_uint16(tmp_key
, totem_config
->interfaces
[i
].ip_port
);
635 totem_config
->transport_number
= TOTEM_TRANSPORT_UDP
;
636 if (icmap_get_string("totem.transport", &str
) == CS_OK
) {
637 if (strcmp (str
, "udpu") == 0) {
638 totem_config
->transport_number
= TOTEM_TRANSPORT_UDPU
;
641 if (strcmp (str
, "iba") == 0) {
642 totem_config
->transport_number
= TOTEM_TRANSPORT_RDMA
;
650 * Check existence of nodelist
652 if (icmap_get_string("nodelist.node.0.ring0_addr", &str
) == CS_OK
) {
657 local_node_pos
= find_local_node_in_nodelist(totem_config
);
658 if (local_node_pos
!= -1) {
659 icmap_set_uint32("nodelist.local_node_pos", local_node_pos
);
661 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.nodeid", local_node_pos
);
663 nodeid_set
= (totem_config
->node_id
!= 0);
664 if (icmap_get_uint32(tmp_key
, &totem_config
->node_id
) == CS_OK
&& nodeid_set
) {
665 *warnings
|= TOTEM_CONFIG_WARNING_TOTEM_NODEID_IGNORED
;
669 * Make localnode ring0_addr read only, so we can be sure that local
670 * node never changes. If rebinding to other IP would be in future
671 * supported, this must be changed and handled properly!
673 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", local_node_pos
);
674 icmap_set_ro_access(tmp_key
, 0, 1);
675 icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
678 put_nodelist_members_to_config(totem_config
);
681 add_totem_config_notification(totem_config
);
686 int totem_config_validate (
687 struct totem_config
*totem_config
,
688 const char **error_string
)
690 static char local_error_reason
[512];
691 char parse_error
[512];
692 const char *error_reason
= local_error_reason
;
694 unsigned int interface_max
= INTERFACE_MAX
;
696 if (totem_config
->interface_count
== 0) {
697 error_reason
= "No interfaces defined";
701 for (i
= 0; i
< totem_config
->interface_count
; i
++) {
703 * Some error checking of parsed data to make sure its valid
706 struct totem_ip_address null_addr
;
707 memset (&null_addr
, 0, sizeof (struct totem_ip_address
));
709 if ((totem_config
->transport_number
== 0) &&
710 memcmp (&totem_config
->interfaces
[i
].mcast_addr
, &null_addr
,
711 sizeof (struct totem_ip_address
)) == 0) {
712 error_reason
= "No multicast address specified";
716 if (totem_config
->interfaces
[i
].ip_port
== 0) {
717 error_reason
= "No multicast port specified";
721 if (totem_config
->interfaces
[i
].ttl
> 255) {
722 error_reason
= "Invalid TTL (should be 0..255)";
725 if (totem_config
->transport_number
!= TOTEM_TRANSPORT_UDP
&&
726 totem_config
->interfaces
[i
].ttl
!= 1) {
727 error_reason
= "Can only set ttl on multicast transport types";
731 if (totem_config
->interfaces
[i
].mcast_addr
.family
== AF_INET6
&&
732 totem_config
->node_id
== 0) {
734 error_reason
= "An IPV6 network requires that a node ID be specified.";
738 if (totem_config
->broadcast_use
== 0 && totem_config
->transport_number
== 0) {
739 if (totem_config
->interfaces
[i
].mcast_addr
.family
!= totem_config
->interfaces
[i
].bindnet
.family
) {
740 error_reason
= "Multicast address family does not match bind address family";
744 if (totem_config
->interfaces
[i
].mcast_addr
.family
!= totem_config
->interfaces
[i
].bindnet
.family
) {
745 error_reason
= "Not all bind address belong to the same IP family";
748 if (totemip_is_mcast (&totem_config
->interfaces
[i
].mcast_addr
) != 0) {
749 error_reason
= "mcastaddr is not a correct multicast address.";
755 if (totem_config
->version
!= 2) {
756 error_reason
= "This totem parser can only parse version 2 configurations.";
761 if (totem_config
->token_retransmits_before_loss_const
== 0) {
762 totem_config
->token_retransmits_before_loss_const
=
763 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST
;
767 * Setup timeout values that are not setup by user
769 if (totem_config
->token_timeout
== 0) {
770 totem_config
->token_timeout
= TOKEN_TIMEOUT
;
773 if (totem_config
->max_network_delay
== 0) {
774 totem_config
->max_network_delay
= MAX_NETWORK_DELAY
;
777 if (totem_config
->max_network_delay
< MINIMUM_TIMEOUT
) {
778 snprintf (local_error_reason
, sizeof(local_error_reason
),
779 "The max_network_delay parameter (%d ms) may not be less then (%d ms).",
780 totem_config
->max_network_delay
, MINIMUM_TIMEOUT
);
784 if (totem_config
->window_size
== 0) {
785 totem_config
->window_size
= WINDOW_SIZE
;
788 if (totem_config
->max_messages
== 0) {
789 totem_config
->max_messages
= MAX_MESSAGES
;
792 if (totem_config
->miss_count_const
== 0) {
793 totem_config
->miss_count_const
= MISS_COUNT_CONST
;
796 if (totem_config
->token_timeout
< MINIMUM_TIMEOUT
) {
797 snprintf (local_error_reason
, sizeof(local_error_reason
),
798 "The token timeout parameter (%d ms) may not be less then (%d ms).",
799 totem_config
->token_timeout
, MINIMUM_TIMEOUT
);
803 if (totem_config
->token_retransmit_timeout
== 0) {
804 totem_config
->token_retransmit_timeout
=
805 (int)(totem_config
->token_timeout
/
806 (totem_config
->token_retransmits_before_loss_const
+ 0.2));
808 if (totem_config
->token_hold_timeout
== 0) {
809 totem_config
->token_hold_timeout
=
810 (int)(totem_config
->token_retransmit_timeout
* 0.8 -
813 if (totem_config
->token_retransmit_timeout
< MINIMUM_TIMEOUT
) {
814 snprintf (local_error_reason
, sizeof(local_error_reason
),
815 "The token retransmit timeout parameter (%d ms) may not be less then (%d ms).",
816 totem_config
->token_retransmit_timeout
, MINIMUM_TIMEOUT
);
820 if (totem_config
->token_hold_timeout
< MINIMUM_TIMEOUT
) {
821 snprintf (local_error_reason
, sizeof(local_error_reason
),
822 "The token hold timeout parameter (%d ms) may not be less then (%d ms).",
823 totem_config
->token_hold_timeout
, MINIMUM_TIMEOUT
);
827 if (totem_config
->join_timeout
== 0) {
828 totem_config
->join_timeout
= JOIN_TIMEOUT
;
831 if (totem_config
->join_timeout
< MINIMUM_TIMEOUT
) {
832 snprintf (local_error_reason
, sizeof(local_error_reason
),
833 "The join timeout parameter (%d ms) may not be less then (%d ms).",
834 totem_config
->join_timeout
, MINIMUM_TIMEOUT
);
838 if (totem_config
->consensus_timeout
== 0) {
839 totem_config
->consensus_timeout
= (int)(float)(1.2 * totem_config
->token_timeout
);
842 if (totem_config
->consensus_timeout
< MINIMUM_TIMEOUT
) {
843 snprintf (local_error_reason
, sizeof(local_error_reason
),
844 "The consensus timeout parameter (%d ms) may not be less then (%d ms).",
845 totem_config
->consensus_timeout
, MINIMUM_TIMEOUT
);
849 if (totem_config
->merge_timeout
== 0) {
850 totem_config
->merge_timeout
= MERGE_TIMEOUT
;
853 if (totem_config
->merge_timeout
< MINIMUM_TIMEOUT
) {
854 snprintf (local_error_reason
, sizeof(local_error_reason
),
855 "The merge timeout parameter (%d ms) may not be less then (%d ms).",
856 totem_config
->merge_timeout
, MINIMUM_TIMEOUT
);
860 if (totem_config
->downcheck_timeout
== 0) {
861 totem_config
->downcheck_timeout
= DOWNCHECK_TIMEOUT
;
864 if (totem_config
->downcheck_timeout
< MINIMUM_TIMEOUT
) {
865 snprintf (local_error_reason
, sizeof(local_error_reason
),
866 "The downcheck timeout parameter (%d ms) may not be less then (%d ms).",
867 totem_config
->downcheck_timeout
, MINIMUM_TIMEOUT
);
872 * RRP values validation
874 if (strcmp (totem_config
->rrp_mode
, "none") &&
875 strcmp (totem_config
->rrp_mode
, "active") &&
876 strcmp (totem_config
->rrp_mode
, "passive")) {
877 snprintf (local_error_reason
, sizeof(local_error_reason
),
878 "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config
->rrp_mode
);
881 if (totem_config
->rrp_problem_count_timeout
== 0) {
882 totem_config
->rrp_problem_count_timeout
= RRP_PROBLEM_COUNT_TIMEOUT
;
884 if (totem_config
->rrp_problem_count_timeout
< MINIMUM_TIMEOUT
) {
885 snprintf (local_error_reason
, sizeof(local_error_reason
),
886 "The RRP problem count timeout parameter (%d ms) may not be less then (%d ms).",
887 totem_config
->rrp_problem_count_timeout
, MINIMUM_TIMEOUT
);
890 if (totem_config
->rrp_problem_count_threshold
== 0) {
891 totem_config
->rrp_problem_count_threshold
= RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT
;
893 if (totem_config
->rrp_problem_count_mcast_threshold
== 0) {
894 totem_config
->rrp_problem_count_mcast_threshold
= totem_config
->rrp_problem_count_threshold
* 10;
896 if (totem_config
->rrp_problem_count_threshold
< RRP_PROBLEM_COUNT_THRESHOLD_MIN
) {
897 snprintf (local_error_reason
, sizeof(local_error_reason
),
898 "The RRP problem count threshold (%d problem count) may not be less then (%d problem count).",
899 totem_config
->rrp_problem_count_threshold
, RRP_PROBLEM_COUNT_THRESHOLD_MIN
);
902 if (totem_config
->rrp_problem_count_mcast_threshold
< RRP_PROBLEM_COUNT_THRESHOLD_MIN
) {
903 snprintf (local_error_reason
, sizeof(local_error_reason
),
904 "The RRP multicast problem count threshold (%d problem count) may not be less then (%d problem count).",
905 totem_config
->rrp_problem_count_mcast_threshold
, RRP_PROBLEM_COUNT_THRESHOLD_MIN
);
908 if (totem_config
->rrp_token_expired_timeout
== 0) {
909 totem_config
->rrp_token_expired_timeout
=
910 totem_config
->token_retransmit_timeout
;
913 if (totem_config
->rrp_token_expired_timeout
< MINIMUM_TIMEOUT
) {
914 snprintf (local_error_reason
, sizeof(local_error_reason
),
915 "The RRP token expired timeout parameter (%d ms) may not be less then (%d ms).",
916 totem_config
->rrp_token_expired_timeout
, MINIMUM_TIMEOUT
);
920 if (totem_config
->rrp_autorecovery_check_timeout
== 0) {
921 totem_config
->rrp_autorecovery_check_timeout
= RRP_AUTORECOVERY_CHECK_TIMEOUT
;
924 if (strcmp (totem_config
->rrp_mode
, "none") == 0) {
927 if (interface_max
< totem_config
->interface_count
) {
928 snprintf (parse_error
, sizeof(parse_error
),
929 "%d is too many configured interfaces for the rrp_mode setting %s.",
930 totem_config
->interface_count
,
931 totem_config
->rrp_mode
);
932 error_reason
= parse_error
;
937 if (totem_config
->fail_to_recv_const
== 0) {
938 totem_config
->fail_to_recv_const
= FAIL_TO_RECV_CONST
;
940 if (totem_config
->seqno_unchanged_const
== 0) {
941 totem_config
->seqno_unchanged_const
= SEQNO_UNCHANGED_CONST
;
943 if (totem_config
->net_mtu
== 0) {
944 totem_config
->net_mtu
= 1500;
947 if ((MESSAGE_QUEUE_MAX
) < totem_config
->max_messages
) {
948 snprintf (local_error_reason
, sizeof(local_error_reason
),
949 "The max_messages parameter (%d messages) may not be greater then (%d messages).",
950 totem_config
->max_messages
, MESSAGE_QUEUE_MAX
);
954 if (totem_config
->threads
> SEND_THREADS_MAX
) {
955 totem_config
->threads
= SEND_THREADS_MAX
;
957 if (totem_config
->net_mtu
> FRAME_SIZE_MAX
) {
958 error_reason
= "This net_mtu parameter is greater then the maximum frame size";
961 if (totem_config
->vsf_type
== NULL
) {
962 totem_config
->vsf_type
= "none";
968 snprintf (error_string_response
, sizeof(error_string_response
),
969 "parse error in config: %s\n", error_reason
);
970 *error_string
= error_string_response
;
974 static int read_keyfile (
975 const char *key_location
,
976 struct totem_config
*totem_config
,
977 const char **error_string
)
981 ssize_t expected_key_len
= sizeof (totem_config
->private_key
);
984 const char *error_ptr
;
986 fd
= open (key_location
, O_RDONLY
);
988 error_ptr
= qb_strerror_r(errno
, error_str
, sizeof(error_str
));
989 snprintf (error_string_response
, sizeof(error_string_response
),
990 "Could not open %s: %s\n",
991 key_location
, error_ptr
);
995 res
= read (fd
, totem_config
->private_key
, expected_key_len
);
1000 error_ptr
= qb_strerror_r (saved_errno
, error_str
, sizeof(error_str
));
1001 snprintf (error_string_response
, sizeof(error_string_response
),
1002 "Could not read %s: %s\n",
1003 key_location
, error_ptr
);
1007 totem_config
->private_key_len
= expected_key_len
;
1009 if (res
!= expected_key_len
) {
1010 snprintf (error_string_response
, sizeof(error_string_response
),
1011 "Could only read %d bits of 1024 bits from %s.\n",
1012 res
* 8, key_location
);
1019 *error_string
= error_string_response
;
1023 int totem_config_keyread (
1024 struct totem_config
*totem_config
,
1025 const char **error_string
)
1028 char *key_location
= NULL
;
1032 memset (totem_config
->private_key
, 0, 128);
1033 totem_config
->private_key_len
= 128;
1035 if (strcmp(totem_config
->crypto_cipher_type
, "none") == 0 &&
1036 strcmp(totem_config
->crypto_hash_type
, "none") == 0) {
1040 /* cmap may store the location of the key file */
1041 if (icmap_get_string("totem.keyfile", &key_location
) == CS_OK
) {
1042 res
= read_keyfile(key_location
, totem_config
, error_string
);
1048 } else { /* Or the key itself may be in the cmap */
1049 if (icmap_get("totem.key", NULL
, &key_len
, NULL
) == CS_OK
) {
1050 if (key_len
> sizeof (totem_config
->private_key
)) {
1051 sprintf(error_string_response
, "key is too long");
1054 if (icmap_get("totem.key", totem_config
->private_key
, &key_len
, NULL
) == CS_OK
) {
1055 totem_config
->private_key_len
= key_len
;
1058 sprintf(error_string_response
, "can't store private key");
1064 /* In desperation we read the default filename */
1066 const char *filename
= getenv("COROSYNC_TOTEM_AUTHKEY_FILE");
1068 filename
= COROSYSCONFDIR
"/authkey";
1069 res
= read_keyfile(filename
, totem_config
, error_string
);
1078 *error_string
= error_string_response
;
1083 static void totem_change_notify(
1085 const char *key_name
,
1086 struct icmap_notify_value new_val
,
1087 struct icmap_notify_value old_val
,
1090 totem_volatile_config_read((struct totem_config
*)user_data
);
1093 static void add_totem_config_notification(struct totem_config
*totem_config
)
1095 icmap_track_t icmap_track
;
1097 icmap_track_add("totem.",
1098 ICMAP_TRACK_ADD
| ICMAP_TRACK_DELETE
| ICMAP_TRACK_MODIFY
| ICMAP_TRACK_PREFIX
,
1099 totem_change_notify
,