2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006-2019 Red Hat, Inc.
7 * Author: Steven Dake (sdake@redhat.com)
8 * Jan Friesse (jfriesse@redhat.com)
9 * Chrissie Caulfield (ccaulfie@redhat.com)
11 * This software licensed under BSD license, the text of which follows:
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
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.
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.
45 #include <sys/socket.h>
46 #include <sys/types.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <sys/param.h>
54 #include <sys/utsname.h>
56 #include <corosync/swab.h>
57 #include <qb/qblist.h>
58 #include <qb/qbdefs.h>
60 #include <corosync/totem/totem.h>
61 #include <corosync/config.h>
62 #include <corosync/logsys.h>
63 #include <corosync/icmap.h>
66 #include "totemconfig.h"
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 /* This constant is not used for knet */
85 #define UDP_NETMTU 1500
87 /* Currently all but PONG_COUNT match the defaults in libknet.h */
88 #define KNET_PING_INTERVAL 1000
89 #define KNET_PING_TIMEOUT 2000
90 #define KNET_PING_PRECISION 2048
91 #define KNET_PONG_COUNT 2
92 #define KNET_PMTUD_INTERVAL 30
93 #define KNET_DEFAULT_TRANSPORT KNET_TRANSPORT_UDP
95 #define DEFAULT_PORT 5405
97 static char error_string_response
[768];
99 static void add_totem_config_notification(struct totem_config
*totem_config
);
101 static void *totem_get_param_by_name(struct totem_config
*totem_config
, const char *param_name
)
103 if (strcmp(param_name
, "totem.token") == 0)
104 return &totem_config
->token_timeout
;
105 if (strcmp(param_name
, "totem.token_warning") == 0)
106 return &totem_config
->token_warning
;
107 if (strcmp(param_name
, "totem.token_retransmit") == 0)
108 return &totem_config
->token_retransmit_timeout
;
109 if (strcmp(param_name
, "totem.hold") == 0)
110 return &totem_config
->token_hold_timeout
;
111 if (strcmp(param_name
, "totem.token_retransmits_before_loss_const") == 0)
112 return &totem_config
->token_retransmits_before_loss_const
;
113 if (strcmp(param_name
, "totem.join") == 0)
114 return &totem_config
->join_timeout
;
115 if (strcmp(param_name
, "totem.send_join") == 0)
116 return &totem_config
->send_join_timeout
;
117 if (strcmp(param_name
, "totem.consensus") == 0)
118 return &totem_config
->consensus_timeout
;
119 if (strcmp(param_name
, "totem.merge") == 0)
120 return &totem_config
->merge_timeout
;
121 if (strcmp(param_name
, "totem.downcheck") == 0)
122 return &totem_config
->downcheck_timeout
;
123 if (strcmp(param_name
, "totem.fail_recv_const") == 0)
124 return &totem_config
->fail_to_recv_const
;
125 if (strcmp(param_name
, "totem.seqno_unchanged_const") == 0)
126 return &totem_config
->seqno_unchanged_const
;
127 if (strcmp(param_name
, "totem.heartbeat_failures_allowed") == 0)
128 return &totem_config
->heartbeat_failures_allowed
;
129 if (strcmp(param_name
, "totem.max_network_delay") == 0)
130 return &totem_config
->max_network_delay
;
131 if (strcmp(param_name
, "totem.window_size") == 0)
132 return &totem_config
->window_size
;
133 if (strcmp(param_name
, "totem.max_messages") == 0)
134 return &totem_config
->max_messages
;
135 if (strcmp(param_name
, "totem.miss_count_const") == 0)
136 return &totem_config
->miss_count_const
;
137 if (strcmp(param_name
, "totem.knet_pmtud_interval") == 0)
138 return &totem_config
->knet_pmtud_interval
;
139 if (strcmp(param_name
, "totem.knet_compression_threshold") == 0)
140 return &totem_config
->knet_compression_threshold
;
141 if (strcmp(param_name
, "totem.knet_compression_level") == 0)
142 return &totem_config
->knet_compression_level
;
143 if (strcmp(param_name
, "totem.knet_compression_model") == 0)
144 return totem_config
->knet_compression_model
;
145 if (strcmp(param_name
, "totem.block_unlisted_ips") == 0)
146 return &totem_config
->block_unlisted_ips
;
152 * Read key_name from icmap. If key is not found or key_name == delete_key or if allow_zero is false
153 * and readed value is zero, default value is used and stored into totem_config.
155 static void totem_volatile_config_set_uint32_value (struct totem_config
*totem_config
, icmap_map_t map
,
156 const char *key_name
, const char *deleted_key
, unsigned int default_value
,
157 int allow_zero_value
)
159 char runtime_key_name
[ICMAP_KEYNAME_MAXLEN
];
161 if (icmap_get_uint32_r(map
, key_name
, totem_get_param_by_name(totem_config
, key_name
)) != CS_OK
||
162 (deleted_key
!= NULL
&& strcmp(deleted_key
, key_name
) == 0) ||
163 (!allow_zero_value
&& *(uint32_t *)totem_get_param_by_name(totem_config
, key_name
) == 0)) {
164 *(uint32_t *)totem_get_param_by_name(totem_config
, key_name
) = default_value
;
168 * Store totem_config value to cmap runtime section
170 if (strlen("runtime.config.") + strlen(key_name
) >= ICMAP_KEYNAME_MAXLEN
) {
172 * This shouldn't happen
177 strcpy(runtime_key_name
, "runtime.config.");
178 strcat(runtime_key_name
, key_name
);
180 icmap_set_uint32_r(map
, runtime_key_name
, *(uint32_t *)totem_get_param_by_name(totem_config
, key_name
));
183 static void totem_volatile_config_set_int32_value (struct totem_config
*totem_config
, icmap_map_t map
,
184 const char *key_name
, const char *deleted_key
, int default_value
,
185 int allow_zero_value
)
187 char runtime_key_name
[ICMAP_KEYNAME_MAXLEN
];
189 if (icmap_get_int32_r(map
, key_name
, totem_get_param_by_name(totem_config
, key_name
)) != CS_OK
||
190 (deleted_key
!= NULL
&& strcmp(deleted_key
, key_name
) == 0) ||
191 (!allow_zero_value
&& *(int32_t *)totem_get_param_by_name(totem_config
, key_name
) == 0)) {
192 *(int32_t *)totem_get_param_by_name(totem_config
, key_name
) = default_value
;
196 * Store totem_config value to cmap runtime section
198 if (strlen("runtime.config.") + strlen(key_name
) >= ICMAP_KEYNAME_MAXLEN
) {
200 * This shouldn't happen
205 strcpy(runtime_key_name
, "runtime.config.");
206 strcat(runtime_key_name
, key_name
);
208 icmap_set_int32_r(map
, runtime_key_name
, *(int32_t *)totem_get_param_by_name(totem_config
, key_name
));
211 static void totem_volatile_config_set_string_value (struct totem_config
*totem_config
, icmap_map_t map
,
212 const char *key_name
, const char *deleted_key
, const char *default_value
)
214 char runtime_key_name
[ICMAP_KEYNAME_MAXLEN
];
216 char *new_config_value
;
217 const void *config_value
;
219 config_value
= totem_get_param_by_name(totem_config
, key_name
);
221 res
= icmap_get_string_r(map
, key_name
, (char **)&new_config_value
);
223 (deleted_key
!= NULL
&& strcmp(deleted_key
, key_name
) == 0)) {
225 /* Slightly pointless use of strncpy but it keeps coverity happy */
226 strncpy((char *)config_value
, default_value
, CONFIG_STRING_LEN_MAX
);
228 strncpy((char *)config_value
, new_config_value
, CONFIG_STRING_LEN_MAX
);
231 free(new_config_value
);
235 * Store totem_config value to cmap runtime section
237 if (strlen("runtime.config.") + strlen(key_name
) >= ICMAP_KEYNAME_MAXLEN
) {
239 * This shouldn't happen
244 strcpy(runtime_key_name
, "runtime.config.");
245 strcat(runtime_key_name
, key_name
);
247 (void)icmap_set_string_r(map
, runtime_key_name
, (char *)config_value
);
251 * Read string value stored in key_name from icmap, use it as a boolean (yes/no) type, convert it
252 * to integer value (1/0) and store into totem_config.
254 * If key is not found or key_name == delete_key default value is used
255 * and stored into totem_config.
257 static void totem_volatile_config_set_boolean_value (struct totem_config
*totem_config
, icmap_map_t map
,
258 const char *key_name
, const char *deleted_key
, unsigned int default_value
)
260 char runtime_key_name
[ICMAP_KEYNAME_MAXLEN
];
267 if ((deleted_key
!= NULL
&& strcmp(deleted_key
, key_name
) == 0) ||
268 (icmap_get_string_r(map
, key_name
, &str
) != CS_OK
)) {
270 * Do nothing. str is NULL (icmap_get_string ether not called or
274 if (strcmp(str
, "yes") == 0) {
276 } else if (strcmp(str
, "no") == 0) {
283 * Store totem_config value to cmap runtime section
285 if (strlen("runtime.config.") + strlen(key_name
) >= ICMAP_KEYNAME_MAXLEN
) {
287 * This shouldn't happen
292 strcpy(runtime_key_name
, "runtime.config.");
293 strcat(runtime_key_name
, key_name
);
295 *(uint32_t *)totem_get_param_by_name(totem_config
, key_name
) = val
;
297 icmap_set_uint32_r(map
, runtime_key_name
, val
);
301 * Read and validate config values from cmap and store them into totem_config. If key doesn't exists,
302 * default value is stored. deleted_key is name of key beeing processed by delete operation
303 * from cmap. It is considered as non existing even if it can be read. Can be NULL.
305 void totem_volatile_config_read (struct totem_config
*totem_config
, icmap_map_t temp_map
, const char *deleted_key
)
309 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.token_retransmits_before_loss_const", deleted_key
,
310 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST
, 0);
312 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.token", deleted_key
, TOKEN_TIMEOUT
, 0);
314 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.token_warning", deleted_key
, TOKEN_WARNING
, 1);
316 if (totem_config
->interfaces
[0].member_count
> 2) {
317 u32
= TOKEN_COEFFICIENT
;
318 icmap_get_uint32_r(temp_map
, "totem.token_coefficient", &u32
);
319 totem_config
->token_timeout
+= (totem_config
->interfaces
[0].member_count
- 2) * u32
;
322 * Store totem_config value to cmap runtime section
324 icmap_set_uint32_r(temp_map
, "runtime.config.totem.token", totem_config
->token_timeout
);
327 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.max_network_delay", deleted_key
, MAX_NETWORK_DELAY
, 0);
329 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.window_size", deleted_key
, WINDOW_SIZE
, 0);
331 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.max_messages", deleted_key
, MAX_MESSAGES
, 0);
333 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.miss_count_const", deleted_key
, MISS_COUNT_CONST
, 0);
334 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.knet_pmtud_interval", deleted_key
, KNET_PMTUD_INTERVAL
, 0);
336 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.token_retransmit", deleted_key
,
337 (int)(totem_config
->token_timeout
/ (totem_config
->token_retransmits_before_loss_const
+ 0.2)), 0);
339 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.hold", deleted_key
,
340 (int)(totem_config
->token_retransmit_timeout
* 0.8 - (1000/HZ
)), 0);
342 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.join", deleted_key
, JOIN_TIMEOUT
, 0);
344 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.consensus", deleted_key
,
345 (int)(float)(1.2 * totem_config
->token_timeout
), 0);
347 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.merge", deleted_key
, MERGE_TIMEOUT
, 0);
349 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.downcheck", deleted_key
, DOWNCHECK_TIMEOUT
, 0);
351 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.fail_recv_const", deleted_key
, FAIL_TO_RECV_CONST
, 0);
353 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.seqno_unchanged_const", deleted_key
,
354 SEQNO_UNCHANGED_CONST
, 0);
356 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.send_join", deleted_key
, 0, 1);
358 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.heartbeat_failures_allowed", deleted_key
, 0, 1);
360 totem_volatile_config_set_uint32_value(totem_config
, temp_map
, "totem.knet_compression_threshold", deleted_key
, 0, 1);
362 totem_volatile_config_set_int32_value(totem_config
, temp_map
, "totem.knet_compression_level", deleted_key
, 0, 1);
364 totem_volatile_config_set_string_value(totem_config
, temp_map
, "totem.knet_compression_model", deleted_key
, "none");
366 totem_volatile_config_set_boolean_value(totem_config
, temp_map
, "totem.block_unlisted_ips", deleted_key
,
370 int totem_volatile_config_validate (
371 struct totem_config
*totem_config
,
372 icmap_map_t temp_map
,
373 const char **error_string
)
375 /* Static just to keep them off the stack */
376 static char local_error_reason
[512];
377 static char addr_str_buf
[INET6_ADDRSTRLEN
];
378 const char *error_reason
= local_error_reason
;
379 char name_key
[ICMAP_KEYNAME_MAXLEN
];
381 int i
, j
, num_configured
, members
;
382 uint32_t tmp_config_value
;
384 if (totem_config
->max_network_delay
< MINIMUM_TIMEOUT
) {
385 snprintf (local_error_reason
, sizeof(local_error_reason
),
386 "The max_network_delay parameter (%d ms) may not be less than (%d ms).",
387 totem_config
->max_network_delay
, MINIMUM_TIMEOUT
);
391 if (totem_config
->token_timeout
< MINIMUM_TIMEOUT
) {
392 snprintf (local_error_reason
, sizeof(local_error_reason
),
393 "The token timeout parameter (%d ms) may not be less than (%d ms).",
394 totem_config
->token_timeout
, MINIMUM_TIMEOUT
);
398 if (totem_config
->token_warning
> 100 || totem_config
->token_warning
< 0) {
399 snprintf (local_error_reason
, sizeof(local_error_reason
),
400 "The token warning parameter (%d%%) must be between 0 (disabled) and 100.",
401 totem_config
->token_warning
);
405 if (totem_config
->token_retransmit_timeout
< MINIMUM_TIMEOUT
) {
406 if (icmap_get_uint32_r(temp_map
, "totem.token_retransmit", &tmp_config_value
) == CS_OK
) {
407 snprintf (local_error_reason
, sizeof(local_error_reason
),
408 "The token retransmit timeout parameter (%d ms) may not be less than (%d ms).",
409 totem_config
->token_retransmit_timeout
, MINIMUM_TIMEOUT
);
412 snprintf (local_error_reason
, sizeof(local_error_reason
),
413 "Not appropriate token or token_retransmits_before_loss_const value set");
418 if (totem_config
->token_hold_timeout
< MINIMUM_TIMEOUT_HOLD
) {
419 snprintf (local_error_reason
, sizeof(local_error_reason
),
420 "The token hold timeout parameter (%d ms) may not be less than (%d ms).",
421 totem_config
->token_hold_timeout
, MINIMUM_TIMEOUT_HOLD
);
425 if (totem_config
->join_timeout
< MINIMUM_TIMEOUT
) {
426 snprintf (local_error_reason
, sizeof(local_error_reason
),
427 "The join timeout parameter (%d ms) may not be less than (%d ms).",
428 totem_config
->join_timeout
, MINIMUM_TIMEOUT
);
432 if (totem_config
->consensus_timeout
< MINIMUM_TIMEOUT
) {
433 snprintf (local_error_reason
, sizeof(local_error_reason
),
434 "The consensus timeout parameter (%d ms) may not be less than (%d ms).",
435 totem_config
->consensus_timeout
, MINIMUM_TIMEOUT
);
439 if (totem_config
->consensus_timeout
< totem_config
->join_timeout
) {
440 snprintf (local_error_reason
, sizeof(local_error_reason
),
441 "The consensus timeout parameter (%d ms) may not be less than join timeout (%d ms).",
442 totem_config
->consensus_timeout
, totem_config
->join_timeout
);
446 if (totem_config
->merge_timeout
< MINIMUM_TIMEOUT
) {
447 snprintf (local_error_reason
, sizeof(local_error_reason
),
448 "The merge timeout parameter (%d ms) may not be less than (%d ms).",
449 totem_config
->merge_timeout
, MINIMUM_TIMEOUT
);
453 if (totem_config
->downcheck_timeout
< MINIMUM_TIMEOUT
) {
454 snprintf (local_error_reason
, sizeof(local_error_reason
),
455 "The downcheck timeout parameter (%d ms) may not be less than (%d ms).",
456 totem_config
->downcheck_timeout
, MINIMUM_TIMEOUT
);
460 /* Check that we have nodelist 'name' if there is more than one link */
463 for (i
= 0; i
< INTERFACE_MAX
; i
++) {
464 if (totem_config
->interfaces
[i
].configured
) {
465 if (num_configured
== 0) {
466 members
= totem_config
->interfaces
[i
].member_count
;
472 if (num_configured
> 1) {
474 * This assert is here just to make compiler happy
476 assert(members
!= -1);
477 for (i
=0; i
< members
; i
++) {
478 snprintf(name_key
, sizeof(name_key
), "nodelist.node.%d.name", i
);
480 if (icmap_get_string_r(temp_map
, name_key
, &name_str
) != CS_OK
) {
481 snprintf (local_error_reason
, sizeof(local_error_reason
),
482 "for a multi-link configuration, all nodes must have a 'name' attribute");
489 for (i
=0; i
< INTERFACE_MAX
; i
++) {
490 if (!totem_config
->interfaces
[i
].configured
) {
493 if (totem_config
->interfaces
[i
].member_count
!= members
) {
494 snprintf (local_error_reason
, sizeof(local_error_reason
),
495 "Not all nodes have the same number of links");
501 /* Verify that all nodes on the same link have the same IP family */
502 for (i
=0; i
< INTERFACE_MAX
; i
++) {
503 for (j
=1; j
<totem_config
->interfaces
[i
].member_count
; j
++) {
504 if (totem_config
->interfaces
[i
].configured
) {
505 if (totem_config
->interfaces
[i
].member_list
[j
].family
!=
506 totem_config
->interfaces
[i
].member_list
[0].family
) {
508 totemip_print(&(totem_config
->interfaces
[i
].member_list
[j
])),
509 sizeof(addr_str_buf
));
511 snprintf (local_error_reason
, sizeof(local_error_reason
),
512 "Nodes for link %d have different IP families "
513 "(compared %s with %s)", i
,
515 totemip_print(&(totem_config
->interfaces
[i
].member_list
[0])));
525 snprintf (error_string_response
, sizeof(error_string_response
),
526 "parse error in config: %s\n", error_reason
);
527 *error_string
= error_string_response
;
532 static int totem_get_crypto(struct totem_config
*totem_config
, icmap_map_t map
, const char **error_string
)
535 const char *tmp_cipher
;
536 const char *tmp_hash
;
537 const char *tmp_model
;
543 if (icmap_get_string_r(map
, "totem.crypto_model", &str
) == CS_OK
) {
544 if (strcmp(str
, "nss") == 0) {
547 if (strcmp(str
, "openssl") == 0) {
548 tmp_model
= "openssl";
555 if (icmap_get_string_r(map
, "totem.secauth", &str
) == CS_OK
) {
556 if (strcmp(str
, "on") == 0) {
557 tmp_cipher
= "aes256";
563 if (icmap_get_string_r(map
, "totem.crypto_cipher", &str
) == CS_OK
) {
564 if (strcmp(str
, "none") == 0) {
567 if (strcmp(str
, "aes256") == 0) {
568 tmp_cipher
= "aes256";
570 if (strcmp(str
, "aes192") == 0) {
571 tmp_cipher
= "aes192";
573 if (strcmp(str
, "aes128") == 0) {
574 tmp_cipher
= "aes128";
579 if (icmap_get_string_r(map
, "totem.crypto_hash", &str
) == CS_OK
) {
580 if (strcmp(str
, "none") == 0) {
583 if (strcmp(str
, "md5") == 0) {
586 if (strcmp(str
, "sha1") == 0) {
589 if (strcmp(str
, "sha256") == 0) {
592 if (strcmp(str
, "sha384") == 0) {
595 if (strcmp(str
, "sha512") == 0) {
601 if ((strcmp(tmp_cipher
, "none") != 0) &&
602 (strcmp(tmp_hash
, "none") == 0)) {
603 *error_string
= "crypto_cipher requires crypto_hash with value other than none";
607 if (strcmp(tmp_model
, "none") == 0) {
608 *error_string
= "crypto_model should be 'nss' or 'openssl'";
612 if (strcmp(tmp_cipher
, totem_config
->crypto_cipher_type
) ||
613 strcmp(tmp_hash
, totem_config
->crypto_hash_type
) ||
614 strcmp(tmp_model
, totem_config
->crypto_model
)) {
615 totem_config
->crypto_changed
= 1;
618 strncpy(totem_config
->crypto_cipher_type
, tmp_cipher
, CONFIG_STRING_LEN_MAX
);
619 strncpy(totem_config
->crypto_hash_type
, tmp_hash
, CONFIG_STRING_LEN_MAX
);
620 strncpy(totem_config
->crypto_model
, tmp_model
, CONFIG_STRING_LEN_MAX
);
625 static int nodelist_byname(icmap_map_t map
, const char *find_name
, int strip_domain
)
628 const char *iter_key
;
629 char name_str
[ICMAP_KEYNAME_MAXLEN
];
631 unsigned int node_pos
;
633 unsigned int namelen
;
635 iter
= icmap_iter_init_r(map
, "nodelist.node.");
636 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
637 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, name_str
);
641 /* ring0_addr is allowed as a fallback */
642 if (strcmp(name_str
, "name") && strcmp(name_str
, "ring0_addr")) {
645 if (icmap_get_string_r(map
, iter_key
, &name
) != CS_OK
) {
648 namelen
= strlen(name
);
652 dot
= strchr(name
, '.');
654 namelen
= name
- dot
- 1;
657 if (strncmp(find_name
, name
, namelen
) == 0 &&
658 strlen(find_name
) == strlen(name
)) {
659 icmap_iter_finalize(iter
);
663 icmap_iter_finalize(iter
);
667 /* Compare two addresses - only address part (sin_addr/sin6_addr) is checked */
668 static int ipaddr_equal(const struct sockaddr
*addr1
, const struct sockaddr
*addr2
)
671 const void *addr1p
, *addr2p
;
673 if (addr1
->sa_family
!= addr2
->sa_family
)
676 switch (addr1
->sa_family
) {
678 addrlen
= sizeof(struct in_addr
);
679 addr1p
= &((struct sockaddr_in
*)addr1
)->sin_addr
;
680 addr2p
= &((struct sockaddr_in
*)addr2
)->sin_addr
;
683 addrlen
= sizeof(struct in6_addr
);
684 addr1p
= &((struct sockaddr_in6
*)addr1
)->sin6_addr
;
685 addr2p
= &((struct sockaddr_in6
*)addr2
)->sin6_addr
;
691 return (memcmp(addr1p
, addr2p
, addrlen
) == 0);
695 /* Finds the local node and returns its position in the nodelist.
696 * Uses nodelist.local_node_pos as a cache to save effort
698 static int find_local_node(icmap_map_t map
, int use_cache
)
700 char nodename2
[PATH_MAX
];
701 char name_str
[ICMAP_KEYNAME_MAXLEN
];
703 const char *iter_key
;
704 unsigned int cached_pos
;
707 struct ifaddrs
*ifa
, *ifa_list
;
712 struct utsname utsname
;
714 /* Check for cached value first */
716 if (icmap_get_uint32("nodelist.local_node_pos", &cached_pos
) == CS_OK
) {
721 res
= uname(&utsname
);
725 node
= utsname
.nodename
;
728 node_pos
= nodelist_byname(map
, node
, 0);
734 /* 2. Try to match with increasingly more
735 * specific versions of it
737 strcpy(nodename2
, node
);
738 dot
= strrchr(nodename2
, '.');
742 node_pos
= nodelist_byname(map
, nodename2
, 0);
747 dot
= strrchr(nodename2
, '.');
750 node_pos
= nodelist_byname(map
, nodename2
, 1);
757 * The corosync.conf name may not be related to uname at all,
758 * they may match a hostname on some network interface.
760 if (getifaddrs(&ifa_list
))
763 for (ifa
= ifa_list
; ifa
; ifa
= ifa
->ifa_next
) {
767 strcpy(nodename2
, node
);
772 if (sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
) {
776 if (sa
->sa_family
== AF_INET
) {
777 salen
= sizeof(struct sockaddr_in
);
779 if (sa
->sa_family
== AF_INET6
) {
780 salen
= sizeof(struct sockaddr_in6
);
783 if (getnameinfo(sa
, salen
,
784 nodename2
, sizeof(nodename2
),
787 node_pos
= nodelist_byname(map
, nodename2
, 0);
793 /* Truncate this name and try again */
794 dot
= strchr(nodename2
, '.');
798 node_pos
= nodelist_byname(map
, nodename2
, 0);
806 /* See if it's the IP address that's in corosync.conf */
807 if (getnameinfo(sa
, sizeof(*sa
),
808 nodename2
, sizeof(nodename2
),
809 NULL
, 0, NI_NUMERICHOST
))
812 node_pos
= nodelist_byname(map
, nodename2
, 0);
821 freeifaddrs(ifa_list
);
826 * This section covers the usecase where the nodename specified in cluster.conf
827 * is an alias specified in /etc/hosts. For example:
828 * <ipaddr> hostname alias1 alias2
829 * and <clusternode name="alias2">
830 * the above calls use uname and getnameinfo does not return aliases.
831 * here we take the name specified in cluster.conf, resolve it to an address
832 * and then compare against all known local ip addresses.
833 * if we have a match, we found our nodename. In theory this chunk of code
834 * could replace all the checks above, but let's avoid any possible regressions
835 * and use it as last.
838 iter
= icmap_iter_init_r(map
, "nodelist.node.");
839 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
840 char *dbnodename
= NULL
;
841 struct addrinfo hints
;
842 struct addrinfo
*result
= NULL
, *rp
= NULL
;
844 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, name_str
);
848 /* 'ring0_addr' is allowed as a fallback, but 'name' will be found first
849 * because the names are in alpha order.
851 if (strcmp(name_str
, "name") && strcmp(name_str
, "ring0_addr")) {
854 if (icmap_get_string_r(map
, iter_key
, &dbnodename
) != CS_OK
) {
858 memset(&hints
, 0, sizeof(struct addrinfo
));
859 hints
.ai_family
= AF_UNSPEC
;
860 hints
.ai_socktype
= SOCK_DGRAM
;
862 hints
.ai_protocol
= IPPROTO_UDP
;
864 if (getaddrinfo(dbnodename
, NULL
, &hints
, &result
)) {
868 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
869 for (ifa
= ifa_list
; ifa
; ifa
= ifa
->ifa_next
) {
871 ipaddr_equal(rp
->ai_addr
, ifa
->ifa_addr
)) {
872 freeaddrinfo(result
);
879 freeaddrinfo(result
);
882 icmap_iter_finalize(iter
);
883 freeifaddrs(ifa_list
);
887 res
= icmap_set_uint32_r(map
, "nodelist.local_node_pos", node_pos
);
893 static enum totem_ip_version_enum
totem_config_get_ip_version(struct totem_config
*totem_config
)
895 enum totem_ip_version_enum res
;
898 res
= TOTEM_IP_VERSION_6_4
;
900 if (totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) {
901 res
= TOTEM_IP_VERSION_4
;
904 if (icmap_get_string("totem.ip_version", &str
) == CS_OK
) {
905 if (strcmp(str
, "ipv4") == 0) {
906 res
= TOTEM_IP_VERSION_4
;
908 if (strcmp(str
, "ipv6") == 0) {
909 res
= TOTEM_IP_VERSION_6
;
911 if (strcmp(str
, "ipv6-4") == 0) {
912 res
= TOTEM_IP_VERSION_6_4
;
914 if (strcmp(str
, "ipv4-6") == 0) {
915 res
= TOTEM_IP_VERSION_4_6
;
923 static uint16_t generate_cluster_id (const char *cluster_name
)
928 for (i
= 0; i
< strlen(cluster_name
); i
++) {
930 value
+= cluster_name
[i
];
933 return (value
& 0xFFFF);
936 static int get_cluster_mcast_addr (
937 const char *cluster_name
,
938 unsigned int linknumber
,
939 enum totem_ip_version_enum ip_version
,
940 struct totem_ip_address
*res
)
943 char addr
[INET6_ADDRSTRLEN
+ 1];
946 if (cluster_name
== NULL
) {
950 clusterid
= generate_cluster_id(cluster_name
) + linknumber
;
951 memset (res
, 0, sizeof(*res
));
953 switch (ip_version
) {
954 case TOTEM_IP_VERSION_4
:
955 case TOTEM_IP_VERSION_4_6
:
956 snprintf(addr
, sizeof(addr
), "239.192.%d.%d", clusterid
>> 8, clusterid
% 0xFF);
958 case TOTEM_IP_VERSION_6
:
959 case TOTEM_IP_VERSION_6_4
:
960 snprintf(addr
, sizeof(addr
), "ff15::%x", clusterid
);
969 err
= totemip_parse (res
, addr
, ip_version
);
974 static unsigned int generate_nodeid(
975 struct totem_config
*totem_config
,
979 struct totem_ip_address totemip
;
981 /* AF_INET hard-coded here because auto-generated nodeids
983 if (totemip_parse(&totemip
, addr
, TOTEM_IP_VERSION_4
) != 0)
986 memcpy (&nodeid
, &totemip
.addr
, sizeof (unsigned int));
988 #if __BYTE_ORDER == __LITTLE_ENDIAN
989 nodeid
= swab32 (nodeid
);
992 if (totem_config
->clear_node_high_bit
) {
993 nodeid
&= 0x7FFFFFFF;
998 static int check_for_duplicate_nodeids(
999 struct totem_config
*totem_config
,
1000 const char **error_string
)
1003 icmap_iter_t subiter
;
1004 const char *iter_key
;
1007 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1008 char *ring0_addr
=NULL
;
1009 char *ring0_addr1
=NULL
;
1010 unsigned int node_pos
;
1011 unsigned int node_pos1
;
1012 unsigned int last_node_pos
= -1;
1013 unsigned int nodeid
;
1014 unsigned int nodeid1
;
1017 iter
= icmap_iter_init("nodelist.node.");
1018 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
1019 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, tmp_key
);
1025 * This relies on the fact the icmap keys are always returned in order
1026 * so all of the keys for a node will be grouped together. We're basically
1027 * just running the code below once for each node.
1029 if (last_node_pos
== node_pos
) {
1032 last_node_pos
= node_pos
;
1034 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.nodeid", node_pos
);
1037 /* Generated nodeids are only allowed for UDP/UDPU so ring0_addr is valid here */
1038 if (icmap_get_uint32(tmp_key
, &nodeid
) != CS_OK
) {
1040 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", node_pos
);
1041 if (icmap_get_string(tmp_key
, &ring0_addr
) != CS_OK
) {
1045 /* Generate nodeid so we can check that auto-generated nodeids don't clash either */
1046 nodeid
= generate_nodeid(totem_config
, ring0_addr
);
1054 subiter
= icmap_iter_init("nodelist.node.");
1055 while (((iter_key
= icmap_iter_next(subiter
, NULL
, NULL
)) != NULL
) && (node_pos1
< node_pos
)) {
1056 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos1
, tmp_key
);
1057 if ((res
!= 2) || (node_pos1
>= node_pos
)) {
1061 if (strcmp(tmp_key
, "nodeid") != 0) {
1065 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.nodeid", node_pos1
);
1066 if (icmap_get_uint32(tmp_key
, &nodeid1
) != CS_OK
) {
1068 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", node_pos1
);
1069 if (icmap_get_string(tmp_key
, &ring0_addr1
) != CS_OK
) {
1072 nodeid1
= generate_nodeid(totem_config
, ring0_addr1
);
1073 if (nodeid1
== -1) {
1078 if (nodeid
== nodeid1
) {
1080 snprintf (error_string_response
, sizeof(error_string_response
),
1081 "Nodeid %u%s%s%s appears twice in corosync.conf", nodeid
,
1082 autogenerated
?"(autogenerated from ":"",
1083 autogenerated
?ring0_addr
:"",
1084 autogenerated
?")":"");
1085 *error_string
= error_string_response
;
1089 icmap_iter_finalize(subiter
);
1091 icmap_iter_finalize(iter
);
1097 * This needs to be done last of all. It would be nice to do it when reading the
1098 * interface params, but the totem params need to have them to be read first. We
1099 * need both, so this is a way round that circular dependancy.
1101 static void calc_knet_ping_timers(struct totem_config
*totem_config
)
1103 char runtime_key_name
[ICMAP_KEYNAME_MAXLEN
];
1106 for (interface
= 0; interface
< INTERFACE_MAX
; interface
++) {
1108 if (totem_config
->interfaces
[interface
].configured
) {
1109 if (!totem_config
->interfaces
[interface
].knet_pong_count
) {
1110 totem_config
->interfaces
[interface
].knet_pong_count
= KNET_PONG_COUNT
;
1112 if (!totem_config
->interfaces
[interface
].knet_ping_timeout
) {
1113 totem_config
->interfaces
[interface
].knet_ping_timeout
=
1114 totem_config
->token_timeout
/ totem_config
->interfaces
[interface
].knet_pong_count
;
1116 snprintf(runtime_key_name
, sizeof(runtime_key_name
),
1117 "runtime.config.totem.interface.%d.knet_ping_timeout", interface
);
1118 icmap_set_uint32(runtime_key_name
, totem_config
->interfaces
[interface
].knet_ping_timeout
);
1120 if (!totem_config
->interfaces
[interface
].knet_ping_interval
) {
1121 totem_config
->interfaces
[interface
].knet_ping_interval
=
1122 totem_config
->token_timeout
/ (totem_config
->interfaces
[interface
].knet_pong_count
* 2);
1124 snprintf(runtime_key_name
, sizeof(runtime_key_name
),
1125 "runtime.config.totem.interface.%d.knet_ping_interval", interface
);
1126 icmap_set_uint32(runtime_key_name
, totem_config
->interfaces
[interface
].knet_ping_interval
);
1132 * Compute difference between two set of totem interface arrays and commit it.
1134 * are changed so for same ring, ip existing in both set1 and set2 are cleared
1135 * (set to 0), and ips which are only in set1 or set2 remains untouched.
1136 * totempg_node_add/remove is called.
1138 static void compute_and_set_totempg_interfaces(struct totem_interface
*set1
,
1139 struct totem_interface
*set2
)
1141 int ring_no
, set1_pos
, set2_pos
;
1142 struct totem_ip_address empty_ip_address
;
1144 memset(&empty_ip_address
, 0, sizeof(empty_ip_address
));
1146 for (ring_no
= 0; ring_no
< INTERFACE_MAX
; ring_no
++) {
1147 if (!set1
[ring_no
].configured
&& !set2
[ring_no
].configured
) {
1151 for (set1_pos
= 0; set1_pos
< set1
[ring_no
].member_count
; set1_pos
++) {
1152 for (set2_pos
= 0; set2_pos
< set2
[ring_no
].member_count
; set2_pos
++) {
1154 * For current ring_no remove all set1 items existing
1157 if (memcmp(&set1
[ring_no
].member_list
[set1_pos
],
1158 &set2
[ring_no
].member_list
[set2_pos
],
1159 sizeof(struct totem_ip_address
)) == 0) {
1160 memset(&set1
[ring_no
].member_list
[set1_pos
], 0,
1161 sizeof(struct totem_ip_address
));
1162 memset(&set2
[ring_no
].member_list
[set2_pos
], 0,
1163 sizeof(struct totem_ip_address
));
1169 for (ring_no
= 0; ring_no
< INTERFACE_MAX
; ring_no
++) {
1170 for (set1_pos
= 0; set1_pos
< set1
[ring_no
].member_count
; set1_pos
++) {
1172 * All items which remain in set1 and don't exist in set2 any more
1173 * have to be removed.
1175 if (memcmp(&set1
[ring_no
].member_list
[set1_pos
], &empty_ip_address
, sizeof(empty_ip_address
)) != 0) {
1176 log_printf(LOGSYS_LEVEL_DEBUG
,
1177 "removing dynamic member %s for ring %u",
1178 totemip_print(&set1
[ring_no
].member_list
[set1_pos
]),
1181 totempg_member_remove(&set1
[ring_no
].member_list
[set1_pos
], ring_no
);
1184 if (!set2
[ring_no
].configured
) {
1187 for (set2_pos
= 0; set2_pos
< set2
[ring_no
].member_count
; set2_pos
++) {
1189 * All items which remain in set2 and don't exist in set1 are new nodes
1190 * and have to be added.
1192 if (memcmp(&set2
[ring_no
].member_list
[set2_pos
], &empty_ip_address
, sizeof(empty_ip_address
)) != 0) {
1193 log_printf(LOGSYS_LEVEL_DEBUG
,
1194 "adding dynamic member %s for ring %u",
1195 totemip_print(&set2
[ring_no
].member_list
[set2_pos
]),
1198 totempg_member_add(&set2
[ring_no
].member_list
[set2_pos
], ring_no
);
1205 * Configure parameters for links
1207 static void configure_link_params(struct totem_config
*totem_config
, icmap_map_t map
)
1210 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1213 int local_node_pos
= find_local_node(map
, 0);
1215 for (i
= 0; i
<INTERFACE_MAX
; i
++) {
1216 if (!totem_config
->interfaces
[i
].configured
) {
1220 log_printf(LOGSYS_LEVEL_DEBUG
, "Configuring link %d params\n", i
);
1222 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring%u_addr", local_node_pos
, i
);
1223 if (icmap_get_string_r(map
, tmp_key
, &addr_string
) != CS_OK
) {
1227 err
= totemip_parse(&totem_config
->interfaces
[i
].local_ip
, addr_string
, totem_config
->ip_version
);
1231 totem_config
->interfaces
[i
].local_ip
.nodeid
= totem_config
->node_id
;
1233 /* In case this is a new link, fill in the defaults if there was no interface{} section for it */
1234 if (!totem_config
->interfaces
[i
].knet_link_priority
)
1235 totem_config
->interfaces
[i
].knet_link_priority
= 1;
1237 /* knet_ping_interval & knet_ping_timeout are set later once we know all the other params */
1238 if (!totem_config
->interfaces
[i
].knet_ping_precision
)
1239 totem_config
->interfaces
[i
].knet_ping_precision
= KNET_PING_PRECISION
;
1240 if (!totem_config
->interfaces
[i
].knet_pong_count
)
1241 totem_config
->interfaces
[i
].knet_pong_count
= KNET_PONG_COUNT
;
1242 if (!totem_config
->interfaces
[i
].knet_transport
)
1243 totem_config
->interfaces
[i
].knet_transport
= KNET_TRANSPORT_UDP
;
1244 if (!totem_config
->interfaces
[i
].ip_port
)
1245 totem_config
->interfaces
[i
].ip_port
= DEFAULT_PORT
+ i
;
1250 static void configure_totem_links(struct totem_config
*totem_config
, icmap_map_t map
)
1254 for (i
= 0; i
<INTERFACE_MAX
; i
++) {
1255 if (!totem_config
->interfaces
[i
].configured
) {
1259 log_printf(LOGSYS_LEVEL_INFO
, "Configuring link %d\n", i
);
1261 totempg_iface_set(&totem_config
->interfaces
[i
].local_ip
, totem_config
->interfaces
[i
].ip_port
, i
);
1265 /* Check for differences in config that can't be done on-the-fly and print an error */
1266 static int check_things_have_not_changed(struct totem_config
*totem_config
, const char **error_string
)
1270 char addr_buf
[INET6_ADDRSTRLEN
];
1273 for (i
= 0; i
<INTERFACE_MAX
; i
++) {
1274 if (totem_config
->interfaces
[i
].configured
&&
1275 totem_config
->orig_interfaces
[i
].configured
) {
1276 if (totem_config
->interfaces
[i
].knet_transport
!=
1277 totem_config
->orig_interfaces
[i
].knet_transport
) {
1278 log_printf(LOGSYS_LEVEL_ERROR
,
1279 "New config has different knet transport for link %d. Internal value was NOT changed.\n", i
);
1283 /* Check each nodeid in the new configuration and make sure its IP address on this link has not changed */
1284 for (j
=0; j
< totem_config
->interfaces
[i
].member_count
; j
++) {
1285 for (k
=0; k
< totem_config
->orig_interfaces
[i
].member_count
; k
++) {
1287 if (totem_config
->interfaces
[i
].member_list
[j
].nodeid
==
1288 totem_config
->orig_interfaces
[i
].member_list
[k
].nodeid
) {
1290 /* Found our nodeid - check the IP address */
1291 if (memcmp(&totem_config
->interfaces
[i
].member_list
[j
],
1292 &totem_config
->orig_interfaces
[i
].member_list
[k
],
1293 sizeof(struct totem_ip_address
))) {
1295 ip_str
= totemip_print(&totem_config
->orig_interfaces
[i
].member_list
[k
]);
1297 /* if ip_str is NULL then the old address was invalid and is allowed to change */
1299 strncpy(addr_buf
, ip_str
, sizeof(addr_buf
));
1300 addr_buf
[sizeof(addr_buf
) - 1] = '\0';
1301 log_printf(LOGSYS_LEVEL_ERROR
,
1302 "new config has different address for link %d (addr changed from %s to %s). Internal value was NOT changed.\n",
1303 i
, addr_buf
, totemip_print(&totem_config
->interfaces
[i
].member_list
[j
]));
1314 snprintf (error_string_response
, sizeof(error_string_response
),
1315 "To reconfigure an interface it must be deleted and recreated. A working interface needs to be available to corosync at all times");
1316 *error_string
= error_string_response
;
1323 static int put_nodelist_members_to_config(struct totem_config
*totem_config
, icmap_map_t map
,
1324 int reload
, const char **error_string
)
1326 icmap_iter_t iter
, iter2
;
1327 const char *iter_key
, *iter_key2
;
1329 unsigned int node_pos
;
1330 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1331 char tmp_key2
[ICMAP_KEYNAME_MAXLEN
];
1332 char *node_addr_str
;
1334 unsigned int linknumber
= 0;
1336 int last_node_pos
= -1;
1338 /* Clear out nodelist so we can put the new one in if needed */
1339 for (i
= 0; i
< INTERFACE_MAX
; i
++) {
1340 for (j
= 0; j
< PROCESSOR_COUNT_MAX
; j
++) {
1341 memset(&totem_config
->interfaces
[i
].member_list
[j
], 0, sizeof(struct totem_ip_address
));
1343 totem_config
->interfaces
[i
].member_count
= 0;
1346 iter
= icmap_iter_init_r(map
, "nodelist.node.");
1347 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
1348 res
= sscanf(iter_key
, "nodelist.node.%u.%s", &node_pos
, tmp_key
);
1352 /* If it's the same as the last node_pos then skip it */
1353 if (node_pos
== last_node_pos
) {
1356 last_node_pos
= node_pos
;
1358 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.", node_pos
);
1359 iter2
= icmap_iter_init_r(map
, tmp_key
);
1360 while ((iter_key2
= icmap_iter_next(iter2
, NULL
, NULL
)) != NULL
) {
1361 unsigned int nodeid
;
1364 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.nodeid", node_pos
);
1365 if (icmap_get_uint32_r(map
, tmp_key
, &nodeid
) != CS_OK
) {
1369 res
= sscanf(iter_key2
, "nodelist.node.%u.ring%u%s", &node_pos
, &linknumber
, tmp_key2
);
1370 if (res
!= 3 || strcmp(tmp_key2
, "_addr") != 0) {
1373 if (linknumber
>= INTERFACE_MAX
) {
1374 snprintf (error_string_response
, sizeof(error_string_response
),
1375 "parse error in config: interface ring number %u is bigger than allowed maximum %u\n",
1376 linknumber
, INTERFACE_MAX
- 1);
1377 *error_string
= error_string_response
;
1379 icmap_iter_finalize(iter2
);
1380 icmap_iter_finalize(iter
);
1384 if (icmap_get_string_r(map
, iter_key2
, &node_addr_str
) != CS_OK
) {
1388 /* Generate nodeids if they are not provided and transport is UDP/U */
1390 (totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
||
1391 totem_config
->transport_number
== TOTEM_TRANSPORT_UDPU
)) {
1392 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", node_pos
);
1393 if (icmap_get_string_r(map
, tmp_key
, &str
) == CS_OK
) {
1394 nodeid
= generate_nodeid(totem_config
, str
);
1396 sprintf(error_string_response
,
1397 "An IPV6 network requires that a node ID be specified "
1398 "for address '%s'.", node_addr_str
);
1399 *error_string
= error_string_response
;
1405 log_printf(LOGSYS_LEVEL_DEBUG
,
1406 "Generated nodeid = " CS_PRI_NODE_ID
" for %s", nodeid
, str
);
1411 member_count
= totem_config
->interfaces
[linknumber
].member_count
;
1412 res
= totemip_parse(&totem_config
->interfaces
[linknumber
].member_list
[member_count
],
1413 node_addr_str
, totem_config
->ip_version
);
1415 totem_config
->interfaces
[linknumber
].member_list
[member_count
].nodeid
= nodeid
;
1416 totem_config
->interfaces
[linknumber
].member_count
++;
1417 totem_config
->interfaces
[linknumber
].configured
= 1;
1419 sprintf(error_string_response
, "failed to parse node address '%s'\n", node_addr_str
);
1420 *error_string
= error_string_response
;
1422 memset(&totem_config
->interfaces
[linknumber
].member_list
[member_count
], 0,
1423 sizeof(struct totem_ip_address
));
1425 free(node_addr_str
);
1426 icmap_iter_finalize(iter2
);
1427 icmap_iter_finalize(iter
);
1431 free(node_addr_str
);
1434 icmap_iter_finalize(iter2
);
1437 icmap_iter_finalize(iter
);
1439 configure_link_params(totem_config
, map
);
1441 log_printf(LOGSYS_LEVEL_DEBUG
, "About to reconfigure links from nodelist.\n");
1443 if (check_things_have_not_changed(totem_config
, error_string
) == -1) {
1450 static void config_convert_nodelist_to_interface(icmap_map_t map
, struct totem_config
*totem_config
)
1454 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1455 char tmp_key2
[ICMAP_KEYNAME_MAXLEN
];
1456 char *node_addr_str
;
1457 unsigned int linknumber
= 0;
1459 const char *iter_key
;
1461 node_pos
= find_local_node(map
, 1);
1462 if (node_pos
> -1) {
1464 * We found node, so create interface section
1466 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.", node_pos
);
1467 iter
= icmap_iter_init_r(map
, tmp_key
);
1468 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
1469 res
= sscanf(iter_key
, "nodelist.node.%u.ring%u%s", &node_pos
, &linknumber
, tmp_key2
);
1470 if (res
!= 3 || strcmp(tmp_key2
, "_addr") != 0) {
1474 if (icmap_get_string_r(map
, iter_key
, &node_addr_str
) != CS_OK
) {
1478 snprintf(tmp_key2
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.bindnetaddr", linknumber
);
1479 icmap_set_string_r(map
, tmp_key2
, node_addr_str
);
1480 free(node_addr_str
);
1482 icmap_iter_finalize(iter
);
1486 static int get_interface_params(struct totem_config
*totem_config
, icmap_map_t map
,
1487 const char **error_string
, uint64_t *warnings
,
1491 unsigned int linknumber
= 0;
1492 int member_count
= 0;
1494 icmap_iter_t iter
, member_iter
;
1495 const char *iter_key
;
1496 const char *member_iter_key
;
1497 char linknumber_key
[ICMAP_KEYNAME_MAXLEN
];
1498 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1502 char *cluster_name
= NULL
;
1503 enum totem_ip_version_enum tmp_ip_version
= TOTEM_IP_VERSION_4
;
1507 for (i
=0; i
<INTERFACE_MAX
; i
++) {
1509 * Set back to defaults things that might have been configured and
1510 * now have been taken out of corosync.conf. These won't be caught by the
1511 * code below which only looks at interface{} sections that actually exist.
1513 totem_config
->interfaces
[i
].configured
= 0;
1514 totem_config
->interfaces
[i
].knet_ping_timeout
= 0;
1515 totem_config
->interfaces
[i
].knet_ping_interval
= 0;
1516 totem_config
->interfaces
[i
].knet_ping_precision
= KNET_PING_PRECISION
;
1517 totem_config
->interfaces
[i
].knet_pong_count
= KNET_PONG_COUNT
;
1520 if (icmap_get_string_r(map
, "totem.cluster_name", &cluster_name
) != CS_OK
) {
1521 cluster_name
= NULL
;
1524 iter
= icmap_iter_init_r(map
, "totem.interface.");
1525 while ((iter_key
= icmap_iter_next(iter
, NULL
, NULL
)) != NULL
) {
1526 res
= sscanf(iter_key
, "totem.interface.%[^.].%s", linknumber_key
, tmp_key
);
1531 if (strcmp(tmp_key
, "bindnetaddr") != 0 && totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) {
1536 linknumber
= atoi(linknumber_key
);
1538 if (linknumber
>= INTERFACE_MAX
) {
1539 snprintf (error_string_response
, sizeof(error_string_response
),
1540 "parse error in config: interface ring number %u is bigger than allowed maximum %u\n",
1541 linknumber
, INTERFACE_MAX
- 1);
1543 *error_string
= error_string_response
;
1548 /* These things are only valid for the initial read */
1551 * Get the bind net address
1553 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.bindnetaddr", linknumber
);
1555 if (icmap_get_string_r(map
, tmp_key
, &str
) == CS_OK
) {
1556 res
= totemip_parse (&totem_config
->interfaces
[linknumber
].bindnet
, str
,
1557 totem_config
->ip_version
);
1560 sprintf(error_string_response
, "failed to parse bindnet address '%s'\n", str
);
1561 *error_string
= error_string_response
;
1572 * Get interface multicast address
1574 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastaddr", linknumber
);
1575 if (icmap_get_string_r(map
, tmp_key
, &str
) == CS_OK
) {
1576 res
= totemip_parse (&totem_config
->interfaces
[linknumber
].mcast_addr
, str
,
1577 totem_config
->ip_version
);
1580 sprintf(error_string_response
, "failed to parse mcast address '%s'\n", str
);
1581 *error_string
= error_string_response
;
1589 } else if (totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) {
1591 * User not specified address -> autogenerate one from cluster_name key
1592 * (if available). Return code is intentionally ignored, because
1593 * udpu doesn't need mcastaddr and validity of mcastaddr for udp is
1594 * checked later anyway.
1597 if (totem_config
->interfaces
[0].bindnet
.family
== AF_INET
) {
1598 tmp_ip_version
= TOTEM_IP_VERSION_4
;
1599 } else if (totem_config
->interfaces
[0].bindnet
.family
== AF_INET6
) {
1600 tmp_ip_version
= TOTEM_IP_VERSION_6
;
1603 (void)get_cluster_mcast_addr (cluster_name
,
1606 &totem_config
->interfaces
[linknumber
].mcast_addr
);
1609 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.broadcast", linknumber
);
1610 if (icmap_get_string(tmp_key
, &str
) == CS_OK
) {
1611 if (strcmp (str
, "yes") == 0) {
1612 totem_config
->broadcast_use
= 1;
1618 /* These things are only valid for the initial read OR a newly-defined link */
1619 if (!reload
|| (totem_config
->interfaces
[linknumber
].configured
== 0)) {
1624 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastport", linknumber
);
1625 if (icmap_get_uint16_r(map
, tmp_key
, &totem_config
->interfaces
[linknumber
].ip_port
) != CS_OK
) {
1626 if (totem_config
->broadcast_use
) {
1627 totem_config
->interfaces
[linknumber
].ip_port
= DEFAULT_PORT
+ (2 * linknumber
);
1629 totem_config
->interfaces
[linknumber
].ip_port
= DEFAULT_PORT
+ linknumber
;
1636 totem_config
->interfaces
[linknumber
].ttl
= 1;
1638 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.ttl", linknumber
);
1640 if (icmap_get_uint8_r(map
, tmp_key
, &u8
) == CS_OK
) {
1641 totem_config
->interfaces
[linknumber
].ttl
= u8
;
1644 totem_config
->interfaces
[linknumber
].knet_transport
= KNET_DEFAULT_TRANSPORT
;
1645 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_transport", linknumber
);
1646 if (icmap_get_string_r(map
, tmp_key
, &str
) == CS_OK
) {
1647 if (strcmp(str
, "sctp") == 0) {
1648 totem_config
->interfaces
[linknumber
].knet_transport
= KNET_TRANSPORT_SCTP
;
1650 else if (strcmp(str
, "udp") == 0) {
1651 totem_config
->interfaces
[linknumber
].knet_transport
= KNET_TRANSPORT_UDP
;
1654 *error_string
= "Unrecognised knet_transport. expected 'udp' or 'sctp'";
1660 totem_config
->interfaces
[linknumber
].configured
= 1;
1663 * Get the knet link params
1665 totem_config
->interfaces
[linknumber
].knet_link_priority
= 1;
1666 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_link_priority", linknumber
);
1668 if (icmap_get_uint8_r(map
, tmp_key
, &u8
) == CS_OK
) {
1669 totem_config
->interfaces
[linknumber
].knet_link_priority
= u8
;
1672 totem_config
->interfaces
[linknumber
].knet_ping_interval
= 0; /* real default applied later */
1673 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_ping_interval", linknumber
);
1674 if (icmap_get_uint32_r(map
, tmp_key
, &u32
) == CS_OK
) {
1675 totem_config
->interfaces
[linknumber
].knet_ping_interval
= u32
;
1677 totem_config
->interfaces
[linknumber
].knet_ping_timeout
= 0; /* real default applied later */
1678 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_ping_timeout", linknumber
);
1679 if (icmap_get_uint32_r(map
, tmp_key
, &u32
) == CS_OK
) {
1680 totem_config
->interfaces
[linknumber
].knet_ping_timeout
= u32
;
1682 totem_config
->interfaces
[linknumber
].knet_ping_precision
= KNET_PING_PRECISION
;
1683 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_ping_precision", linknumber
);
1684 if (icmap_get_uint32_r(map
, tmp_key
, &u32
) == CS_OK
) {
1685 totem_config
->interfaces
[linknumber
].knet_ping_precision
= u32
;
1687 totem_config
->interfaces
[linknumber
].knet_pong_count
= KNET_PONG_COUNT
;
1688 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.knet_pong_count", linknumber
);
1689 if (icmap_get_uint32_r(map
, tmp_key
, &u32
) == CS_OK
) {
1690 totem_config
->interfaces
[linknumber
].knet_pong_count
= u32
;
1693 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.member.", linknumber
);
1694 member_iter
= icmap_iter_init_r(map
, tmp_key
);
1695 while ((member_iter_key
= icmap_iter_next(member_iter
, NULL
, NULL
)) != NULL
) {
1696 if (member_count
== 0) {
1697 if (icmap_get_string("nodelist.node.0.ring0_addr", &str
) == CS_OK
) {
1699 *warnings
|= TOTEM_CONFIG_WARNING_MEMBERS_IGNORED
;
1702 *warnings
|= TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED
;
1706 if (icmap_get_string_r(map
, member_iter_key
, &str
) == CS_OK
) {
1707 res
= totemip_parse (&totem_config
->interfaces
[linknumber
].member_list
[member_count
++],
1708 str
, totem_config
->ip_version
);
1710 sprintf(error_string_response
, "failed to parse node address '%s'\n", str
);
1711 *error_string
= error_string_response
;
1713 icmap_iter_finalize(member_iter
);
1722 icmap_iter_finalize(member_iter
);
1724 totem_config
->interfaces
[linknumber
].member_count
= member_count
;
1729 icmap_iter_finalize(iter
);
1735 extern int totem_config_read (
1736 struct totem_config
*totem_config
,
1737 const char **error_string
,
1741 char *str
, *ring0_addr_str
;
1742 char tmp_key
[ICMAP_KEYNAME_MAXLEN
];
1750 memset (totem_config
, 0, sizeof (struct totem_config
));
1751 totem_config
->interfaces
= malloc (sizeof (struct totem_interface
) * INTERFACE_MAX
);
1752 if (totem_config
->interfaces
== 0) {
1753 *error_string
= "Out of memory trying to allocate ethernet interface storage area";
1757 totem_config
->transport_number
= TOTEM_TRANSPORT_KNET
;
1758 if (icmap_get_string("totem.transport", &str
) == CS_OK
) {
1759 if (strcmp (str
, "udpu") == 0) {
1760 totem_config
->transport_number
= TOTEM_TRANSPORT_UDPU
;
1761 } else if (strcmp (str
, "udp") == 0) {
1762 totem_config
->transport_number
= TOTEM_TRANSPORT_UDP
;
1763 } else if (strcmp (str
, "knet") == 0) {
1764 totem_config
->transport_number
= TOTEM_TRANSPORT_KNET
;
1766 *error_string
= "Invalid transport type. Should be udpu, udp or knet";
1774 memset (totem_config
->interfaces
, 0,
1775 sizeof (struct totem_interface
) * INTERFACE_MAX
);
1777 strcpy (totem_config
->link_mode
, "passive");
1779 icmap_get_uint32("totem.version", (uint32_t *)&totem_config
->version
);
1781 /* initial crypto load */
1782 if (totem_get_crypto(totem_config
, icmap_get_global_map(), error_string
) != 0) {
1785 if (totem_config_keyread(totem_config
, icmap_get_global_map(), error_string
) != 0) {
1788 totem_config
->crypto_index
= 1;
1789 totem_config
->crypto_changed
= 0;
1791 if (icmap_get_string("totem.link_mode", &str
) == CS_OK
) {
1792 if (strlen(str
) >= TOTEM_LINK_MODE_BYTES
) {
1793 *error_string
= "totem.link_mode is too long";
1798 strcpy (totem_config
->link_mode
, str
);
1802 icmap_get_uint32("totem.nodeid", &totem_config
->node_id
);
1804 totem_config
->clear_node_high_bit
= 0;
1805 if (icmap_get_string("totem.clear_node_high_bit", &str
) == CS_OK
) {
1806 if (strcmp (str
, "yes") == 0) {
1807 totem_config
->clear_node_high_bit
= 1;
1812 icmap_get_uint32("totem.threads", &totem_config
->threads
);
1814 icmap_get_uint32("totem.netmtu", &totem_config
->net_mtu
);
1816 totem_config
->ip_version
= totem_config_get_ip_version(totem_config
);
1818 if (icmap_get_string("totem.interface.0.bindnetaddr", &str
) != CS_OK
) {
1820 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
1822 config_convert_nodelist_to_interface(icmap_get_global_map(), totem_config
);
1824 if (icmap_get_string("nodelist.node.0.ring0_addr", &ring0_addr_str
) == CS_OK
) {
1826 * Both bindnetaddr and ring0_addr are set.
1827 * Log warning information, and use nodelist instead
1829 *warnings
|= TOTEM_CONFIG_BINDNETADDR_NODELIST_SET
;
1831 config_convert_nodelist_to_interface(icmap_get_global_map(), totem_config
);
1833 free(ring0_addr_str
);
1840 * Broadcast option is global but set in interface section,
1841 * so reset before processing interfaces.
1843 totem_config
->broadcast_use
= 0;
1845 res
= get_interface_params(totem_config
, icmap_get_global_map(), error_string
, warnings
, 0);
1851 * Use broadcast is global, so if set, make sure to fill mcast addr correctly
1852 * broadcast is only supported for UDP so just do interface 0;
1854 if (totem_config
->broadcast_use
) {
1855 totemip_parse (&totem_config
->interfaces
[0].mcast_addr
,
1856 "255.255.255.255", TOTEM_IP_VERSION_4
);
1861 * Store automatically generated items back to icmap only for UDP
1863 if (totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) {
1864 for (i
= 0; i
< INTERFACE_MAX
; i
++) {
1865 if (!totem_config
->interfaces
[i
].configured
) {
1868 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastaddr", i
);
1869 if (icmap_get_string(tmp_key
, &str
) == CS_OK
) {
1872 str
= (char *)totemip_print(&totem_config
->interfaces
[i
].mcast_addr
);
1873 icmap_set_string(tmp_key
, str
);
1876 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "totem.interface.%u.mcastport", i
);
1877 if (icmap_get_uint16(tmp_key
, &u16
) != CS_OK
) {
1878 icmap_set_uint16(tmp_key
, totem_config
->interfaces
[i
].ip_port
);
1884 * Check existence of nodelist
1886 if ((icmap_get_string("nodelist.node.0.name", &str
) == CS_OK
) ||
1887 (icmap_get_string("nodelist.node.0.ring0_addr", &str
) == CS_OK
)) {
1892 local_node_pos
= find_local_node(icmap_get_global_map(), 1);
1893 if (local_node_pos
!= -1) {
1895 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.nodeid", local_node_pos
);
1897 nodeid_set
= (totem_config
->node_id
!= 0);
1898 if (icmap_get_uint32(tmp_key
, &totem_config
->node_id
) == CS_OK
&& nodeid_set
) {
1899 *warnings
|= TOTEM_CONFIG_WARNING_TOTEM_NODEID_IGNORED
;
1901 if ((totem_config
->transport_number
== TOTEM_TRANSPORT_KNET
) && (!totem_config
->node_id
)) {
1902 *error_string
= "Knet requires an explicit nodeid for the local node";
1906 if ((totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
||
1907 totem_config
->transport_number
== TOTEM_TRANSPORT_UDPU
) && (!totem_config
->node_id
)) {
1909 snprintf(tmp_key
, ICMAP_KEYNAME_MAXLEN
, "nodelist.node.%u.ring0_addr", local_node_pos
);
1910 icmap_get_string(tmp_key
, &str
);
1912 totem_config
->node_id
= generate_nodeid(totem_config
, str
);
1913 if (totem_config
->node_id
== -1) {
1914 *error_string
= "An IPV6 network requires that a node ID be specified";
1920 totem_config
->interfaces
[0].member_list
[local_node_pos
].nodeid
= totem_config
->node_id
;
1925 /* Users must not change this */
1926 icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
1929 if (put_nodelist_members_to_config(totem_config
, icmap_get_global_map(), 0, error_string
)) {
1935 * Get things that might change in the future (and can depend on totem_config->interfaces);
1937 totem_volatile_config_read(totem_config
, icmap_get_global_map(), NULL
);
1939 calc_knet_ping_timers(totem_config
);
1941 /* This is now done in the totemknet interface callback */
1942 /* configure_totem_links(totem_config, icmap_get_global_map()); */
1944 add_totem_config_notification(totem_config
);
1950 int totem_config_validate (
1951 struct totem_config
*totem_config
,
1952 const char **error_string
)
1954 static char local_error_reason
[512];
1955 char parse_error
[512];
1956 const char *error_reason
= local_error_reason
;
1959 int num_configured
= 0;
1960 unsigned int interface_max
= INTERFACE_MAX
;
1962 for (i
= 0; i
< INTERFACE_MAX
; i
++) {
1963 if (totem_config
->interfaces
[i
].configured
) {
1967 if (num_configured
== 0) {
1968 error_reason
= "No interfaces defined";
1972 /* Check we found a local node name */
1973 if (icmap_get_uint32("nodelist.local_node_pos", &u32
) != CS_OK
) {
1974 error_reason
= "No valid name found for local host";
1978 for (i
= 0; i
< INTERFACE_MAX
; i
++) {
1980 * Some error checking of parsed data to make sure its valid
1983 struct totem_ip_address null_addr
;
1985 if (!totem_config
->interfaces
[i
].configured
) {
1989 memset (&null_addr
, 0, sizeof (struct totem_ip_address
));
1991 if ((totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) &&
1992 memcmp (&totem_config
->interfaces
[i
].mcast_addr
, &null_addr
,
1993 sizeof (struct totem_ip_address
)) == 0) {
1994 snprintf (local_error_reason
, sizeof(local_error_reason
),
1995 "No multicast address specified for interface %u", i
);
1999 if (totem_config
->interfaces
[i
].ip_port
== 0) {
2000 snprintf (local_error_reason
, sizeof(local_error_reason
),
2001 "No multicast port specified for interface %u", i
);
2005 if (totem_config
->interfaces
[i
].ttl
> 255) {
2006 snprintf (local_error_reason
, sizeof(local_error_reason
),
2007 "Invalid TTL (should be 0..255) for interface %u", i
);
2010 if (totem_config
->transport_number
!= TOTEM_TRANSPORT_UDP
&&
2011 totem_config
->interfaces
[i
].ttl
!= 1) {
2012 snprintf (local_error_reason
, sizeof(local_error_reason
),
2013 "Can only set ttl on multicast transport types for interface %u", i
);
2016 if (totem_config
->interfaces
[i
].knet_link_priority
> 255) {
2017 snprintf (local_error_reason
, sizeof(local_error_reason
),
2018 "Invalid link priority (should be 0..255) for interface %u", i
);
2021 if (totem_config
->transport_number
!= TOTEM_TRANSPORT_KNET
&&
2022 totem_config
->interfaces
[i
].knet_link_priority
!= 1) {
2023 snprintf (local_error_reason
, sizeof(local_error_reason
),
2024 "Can only set link priority on knet transport type for interface %u", i
);
2028 if (totem_config
->interfaces
[i
].mcast_addr
.family
== AF_INET6
&&
2029 totem_config
->node_id
== 0) {
2030 snprintf (local_error_reason
, sizeof(local_error_reason
),
2031 "An IPV6 network requires that a node ID be specified for interface %u", i
);
2035 if (totem_config
->broadcast_use
== 0 && totem_config
->transport_number
== TOTEM_TRANSPORT_UDP
) {
2036 if (totem_config
->interfaces
[i
].mcast_addr
.family
!= totem_config
->interfaces
[i
].bindnet
.family
) {
2037 snprintf (local_error_reason
, sizeof(local_error_reason
),
2038 "Multicast address family does not match bind address family for interface %u", i
);
2042 if (totemip_is_mcast (&totem_config
->interfaces
[i
].mcast_addr
) != 0) {
2043 snprintf (local_error_reason
, sizeof(local_error_reason
),
2044 "mcastaddr is not a correct multicast address for interface %u", i
);
2050 if (totem_config
->version
!= 2) {
2051 error_reason
= "This totem parser can only parse version 2 configurations.";
2055 if (totem_volatile_config_validate(totem_config
, icmap_get_global_map(), error_string
) == -1) {
2059 if (check_for_duplicate_nodeids(totem_config
, error_string
) == -1) {
2064 * KNET Link values validation
2066 if (strcmp (totem_config
->link_mode
, "active") &&
2067 strcmp (totem_config
->link_mode
, "rr") &&
2068 strcmp (totem_config
->link_mode
, "passive")) {
2069 snprintf (local_error_reason
, sizeof(local_error_reason
),
2070 "The Knet link mode \"%s\" specified is invalid. It must be active, passive or rr.\n", totem_config
->link_mode
);
2074 /* Only Knet does multiple interfaces */
2075 if (totem_config
->transport_number
!= TOTEM_TRANSPORT_KNET
) {
2079 if (interface_max
< num_configured
) {
2080 snprintf (parse_error
, sizeof(parse_error
),
2081 "%d is too many configured interfaces for non-Knet transport.",
2083 error_reason
= parse_error
;
2087 /* Only knet allows crypto */
2088 if (totem_config
->transport_number
!= TOTEM_TRANSPORT_KNET
) {
2089 if ((strcmp(totem_config
->crypto_cipher_type
, "none") != 0) ||
2090 (strcmp(totem_config
->crypto_hash_type
, "none") != 0)) {
2092 snprintf (parse_error
, sizeof(parse_error
),
2093 "crypto_cipher & crypto_hash are only valid for the Knet transport.");
2094 error_reason
= parse_error
;
2099 if (totem_config
->net_mtu
== 0) {
2100 if (totem_config
->transport_number
== TOTEM_TRANSPORT_KNET
) {
2101 totem_config
->net_mtu
= KNET_MAX_PACKET_SIZE
;
2104 totem_config
->net_mtu
= UDP_NETMTU
;
2111 snprintf (error_string_response
, sizeof(error_string_response
),
2112 "parse error in config: %s\n", error_reason
);
2113 *error_string
= error_string_response
;
2118 static int read_keyfile (
2119 const char *key_location
,
2120 struct totem_config
*totem_config
,
2121 const char **error_string
)
2126 char error_str
[100];
2127 const char *error_ptr
;
2129 fd
= open (key_location
, O_RDONLY
);
2131 error_ptr
= qb_strerror_r(errno
, error_str
, sizeof(error_str
));
2132 snprintf (error_string_response
, sizeof(error_string_response
),
2133 "Could not open %s: %s\n",
2134 key_location
, error_ptr
);
2138 res
= read (fd
, totem_config
->private_key
, TOTEM_PRIVATE_KEY_LEN_MAX
);
2139 saved_errno
= errno
;
2143 error_ptr
= qb_strerror_r (saved_errno
, error_str
, sizeof(error_str
));
2144 snprintf (error_string_response
, sizeof(error_string_response
),
2145 "Could not read %s: %s\n",
2146 key_location
, error_ptr
);
2150 if (res
< TOTEM_PRIVATE_KEY_LEN_MIN
) {
2151 snprintf (error_string_response
, sizeof(error_string_response
),
2152 "Could only read %d bits of minimum %u bits from %s.\n",
2153 res
* 8, TOTEM_PRIVATE_KEY_LEN_MIN
* 8, key_location
);
2157 totem_config
->private_key_len
= res
;
2162 *error_string
= error_string_response
;
2166 int totem_config_keyread (
2167 struct totem_config
*totem_config
,
2169 const char **error_string
)
2172 char *key_location
= NULL
;
2175 char old_key
[TOTEM_PRIVATE_KEY_LEN_MAX
];
2178 /* Take a copy so we can see if it has changed */
2179 memcpy(old_key
, totem_config
->private_key
, sizeof(totem_config
->private_key
));
2180 old_key_len
= totem_config
->private_key_len
;
2182 memset (totem_config
->private_key
, 0, sizeof(totem_config
->private_key
));
2183 totem_config
->private_key_len
= 0;
2185 if (strcmp(totem_config
->crypto_cipher_type
, "none") == 0 &&
2186 strcmp(totem_config
->crypto_hash_type
, "none") == 0) {
2190 /* cmap may store the location of the key file */
2191 if (icmap_get_string_r(map
, "totem.keyfile", &key_location
) == CS_OK
) {
2192 res
= read_keyfile(key_location
, totem_config
, error_string
);
2198 } else { /* Or the key itself may be in the cmap */
2199 if (icmap_get_r(map
, "totem.key", NULL
, &key_len
, NULL
) == CS_OK
) {
2200 if (key_len
> sizeof(totem_config
->private_key
)) {
2201 sprintf(error_string_response
, "key is too long");
2204 if (key_len
< TOTEM_PRIVATE_KEY_LEN_MIN
) {
2205 sprintf(error_string_response
, "key is too short");
2208 if (icmap_get_r(map
, "totem.key", totem_config
->private_key
, &key_len
, NULL
) == CS_OK
) {
2209 totem_config
->private_key_len
= key_len
;
2212 sprintf(error_string_response
, "can't load private key");
2218 /* In desperation we read the default filename */
2220 res
= read_keyfile(COROSYSCONFDIR
"/authkey", totem_config
, error_string
);
2225 if (old_key_len
!= totem_config
->private_key_len
||
2226 memcmp(old_key
, totem_config
->private_key
, sizeof(totem_config
->private_key
))) {
2227 totem_config
->crypto_changed
= 1;
2233 *error_string
= error_string_response
;
2238 int totem_reread_crypto_config(struct totem_config
*totem_config
, icmap_map_t map
, const char **error_string
)
2240 if (totem_get_crypto(totem_config
, map
, error_string
) != 0) {
2243 if (totem_config_keyread(totem_config
, map
, error_string
) != 0) {
2249 static void debug_dump_totem_config(const struct totem_config
*totem_config
)
2252 log_printf(LOGSYS_LEVEL_DEBUG
, "Token Timeout (%d ms) retransmit timeout (%d ms)",
2253 totem_config
->token_timeout
, totem_config
->token_retransmit_timeout
);
2254 if (totem_config
->token_warning
) {
2255 uint32_t token_warning_ms
= totem_config
->token_warning
* totem_config
->token_timeout
/ 100;
2256 log_printf(LOGSYS_LEVEL_DEBUG
, "Token warning every %d ms (%d%% of Token Timeout)",
2257 token_warning_ms
, totem_config
->token_warning
);
2258 if (token_warning_ms
< totem_config
->token_retransmit_timeout
)
2259 log_printf (LOGSYS_LEVEL_DEBUG
,
2260 "The token warning interval (%d ms) is less than the token retransmit timeout (%d ms) "
2261 "which can lead to spurious token warnings. Consider increasing the token_warning parameter.",
2262 token_warning_ms
, totem_config
->token_retransmit_timeout
);
2265 log_printf(LOGSYS_LEVEL_DEBUG
, "Token warnings disabled");
2266 log_printf(LOGSYS_LEVEL_DEBUG
, "token hold (%d ms) retransmits before loss (%d retrans)",
2267 totem_config
->token_hold_timeout
, totem_config
->token_retransmits_before_loss_const
);
2268 log_printf(LOGSYS_LEVEL_DEBUG
, "join (%d ms) send_join (%d ms) consensus (%d ms) merge (%d ms)",
2269 totem_config
->join_timeout
, totem_config
->send_join_timeout
, totem_config
->consensus_timeout
,
2270 totem_config
->merge_timeout
);
2271 log_printf(LOGSYS_LEVEL_DEBUG
, "downcheck (%d ms) fail to recv const (%d msgs)",
2272 totem_config
->downcheck_timeout
, totem_config
->fail_to_recv_const
);
2273 log_printf(LOGSYS_LEVEL_DEBUG
,
2274 "seqno unchanged const (%d rotations) Maximum network MTU %d",
2275 totem_config
->seqno_unchanged_const
, totem_config
->net_mtu
);
2276 log_printf(LOGSYS_LEVEL_DEBUG
,
2277 "window size per rotation (%d messages) maximum messages per rotation (%d messages)",
2278 totem_config
->window_size
, totem_config
->max_messages
);
2279 log_printf(LOGSYS_LEVEL_DEBUG
, "missed count const (%d messages)", totem_config
->miss_count_const
);
2280 log_printf(LOGSYS_LEVEL_DEBUG
, "heartbeat_failures_allowed (%d)",
2281 totem_config
->heartbeat_failures_allowed
);
2282 log_printf(LOGSYS_LEVEL_DEBUG
, "max_network_delay (%d ms)", totem_config
->max_network_delay
);
2286 static void totem_change_notify(
2288 const char *key_name
,
2289 struct icmap_notify_value new_val
,
2290 struct icmap_notify_value old_val
,
2293 struct totem_config
*totem_config
= (struct totem_config
*)user_data
;
2296 const char *deleted_key
= NULL
;
2297 const char *error_string
;
2300 * If a full reload is in progress then don't do anything until it's done and
2301 * can reconfigure it all atomically
2303 if (icmap_get_uint8("config.reload_in_progress", &reloading
) == CS_OK
&& reloading
)
2306 param
= totem_get_param_by_name((struct totem_config
*)user_data
, key_name
);
2308 * Process change only if changed key is found in totem_config (-> param is not NULL)
2309 * or for special key token_coefficient. token_coefficient key is not stored in
2310 * totem_config, but it is used for computation of token timeout.
2312 if (!param
&& strcmp(key_name
, "totem.token_coefficient") != 0)
2316 * Values other than UINT32 are not supported, or needed (yet)
2319 case ICMAP_TRACK_DELETE
:
2320 deleted_key
= key_name
;
2322 case ICMAP_TRACK_ADD
:
2323 case ICMAP_TRACK_MODIFY
:
2330 totem_volatile_config_read (totem_config
, icmap_get_global_map(), deleted_key
);
2331 log_printf(LOGSYS_LEVEL_DEBUG
, "Totem related config key changed. Dumping actual totem config.");
2332 debug_dump_totem_config(totem_config
);
2333 if (totem_volatile_config_validate(totem_config
, icmap_get_global_map(), &error_string
) == -1) {
2334 log_printf (LOGSYS_LEVEL_ERROR
, "%s", error_string
);
2336 * TODO: Consider corosync exit and/or load defaults for volatile
2337 * values. For now, log error seems to be enough
2343 int totemconfig_configure_new_params(
2344 struct totem_config
*totem_config
,
2346 const char **error_string
)
2348 uint64_t warnings
= 0LL;
2350 get_interface_params(totem_config
, map
, error_string
, &warnings
, 1);
2351 if (put_nodelist_members_to_config (totem_config
, map
, 1, error_string
)) {
2355 calc_knet_ping_timers(totem_config
);
2357 log_printf(LOGSYS_LEVEL_DEBUG
, "Configuration reloaded. Dumping actual totem config.");
2358 debug_dump_totem_config(totem_config
);
2360 /* Reinstate the local_node_pos */
2361 (void)find_local_node(map
, 0);
2366 void totemconfig_commit_new_params(
2367 struct totem_config
*totem_config
,
2370 struct totem_interface
*new_interfaces
= NULL
;
2372 new_interfaces
= malloc (sizeof (struct totem_interface
) * INTERFACE_MAX
);
2373 assert(new_interfaces
!= NULL
);
2374 memcpy(new_interfaces
, totem_config
->interfaces
, sizeof (struct totem_interface
) * INTERFACE_MAX
);
2376 /* Set link parameters including local_ip */
2377 configure_totem_links(totem_config
, map
);
2379 /* Add & remove nodes */
2380 compute_and_set_totempg_interfaces(totem_config
->orig_interfaces
, new_interfaces
);
2382 /* Does basic global params (like compression) */
2383 totempg_reconfigure();
2385 free(new_interfaces
);
2388 static void add_totem_config_notification(struct totem_config
*totem_config
)
2390 icmap_track_t icmap_track
;
2392 icmap_track_add("totem.",
2393 ICMAP_TRACK_ADD
| ICMAP_TRACK_DELETE
| ICMAP_TRACK_MODIFY
| ICMAP_TRACK_PREFIX
,
2394 totem_change_notify
,