]> git.proxmox.com Git - mirror_corosync.git/blob - exec/totemconfig.c
config: Allow use of ring0_addr
[mirror_corosync.git] / exec / totemconfig.c
1 /*
2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006-2018 Red Hat, Inc.
4 *
5 * All rights reserved.
6 *
7 * Author: Steven Dake (sdake@redhat.com)
8 * Jan Friesse (jfriesse@redhat.com)
9 *
10 * This software licensed under BSD license, the text of which follows:
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
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.
23 *
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.
35 */
36
37 #include <config.h>
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <sys/socket.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <ifaddrs.h>
49 #include <netdb.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <sys/param.h>
53 #include <sys/utsname.h>
54
55 #include <corosync/swab.h>
56 #include <qb/qblist.h>
57 #include <qb/qbdefs.h>
58 #include <libknet.h>
59 #include <corosync/totem/totem.h>
60 #include <corosync/config.h>
61 #include <corosync/logsys.h>
62 #include <corosync/icmap.h>
63
64 #include "util.h"
65 #include "totemconfig.h"
66
67 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
68 #define TOKEN_TIMEOUT 1000
69 #define TOKEN_COEFFICIENT 650
70 #define JOIN_TIMEOUT 50
71 #define MERGE_TIMEOUT 200
72 #define DOWNCHECK_TIMEOUT 1000
73 #define FAIL_TO_RECV_CONST 2500
74 #define SEQNO_UNCHANGED_CONST 30
75 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3
76 #define MAX_NETWORK_DELAY 50
77 #define WINDOW_SIZE 50
78 #define MAX_MESSAGES 17
79 #define MISS_COUNT_CONST 5
80
81 /* These currently match the defaults in libknet.h */
82 #define KNET_PING_INTERVAL 1000
83 #define KNET_PING_TIMEOUT 2000
84 #define KNET_PING_PRECISION 2048
85 #define KNET_PONG_COUNT 2
86 #define KNET_PMTUD_INTERVAL 30
87 #define KNET_DEFAULT_TRANSPORT KNET_TRANSPORT_UDP
88
89 #define DEFAULT_PORT 5405
90
91 static char error_string_response[512];
92
93 static void add_totem_config_notification(struct totem_config *totem_config);
94
95 static void *totem_get_param_by_name(struct totem_config *totem_config, const char *param_name)
96 {
97 if (strcmp(param_name, "totem.token") == 0)
98 return &totem_config->token_timeout;
99 if (strcmp(param_name, "totem.token_retransmit") == 0)
100 return &totem_config->token_retransmit_timeout;
101 if (strcmp(param_name, "totem.hold") == 0)
102 return &totem_config->token_hold_timeout;
103 if (strcmp(param_name, "totem.token_retransmits_before_loss_const") == 0)
104 return &totem_config->token_retransmits_before_loss_const;
105 if (strcmp(param_name, "totem.join") == 0)
106 return &totem_config->join_timeout;
107 if (strcmp(param_name, "totem.send_join") == 0)
108 return &totem_config->send_join_timeout;
109 if (strcmp(param_name, "totem.consensus") == 0)
110 return &totem_config->consensus_timeout;
111 if (strcmp(param_name, "totem.merge") == 0)
112 return &totem_config->merge_timeout;
113 if (strcmp(param_name, "totem.downcheck") == 0)
114 return &totem_config->downcheck_timeout;
115 if (strcmp(param_name, "totem.fail_recv_const") == 0)
116 return &totem_config->fail_to_recv_const;
117 if (strcmp(param_name, "totem.seqno_unchanged_const") == 0)
118 return &totem_config->seqno_unchanged_const;
119 if (strcmp(param_name, "totem.heartbeat_failures_allowed") == 0)
120 return &totem_config->heartbeat_failures_allowed;
121 if (strcmp(param_name, "totem.max_network_delay") == 0)
122 return &totem_config->max_network_delay;
123 if (strcmp(param_name, "totem.window_size") == 0)
124 return &totem_config->window_size;
125 if (strcmp(param_name, "totem.max_messages") == 0)
126 return &totem_config->max_messages;
127 if (strcmp(param_name, "totem.miss_count_const") == 0)
128 return &totem_config->miss_count_const;
129 if (strcmp(param_name, "totem.knet_pmtud_interval") == 0)
130 return &totem_config->knet_pmtud_interval;
131 if (strcmp(param_name, "totem.knet_compression_threshold") == 0)
132 return &totem_config->knet_compression_threshold;
133 if (strcmp(param_name, "totem.knet_compression_level") == 0)
134 return &totem_config->knet_compression_level;
135 if (strcmp(param_name, "totem.knet_compression_model") == 0)
136 return &totem_config->knet_compression_model;
137
138 return NULL;
139 }
140
141 /*
142 * Read key_name from icmap. If key is not found or key_name == delete_key or if allow_zero is false
143 * and readed value is zero, default value is used and stored into totem_config.
144 */
145 static void totem_volatile_config_set_uint32_value (struct totem_config *totem_config,
146 const char *key_name, const char *deleted_key, unsigned int default_value,
147 int allow_zero_value)
148 {
149 char runtime_key_name[ICMAP_KEYNAME_MAXLEN];
150
151 if (icmap_get_uint32(key_name, totem_get_param_by_name(totem_config, key_name)) != CS_OK ||
152 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0) ||
153 (!allow_zero_value && *(uint32_t *)totem_get_param_by_name(totem_config, key_name) == 0)) {
154 *(uint32_t *)totem_get_param_by_name(totem_config, key_name) = default_value;
155 }
156
157 /*
158 * Store totem_config value to cmap runtime section
159 */
160 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
161 /*
162 * This shouldn't happen
163 */
164 return ;
165 }
166
167 strcpy(runtime_key_name, "runtime.config.");
168 strcat(runtime_key_name, key_name);
169
170 icmap_set_uint32(runtime_key_name, *(uint32_t *)totem_get_param_by_name(totem_config, key_name));
171 }
172
173 static void totem_volatile_config_set_int32_value (struct totem_config *totem_config,
174 const char *key_name, const char *deleted_key, int default_value,
175 int allow_zero_value)
176 {
177 char runtime_key_name[ICMAP_KEYNAME_MAXLEN];
178
179 if (icmap_get_int32(key_name, totem_get_param_by_name(totem_config, key_name)) != CS_OK ||
180 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0) ||
181 (!allow_zero_value && *(int32_t *)totem_get_param_by_name(totem_config, key_name) == 0)) {
182 *(int32_t *)totem_get_param_by_name(totem_config, key_name) = default_value;
183 }
184
185 /*
186 * Store totem_config value to cmap runtime section
187 */
188 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
189 /*
190 * This shouldn't happen
191 */
192 return ;
193 }
194
195 strcpy(runtime_key_name, "runtime.config.");
196 strcat(runtime_key_name, key_name);
197
198 icmap_set_int32(runtime_key_name, *(int32_t *)totem_get_param_by_name(totem_config, key_name));
199 }
200
201 static void totem_volatile_config_set_string_value (struct totem_config *totem_config,
202 const char *key_name, const char *deleted_key, const char *default_value)
203 {
204 char runtime_key_name[ICMAP_KEYNAME_MAXLEN];
205 void **config_value;
206 void *old_config_ptr;
207
208 config_value = totem_get_param_by_name(totem_config, key_name);
209 old_config_ptr = *config_value;
210 if (icmap_get_string(key_name, totem_get_param_by_name(totem_config, key_name)) != CS_OK ||
211 (deleted_key != NULL && strcmp(deleted_key, key_name) == 0)) {
212
213 /* Need to strdup() here so that the free() below works for a default and a configured value */
214 *config_value = strdup(default_value);
215 }
216 free(old_config_ptr);
217
218 /*
219 * Store totem_config value to cmap runtime section
220 */
221 if (strlen("runtime.config.") + strlen(key_name) >= ICMAP_KEYNAME_MAXLEN) {
222 /*
223 * This shouldn't happen
224 */
225 return ;
226 }
227
228 strcpy(runtime_key_name, "runtime.config.");
229 strcat(runtime_key_name, key_name);
230
231 icmap_set_string(runtime_key_name, (char *)*config_value);
232 }
233
234
235 /*
236 * Read and validate config values from cmap and store them into totem_config. If key doesn't exists,
237 * default value is stored. deleted_key is name of key beeing processed by delete operation
238 * from cmap. It is considered as non existing even if it can be read. Can be NULL.
239 */
240 static void totem_volatile_config_read (struct totem_config *totem_config, const char *deleted_key)
241 {
242 uint32_t u32;
243
244 totem_volatile_config_set_uint32_value(totem_config, "totem.token_retransmits_before_loss_const", deleted_key,
245 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST, 0);
246
247 totem_volatile_config_set_uint32_value(totem_config, "totem.token", deleted_key, TOKEN_TIMEOUT, 0);
248
249 if (totem_config->interfaces[0].member_count > 2) {
250 u32 = TOKEN_COEFFICIENT;
251 icmap_get_uint32("totem.token_coefficient", &u32);
252 totem_config->token_timeout += (totem_config->interfaces[0].member_count - 2) * u32;
253
254 /*
255 * Store totem_config value to cmap runtime section
256 */
257 icmap_set_uint32("runtime.config.totem.token", totem_config->token_timeout);
258 }
259
260 totem_volatile_config_set_uint32_value(totem_config, "totem.max_network_delay", deleted_key, MAX_NETWORK_DELAY, 0);
261
262 totem_volatile_config_set_uint32_value(totem_config, "totem.window_size", deleted_key, WINDOW_SIZE, 0);
263
264 totem_volatile_config_set_uint32_value(totem_config, "totem.max_messages", deleted_key, MAX_MESSAGES, 0);
265
266 totem_volatile_config_set_uint32_value(totem_config, "totem.miss_count_const", deleted_key, MISS_COUNT_CONST, 0);
267 totem_volatile_config_set_uint32_value(totem_config, "totem.knet_pmtud_interval", deleted_key, KNET_PMTUD_INTERVAL, 0);
268
269 totem_volatile_config_set_uint32_value(totem_config, "totem.token_retransmit", deleted_key,
270 (int)(totem_config->token_timeout / (totem_config->token_retransmits_before_loss_const + 0.2)), 0);
271
272 totem_volatile_config_set_uint32_value(totem_config, "totem.hold", deleted_key,
273 (int)(totem_config->token_retransmit_timeout * 0.8 - (1000/HZ)), 0);
274
275 totem_volatile_config_set_uint32_value(totem_config, "totem.join", deleted_key, JOIN_TIMEOUT, 0);
276
277 totem_volatile_config_set_uint32_value(totem_config, "totem.consensus", deleted_key,
278 (int)(float)(1.2 * totem_config->token_timeout), 0);
279
280 totem_volatile_config_set_uint32_value(totem_config, "totem.merge", deleted_key, MERGE_TIMEOUT, 0);
281
282 totem_volatile_config_set_uint32_value(totem_config, "totem.downcheck", deleted_key, DOWNCHECK_TIMEOUT, 0);
283
284 totem_volatile_config_set_uint32_value(totem_config, "totem.fail_recv_const", deleted_key, FAIL_TO_RECV_CONST, 0);
285
286 totem_volatile_config_set_uint32_value(totem_config, "totem.seqno_unchanged_const", deleted_key,
287 SEQNO_UNCHANGED_CONST, 0);
288
289 totem_volatile_config_set_uint32_value(totem_config, "totem.send_join", deleted_key, 0, 1);
290
291 totem_volatile_config_set_uint32_value(totem_config, "totem.heartbeat_failures_allowed", deleted_key, 0, 1);
292
293 totem_volatile_config_set_uint32_value(totem_config, "totem.knet_compression_threshold", deleted_key, 0, 1);
294
295 totem_volatile_config_set_int32_value(totem_config, "totem.knet_compression_level", deleted_key, 0, 1);
296
297 totem_volatile_config_set_string_value(totem_config, "totem.knet_compression_model", deleted_key, "none");
298
299
300 }
301
302 static int totem_volatile_config_validate (
303 struct totem_config *totem_config,
304 const char **error_string)
305 {
306 static char local_error_reason[512];
307 const char *error_reason = local_error_reason;
308
309 if (totem_config->max_network_delay < MINIMUM_TIMEOUT) {
310 snprintf (local_error_reason, sizeof(local_error_reason),
311 "The max_network_delay parameter (%d ms) may not be less than (%d ms).",
312 totem_config->max_network_delay, MINIMUM_TIMEOUT);
313 goto parse_error;
314 }
315
316 if (totem_config->token_timeout < MINIMUM_TIMEOUT) {
317 snprintf (local_error_reason, sizeof(local_error_reason),
318 "The token timeout parameter (%d ms) may not be less than (%d ms).",
319 totem_config->token_timeout, MINIMUM_TIMEOUT);
320 goto parse_error;
321 }
322
323 if (totem_config->token_retransmit_timeout < MINIMUM_TIMEOUT) {
324 snprintf (local_error_reason, sizeof(local_error_reason),
325 "The token retransmit timeout parameter (%d ms) may not be less than (%d ms).",
326 totem_config->token_retransmit_timeout, MINIMUM_TIMEOUT);
327 goto parse_error;
328 }
329
330 if (totem_config->token_hold_timeout < MINIMUM_TIMEOUT) {
331 snprintf (local_error_reason, sizeof(local_error_reason),
332 "The token hold timeout parameter (%d ms) may not be less than (%d ms).",
333 totem_config->token_hold_timeout, MINIMUM_TIMEOUT);
334 goto parse_error;
335 }
336
337 if (totem_config->join_timeout < MINIMUM_TIMEOUT) {
338 snprintf (local_error_reason, sizeof(local_error_reason),
339 "The join timeout parameter (%d ms) may not be less than (%d ms).",
340 totem_config->join_timeout, MINIMUM_TIMEOUT);
341 goto parse_error;
342 }
343
344 if (totem_config->consensus_timeout < MINIMUM_TIMEOUT) {
345 snprintf (local_error_reason, sizeof(local_error_reason),
346 "The consensus timeout parameter (%d ms) may not be less than (%d ms).",
347 totem_config->consensus_timeout, MINIMUM_TIMEOUT);
348 goto parse_error;
349 }
350
351 if (totem_config->consensus_timeout < totem_config->join_timeout) {
352 snprintf (local_error_reason, sizeof(local_error_reason),
353 "The consensus timeout parameter (%d ms) may not be less than join timeout (%d ms).",
354 totem_config->consensus_timeout, totem_config->join_timeout);
355 goto parse_error;
356 }
357
358 if (totem_config->merge_timeout < MINIMUM_TIMEOUT) {
359 snprintf (local_error_reason, sizeof(local_error_reason),
360 "The merge timeout parameter (%d ms) may not be less than (%d ms).",
361 totem_config->merge_timeout, MINIMUM_TIMEOUT);
362 goto parse_error;
363 }
364
365 if (totem_config->downcheck_timeout < MINIMUM_TIMEOUT) {
366 snprintf (local_error_reason, sizeof(local_error_reason),
367 "The downcheck timeout parameter (%d ms) may not be less than (%d ms).",
368 totem_config->downcheck_timeout, MINIMUM_TIMEOUT);
369 goto parse_error;
370 }
371
372 return 0;
373
374 parse_error:
375 snprintf (error_string_response, sizeof(error_string_response),
376 "parse error in config: %s\n", error_reason);
377 *error_string = error_string_response;
378 return (-1);
379
380 }
381
382 static int totem_get_crypto(struct totem_config *totem_config, const char **error_string)
383 {
384 char *str;
385 const char *tmp_cipher;
386 const char *tmp_hash;
387 const char *tmp_model;
388
389 tmp_hash = "none";
390 tmp_cipher = "none";
391 tmp_model = "none";
392
393 if (icmap_get_string("totem.crypto_model", &str) == CS_OK) {
394 if (strcmp(str, "nss") == 0) {
395 tmp_model = "nss";
396 }
397 if (strcmp(str, "openssl") == 0) {
398 tmp_model = "openssl";
399 }
400 free(str);
401 } else {
402 tmp_model = "nss";
403 }
404
405 if (icmap_get_string("totem.crypto_cipher", &str) == CS_OK) {
406 if (strcmp(str, "none") == 0) {
407 tmp_cipher = "none";
408 }
409 if (strcmp(str, "aes256") == 0) {
410 tmp_cipher = "aes256";
411 }
412 if (strcmp(str, "aes192") == 0) {
413 tmp_cipher = "aes192";
414 }
415 if (strcmp(str, "aes128") == 0) {
416 tmp_cipher = "aes128";
417 }
418 if (strcmp(str, "3des") == 0) {
419 tmp_cipher = "3des";
420 }
421 free(str);
422 }
423
424 if (icmap_get_string("totem.crypto_hash", &str) == CS_OK) {
425 if (strcmp(str, "none") == 0) {
426 tmp_hash = "none";
427 }
428 if (strcmp(str, "md5") == 0) {
429 tmp_hash = "md5";
430 }
431 if (strcmp(str, "sha1") == 0) {
432 tmp_hash = "sha1";
433 }
434 if (strcmp(str, "sha256") == 0) {
435 tmp_hash = "sha256";
436 }
437 if (strcmp(str, "sha384") == 0) {
438 tmp_hash = "sha384";
439 }
440 if (strcmp(str, "sha512") == 0) {
441 tmp_hash = "sha512";
442 }
443 free(str);
444 }
445
446 if ((strcmp(tmp_cipher, "none") != 0) &&
447 (strcmp(tmp_hash, "none") == 0)) {
448 *error_string = "crypto_cipher requires crypto_hash with value other than none";
449 return -1;
450 }
451
452 if (strcmp(tmp_model, "none") == 0) {
453 *error_string = "crypto_model should be 'nss' or 'openssl'";
454 return -1;
455 }
456
457 free(totem_config->crypto_cipher_type);
458 free(totem_config->crypto_hash_type);
459 free(totem_config->crypto_model);
460
461 totem_config->crypto_cipher_type = strdup(tmp_cipher);
462 totem_config->crypto_hash_type = strdup(tmp_hash);
463 totem_config->crypto_model = strdup(tmp_model);
464
465 return 0;
466 }
467
468 static int nodelist_byname(const char *find_name, int strip_domain)
469 {
470 icmap_iter_t iter;
471 const char *iter_key;
472 char name_str[ICMAP_KEYNAME_MAXLEN];
473 int res = 0;
474 unsigned int node_pos;
475 char *name;
476 unsigned int namelen;
477
478 iter = icmap_iter_init("nodelist.node.");
479 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
480 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, name_str);
481 if (res != 2) {
482 continue;
483 }
484 /* ring0_addr is allowed as a fallback */
485 if (strcmp(name_str, "name") && strcmp(name_str, "ring0_addr")) {
486 continue;
487 }
488 if (icmap_get_string(iter_key, &name) != CS_OK) {
489 continue;
490 }
491 namelen = strlen(name);
492
493 if (strip_domain) {
494 char *dot;
495 dot = strchr(name, '.');
496 if (dot) {
497 namelen = name - dot - 1;
498 }
499 }
500 if (strncmp(find_name, name, namelen) == 0 &&
501 strlen(find_name) == strlen(name)) {
502 icmap_iter_finalize(iter);
503 return node_pos;
504 }
505 }
506 icmap_iter_finalize(iter);
507 return -1;
508 }
509
510 /* Compare two addresses */
511 static int ipaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
512 {
513 int addrlen = 0;
514
515 if (addr1->ss_family != addr2->ss_family)
516 return 0;
517
518 if (addr1->ss_family == AF_INET) {
519 addrlen = sizeof(struct sockaddr_in);
520 }
521 if (addr1->ss_family == AF_INET6) {
522 addrlen = sizeof(struct sockaddr_in6);
523 }
524 assert(addrlen);
525
526 if (memcmp(addr1, addr2, addrlen) == 0)
527 return 1;
528 else
529 return 0;
530
531 }
532
533
534 /* Finds the local node and returns its position in the nodelist.
535 * Uses nodelist.local_node_pos as a cache to save effort
536 */
537 static int find_local_node(int use_cache)
538 {
539 char nodename2[PATH_MAX];
540 char name_str[ICMAP_KEYNAME_MAXLEN];
541 icmap_iter_t iter;
542 const char *iter_key;
543 unsigned int cached_pos;
544 char *dot = NULL;
545 const char *node;
546 struct ifaddrs *ifa, *ifa_list;
547 struct sockaddr *sa;
548 int found = 0;
549 int node_pos = -1;
550 int res;
551 struct utsname utsname;
552
553 /* Check for cached value first */
554 if (use_cache) {
555 if (icmap_get_uint32("nodelist.local_node_pos", &cached_pos) == CS_OK) {
556 return cached_pos;
557 }
558 }
559
560 res = uname(&utsname);
561 if (res) {
562 return -1;
563 }
564 node = utsname.nodename;
565
566 /* 1. Exact match */
567 node_pos = nodelist_byname(node, 0);
568 if (node_pos > -1) {
569 found = 1;
570 goto ret_found;
571 }
572
573 /* 2. Try to match with increasingly more
574 * specific versions of it
575 */
576 strcpy(nodename2, node);
577 dot = strrchr(nodename2, '.');
578 while (dot) {
579 *dot = '\0';
580
581 node_pos = nodelist_byname(nodename2, 0);
582 if (node_pos > -1) {
583 found = 1;
584 goto ret_found;
585 }
586 dot = strrchr(nodename2, '.');
587 }
588
589 node_pos = nodelist_byname(nodename2, 1);
590 if (node_pos > -1) {
591 found = 1;
592 goto ret_found;
593 }
594
595 /*
596 * The corosync.conf name may not be related to uname at all,
597 * they may match a hostname on some network interface.
598 */
599 if (getifaddrs(&ifa_list))
600 return -1;
601
602 for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
603 socklen_t salen = 0;
604
605 /* Restore this */
606 strcpy(nodename2, node);
607 sa = ifa->ifa_addr;
608 if (!sa) {
609 continue;
610 }
611 if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) {
612 continue;
613 }
614
615 if (sa->sa_family == AF_INET) {
616 salen = sizeof(struct sockaddr_in);
617 }
618 if (sa->sa_family == AF_INET6) {
619 salen = sizeof(struct sockaddr_in6);
620 }
621
622 if (getnameinfo(sa, salen,
623 nodename2, sizeof(nodename2),
624 NULL, 0, 0) == 0) {
625
626 node_pos = nodelist_byname(nodename2, 0);
627 if (node_pos > -1) {
628 found = 1;
629 goto out;
630 }
631
632 /* Truncate this name and try again */
633 dot = strchr(nodename2, '.');
634 if (dot) {
635 *dot = '\0';
636
637 node_pos = nodelist_byname(nodename2, 0);
638 if (node_pos > -1) {
639 found = 1;
640 goto out;
641 }
642 }
643 }
644
645 /* See if it's the IP address that's in corosync.conf */
646 if (getnameinfo(sa, sizeof(*sa),
647 nodename2, sizeof(nodename2),
648 NULL, 0, NI_NUMERICHOST))
649 continue;
650
651 node_pos = nodelist_byname(nodename2, 0);
652 if (node_pos > -1) {
653 found = 1;
654 goto out;
655 }
656 }
657
658 out:
659 if (found) {
660 freeifaddrs(ifa_list);
661 goto ret_found;
662 }
663
664 /*
665 * This section covers the usecase where the nodename specified in cluster.conf
666 * is an alias specified in /etc/hosts. For example:
667 * <ipaddr> hostname alias1 alias2
668 * and <clusternode name="alias2">
669 * the above calls use uname and getnameinfo does not return aliases.
670 * here we take the name specified in cluster.conf, resolve it to an address
671 * and then compare against all known local ip addresses.
672 * if we have a match, we found our nodename. In theory this chunk of code
673 * could replace all the checks above, but let's avoid any possible regressions
674 * and use it as last.
675 */
676
677 iter = icmap_iter_init("nodelist.node.");
678 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
679 char *dbnodename = NULL;
680 struct addrinfo hints;
681 struct addrinfo *result = NULL, *rp = NULL;
682
683 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, name_str);
684 if (res != 2) {
685 continue;
686 }
687 /* 'ring0_addr' is allowed as a fallback, but 'name' will be found first
688 * because the names are in alpha order.
689 */
690 if (strcmp(name_str, "name") && strcmp(name_str, "ring0_addr")) {
691 continue;
692 }
693 if (icmap_get_string(iter_key, &dbnodename) != CS_OK) {
694 continue;
695 }
696
697 memset(&hints, 0, sizeof(struct addrinfo));
698 hints.ai_family = AF_UNSPEC;
699 hints.ai_socktype = SOCK_DGRAM;
700 hints.ai_flags = 0;
701 hints.ai_protocol = IPPROTO_UDP;
702
703 if (getaddrinfo(dbnodename, NULL, &hints, &result)) {
704 continue;
705 }
706
707 for (rp = result; rp != NULL; rp = rp->ai_next) {
708 for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
709 if (ifa->ifa_addr &&
710 ipaddr_equal((struct sockaddr_storage *)rp->ai_addr,
711 (struct sockaddr_storage *)ifa->ifa_addr)) {
712 freeaddrinfo(result);
713 found = 1;
714 goto out2;
715 }
716 }
717 }
718
719 freeaddrinfo(result);
720 }
721 out2:
722 icmap_iter_finalize(iter);
723 freeifaddrs(ifa_list);
724
725 ret_found:
726 if (found) {
727 res = icmap_set_uint32("nodelist.local_node_pos", node_pos);
728 }
729
730 return node_pos;
731 }
732
733 static int totem_config_get_ip_version(struct totem_config *totem_config)
734 {
735 int res;
736 char *str;
737
738 res = AF_INET;
739 if (totem_config->transport_number == TOTEM_TRANSPORT_KNET) {
740 res = AF_UNSPEC;
741 } else {
742 if (icmap_get_string("totem.ip_version", &str) == CS_OK) {
743 if (strcmp(str, "ipv4") == 0) {
744 res = AF_INET;
745 }
746 if (strcmp(str, "ipv6") == 0) {
747 res = AF_INET6;
748 }
749 free(str);
750 }
751 }
752
753 return (res);
754 }
755
756 static uint16_t generate_cluster_id (const char *cluster_name)
757 {
758 int i;
759 int value = 0;
760
761 for (i = 0; i < strlen(cluster_name); i++) {
762 value <<= 1;
763 value += cluster_name[i];
764 }
765
766 return (value & 0xFFFF);
767 }
768
769 static int get_cluster_mcast_addr (
770 const char *cluster_name,
771 unsigned int linknumber,
772 int ip_version,
773 struct totem_ip_address *res)
774 {
775 uint16_t clusterid;
776 char addr[INET6_ADDRSTRLEN + 1];
777 int err;
778
779 if (cluster_name == NULL) {
780 return (-1);
781 }
782
783 clusterid = generate_cluster_id(cluster_name) + linknumber;
784 memset (res, 0, sizeof(*res));
785
786 switch (ip_version) {
787 case AF_INET:
788 snprintf(addr, sizeof(addr), "239.192.%d.%d", clusterid >> 8, clusterid % 0xFF);
789 break;
790 case AF_INET6:
791 snprintf(addr, sizeof(addr), "ff15::%x", clusterid);
792 break;
793 default:
794 /*
795 * Unknown family
796 */
797 return (-1);
798 }
799
800 err = totemip_parse (res, addr, ip_version);
801
802 return (err);
803 }
804
805 static unsigned int generate_nodeid_for_duplicate_test(
806 struct totem_config *totem_config,
807 char *addr)
808 {
809 unsigned int nodeid;
810 struct totem_ip_address totemip;
811
812 /* AF_INET hard-coded here because auto-generated nodeids
813 are only for IPv4 */
814 if (totemip_parse(&totemip, addr, AF_INET) != 0)
815 return -1;
816
817 memcpy (&nodeid, &totemip.addr, sizeof (unsigned int));
818
819 #if __BYTE_ORDER == __LITTLE_ENDIAN
820 nodeid = swab32 (nodeid);
821 #endif
822
823 if (totem_config->clear_node_high_bit) {
824 nodeid &= 0x7FFFFFFF;
825 }
826 return nodeid;
827 }
828
829 static int check_for_duplicate_nodeids(
830 struct totem_config *totem_config,
831 const char **error_string)
832 {
833 icmap_iter_t iter;
834 icmap_iter_t subiter;
835 const char *iter_key;
836 int res = 0;
837 int retval = 0;
838 char tmp_key[ICMAP_KEYNAME_MAXLEN];
839 char *ring0_addr=NULL;
840 char *ring0_addr1=NULL;
841 unsigned int node_pos;
842 unsigned int node_pos1;
843 unsigned int nodeid;
844 unsigned int nodeid1;
845 int autogenerated;
846
847 iter = icmap_iter_init("nodelist.node.");
848 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
849 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
850 if (res != 2) {
851 continue;
852 }
853
854 if (strcmp(tmp_key, "nodeid") != 0) {
855 continue;
856 }
857
858 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
859 autogenerated = 0;
860
861 /* Generated nodeids are only allowed for UDP/UDPU so ring0_addr is valid here */
862 if (icmap_get_uint32(tmp_key, &nodeid) != CS_OK) {
863
864 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos);
865 if (icmap_get_string(tmp_key, &ring0_addr) != CS_OK) {
866 continue;
867 }
868
869 /* Generate nodeid so we can check that auto-generated nodeids don't clash either */
870 nodeid = generate_nodeid_for_duplicate_test(totem_config, ring0_addr);
871 if (nodeid == -1) {
872 continue;
873 }
874 autogenerated = 1;
875 }
876
877 node_pos1 = 0;
878 subiter = icmap_iter_init("nodelist.node.");
879 while (((iter_key = icmap_iter_next(subiter, NULL, NULL)) != NULL) && (node_pos1 < node_pos)) {
880 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos1, tmp_key);
881 if ((res != 2) || (node_pos1 >= node_pos)) {
882 continue;
883 }
884
885 if (strcmp(tmp_key, "nodeid") != 0) {
886 continue;
887 }
888
889 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos1);
890 if (icmap_get_uint32(tmp_key, &nodeid1) != CS_OK) {
891
892 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos1);
893 if (icmap_get_string(tmp_key, &ring0_addr1) != CS_OK) {
894 continue;
895 }
896 nodeid1 = generate_nodeid_for_duplicate_test(totem_config, ring0_addr1);
897 if (nodeid1 == -1) {
898 continue;
899 }
900 }
901
902 if (nodeid == nodeid1) {
903 retval = -1;
904 snprintf (error_string_response, sizeof(error_string_response),
905 "Nodeid %u%s%s%s appears twice in corosync.conf", nodeid,
906 autogenerated?"(autogenerated from ":"",
907 autogenerated?ring0_addr:"",
908 autogenerated?")":"");
909 log_printf (LOGSYS_LEVEL_ERROR, error_string_response);
910 *error_string = error_string_response;
911 break;
912 }
913 }
914 icmap_iter_finalize(subiter);
915 }
916 icmap_iter_finalize(iter);
917 return retval;
918 }
919
920
921 /*
922 * This needs to be done last of all. It would be nice to do it when reading the
923 * interface params, but the totem params need to have them to be read first. We
924 * need both, so this is a way round that circular dependancy.
925 */
926 static void calc_knet_ping_timers(struct totem_config *totem_config)
927 {
928 char runtime_key_name[ICMAP_KEYNAME_MAXLEN];
929 int interface;
930
931 for (interface = 0; interface < INTERFACE_MAX; interface++) {
932
933 if (totem_config->interfaces[interface].configured) {
934 if (!totem_config->interfaces[interface].knet_ping_timeout) {
935 totem_config->interfaces[interface].knet_ping_timeout =
936 totem_config->token_timeout / totem_config->interfaces[interface].knet_pong_count;
937 }
938 snprintf(runtime_key_name, sizeof(runtime_key_name),
939 "runtime.config.totem.interface.%d.knet_ping_timeout", interface);
940 icmap_set_uint32(runtime_key_name, totem_config->interfaces[interface].knet_ping_timeout);
941
942 if (!totem_config->interfaces[interface].knet_ping_interval) {
943 totem_config->interfaces[interface].knet_ping_interval =
944 totem_config->token_timeout / (totem_config->interfaces[interface].knet_pong_count * 2);
945 }
946 snprintf(runtime_key_name, sizeof(runtime_key_name),
947 "runtime.config.totem.interface.%d.knet_ping_interval", interface);
948 icmap_set_uint32(runtime_key_name, totem_config->interfaces[interface].knet_ping_interval);
949 }
950 }
951 }
952
953 /*
954 * Compute difference between two set of totem interface arrays. set1 and set2
955 * are changed so for same ring, ip existing in both set1 and set2 are cleared
956 * (set to 0), and ips which are only in set1 or set2 remains untouched.
957 * totempg_node_add/remove is called.
958 */
959 static void compute_interfaces_diff(struct totem_interface *set1,
960 struct totem_interface *set2)
961 {
962 int ring_no, set1_pos, set2_pos;
963 struct totem_ip_address empty_ip_address;
964
965 memset(&empty_ip_address, 0, sizeof(empty_ip_address));
966
967 for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
968 if (!set1[ring_no].configured && !set2[ring_no].configured) {
969 continue;
970 }
971
972 for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
973 for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
974 /*
975 * For current ring_no remove all set1 items existing
976 * in set2
977 */
978 if (memcmp(&set1[ring_no].member_list[set1_pos],
979 &set2[ring_no].member_list[set2_pos],
980 sizeof(struct totem_ip_address)) == 0) {
981 memset(&set1[ring_no].member_list[set1_pos], 0,
982 sizeof(struct totem_ip_address));
983 memset(&set2[ring_no].member_list[set2_pos], 0,
984 sizeof(struct totem_ip_address));
985 }
986 }
987 }
988 }
989
990 for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
991 for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
992 /*
993 * All items which remained in set1 doesn't exists in set2 any longer so
994 * node has to be removed.
995 */
996 if (memcmp(&set1[ring_no].member_list[set1_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
997 log_printf(LOGSYS_LEVEL_DEBUG,
998 "removing dynamic member %s for ring %u",
999 totemip_print(&set1[ring_no].member_list[set1_pos]),
1000 ring_no);
1001
1002 totempg_member_remove(&set1[ring_no].member_list[set1_pos], ring_no);
1003 }
1004 }
1005 if (!set2[ring_no].configured) {
1006 continue;
1007 }
1008 for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
1009 /*
1010 * All items which remained in set2 doesn't existed in set1 so this is no node
1011 * and has to be added.
1012 */
1013 if (memcmp(&set2[ring_no].member_list[set2_pos], &empty_ip_address, sizeof(empty_ip_address)) != 0) {
1014 log_printf(LOGSYS_LEVEL_DEBUG,
1015 "adding dynamic member %s for ring %u",
1016 totemip_print(&set2[ring_no].member_list[set2_pos]),
1017 ring_no);
1018
1019 totempg_member_add(&set2[ring_no].member_list[set2_pos], ring_no);
1020 }
1021 }
1022 }
1023 }
1024
1025 /*
1026 * Reconfigure links in totempg. Sets new local IP address and adds params for new links.
1027 */
1028 static void reconfigure_links(struct totem_config *totem_config)
1029 {
1030 int i;
1031 char tmp_key[ICMAP_KEYNAME_MAXLEN];
1032 char *addr_string;
1033 struct totem_ip_address local_ip;
1034 int err;
1035 int local_node_pos = find_local_node(0);
1036
1037 for (i = 0; i<INTERFACE_MAX; i++) {
1038 if (!totem_config->interfaces[i].configured) {
1039 continue;
1040 }
1041
1042 log_printf(LOGSYS_LEVEL_INFO, "Configuring link %d\n", i);
1043
1044 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring%u_addr", local_node_pos, i);
1045 if (icmap_get_string(tmp_key, &addr_string) != CS_OK) {
1046 continue;
1047 }
1048
1049 err = totemip_parse(&local_ip, addr_string, AF_UNSPEC);
1050 if (err != 0) {
1051 continue;
1052 }
1053 local_ip.nodeid = totem_config->node_id;
1054
1055 /* In case this is a new link, fill in the defaults if there was no interface{} section for it */
1056 if (!totem_config->interfaces[i].knet_link_priority)
1057 totem_config->interfaces[i].knet_link_priority = 1;
1058
1059 /* knet_ping_interval & knet_ping_timeout are set later once we know all the other params */
1060
1061 if (!totem_config->interfaces[i].knet_ping_precision)
1062 totem_config->interfaces[i].knet_ping_precision = KNET_PING_PRECISION;
1063 if (!totem_config->interfaces[i].knet_pong_count)
1064 totem_config->interfaces[i].knet_pong_count = KNET_PONG_COUNT;
1065 if (!totem_config->interfaces[i].knet_transport)
1066 totem_config->interfaces[i].knet_transport = KNET_TRANSPORT_UDP;
1067 if (!totem_config->interfaces[i].ip_port)
1068 totem_config->interfaces[i].ip_port = DEFAULT_PORT + i;
1069
1070 totempg_iface_set(&local_ip, totem_config->interfaces[i].ip_port, i);
1071 }
1072 }
1073
1074 static void put_nodelist_members_to_config(struct totem_config *totem_config, int reload)
1075 {
1076 icmap_iter_t iter, iter2;
1077 const char *iter_key, *iter_key2;
1078 int res = 0;
1079 unsigned int node_pos;
1080 char tmp_key[ICMAP_KEYNAME_MAXLEN];
1081 char tmp_key2[ICMAP_KEYNAME_MAXLEN];
1082 char *node_addr_str;
1083 int member_count;
1084 unsigned int linknumber = 0;
1085 int i, j;
1086 struct totem_interface *new_interfaces = NULL;
1087
1088 if (reload) {
1089 /*
1090 * We need to compute diff only for reload. Also for initial configuration
1091 * not all totem structures are initialized so corosync will crash during
1092 * member_add/remove
1093 */
1094 new_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
1095 assert(new_interfaces != NULL);
1096 }
1097
1098 /* Clear out nodelist so we can put the new one in if needed */
1099 for (i = 0; i < INTERFACE_MAX; i++) {
1100 for (j = 0; j < PROCESSOR_COUNT_MAX; j++) {
1101 memset(&totem_config->interfaces[i].member_list[j], 0, sizeof(struct totem_ip_address));
1102 }
1103 totem_config->interfaces[i].member_count = 0;
1104 }
1105
1106 iter = icmap_iter_init("nodelist.node.");
1107 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1108 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
1109 if (res != 2) {
1110 continue;
1111 }
1112 if (strcmp(tmp_key, "nodeid") != 0) {
1113 continue;
1114 }
1115
1116 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
1117 iter2 = icmap_iter_init(tmp_key);
1118 while ((iter_key2 = icmap_iter_next(iter2, NULL, NULL)) != NULL) {
1119 unsigned int nodeid;
1120
1121 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
1122 if (icmap_get_uint32(tmp_key, &nodeid) != CS_OK) {
1123 }
1124
1125 res = sscanf(iter_key2, "nodelist.node.%u.ring%u%s", &node_pos, &linknumber, tmp_key2);
1126 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
1127 continue;
1128 }
1129
1130 if (icmap_get_string(iter_key2, &node_addr_str) != CS_OK) {
1131 continue;
1132 }
1133
1134 member_count = totem_config->interfaces[linknumber].member_count;
1135 res = totemip_parse(&totem_config->interfaces[linknumber].member_list[member_count],
1136 node_addr_str, totem_config->ip_version);
1137 if (res != -1) {
1138 totem_config->interfaces[linknumber].member_list[member_count].nodeid = nodeid;
1139 totem_config->interfaces[linknumber].member_count++;
1140 }
1141 totem_config->interfaces[linknumber].configured = 1;
1142 free(node_addr_str);
1143 }
1144
1145 icmap_iter_finalize(iter2);
1146 }
1147
1148 icmap_iter_finalize(iter);
1149
1150 if (reload) {
1151 log_printf(LOGSYS_LEVEL_DEBUG, "About to reconfigure links from nodelist.\n");
1152 reconfigure_links(totem_config);
1153
1154 memcpy(new_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
1155
1156 compute_interfaces_diff(totem_config->orig_interfaces, new_interfaces);
1157
1158 free(new_interfaces);
1159 }
1160 }
1161
1162 static void nodelist_dynamic_notify(
1163 int32_t event,
1164 const char *key_name,
1165 struct icmap_notify_value new_val,
1166 struct icmap_notify_value old_val,
1167 void *user_data)
1168 {
1169 int res;
1170 unsigned int ring_no;
1171 unsigned int member_no;
1172 char tmp_str[ICMAP_KEYNAME_MAXLEN];
1173 uint8_t reloading;
1174 struct totem_config *totem_config = (struct totem_config *)user_data;
1175
1176 /*
1177 * If a full reload is in progress then don't do anything until it's done and
1178 * can reconfigure it all atomically
1179 */
1180 if (icmap_get_uint8("config.totemconfig_reload_in_progress", &reloading) == CS_OK && reloading) {
1181 return ;
1182 }
1183
1184 res = sscanf(key_name, "nodelist.node.%u.ring%u%s", &member_no, &ring_no, tmp_str);
1185 if (res != 3)
1186 return ;
1187
1188 if (strcmp(tmp_str, "_addr") != 0) {
1189 return;
1190 }
1191
1192 put_nodelist_members_to_config(totem_config, 1);
1193 }
1194
1195
1196
1197 static void config_convert_nodelist_to_interface(struct totem_config *totem_config)
1198 {
1199 int res = 0;
1200 int node_pos;
1201 char tmp_key[ICMAP_KEYNAME_MAXLEN];
1202 char tmp_key2[ICMAP_KEYNAME_MAXLEN];
1203 char *node_addr_str;
1204 unsigned int linknumber = 0;
1205 icmap_iter_t iter;
1206 const char *iter_key;
1207
1208 node_pos = find_local_node(1);
1209 if (node_pos > -1) {
1210 /*
1211 * We found node, so create interface section
1212 */
1213 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
1214 iter = icmap_iter_init(tmp_key);
1215 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1216 res = sscanf(iter_key, "nodelist.node.%u.ring%u%s", &node_pos, &linknumber, tmp_key2);
1217 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
1218 continue ;
1219 }
1220
1221 if (icmap_get_string(iter_key, &node_addr_str) != CS_OK) {
1222 continue;
1223 }
1224
1225 snprintf(tmp_key2, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", linknumber);
1226 icmap_set_string(tmp_key2, node_addr_str);
1227 free(node_addr_str);
1228 }
1229 icmap_iter_finalize(iter);
1230 }
1231 }
1232
1233 static int get_interface_params(struct totem_config *totem_config,
1234 const char **error_string, uint64_t *warnings,
1235 int reload)
1236 {
1237 int res = 0;
1238 unsigned int linknumber = 0;
1239 int member_count = 0;
1240 int i;
1241 icmap_iter_t iter, member_iter;
1242 const char *iter_key;
1243 const char *member_iter_key;
1244 char linknumber_key[ICMAP_KEYNAME_MAXLEN];
1245 char tmp_key[ICMAP_KEYNAME_MAXLEN];
1246 uint8_t u8;
1247 uint32_t u32;
1248 char *str;
1249 char *cluster_name = NULL;
1250
1251 if (reload) {
1252 for (i=0; i<INTERFACE_MAX; i++) {
1253 /*
1254 * Set back to defaults things that might have been configured and
1255 * now have been taken out of corosync.conf. These won't be caught by the
1256 * code below which only looks at interface{} sections that actually exist.
1257 */
1258 totem_config->interfaces[i].configured = 0;
1259 totem_config->interfaces[i].knet_ping_timeout = 0;
1260 totem_config->interfaces[i].knet_ping_interval = 0;
1261 totem_config->interfaces[i].knet_ping_precision = KNET_PING_PRECISION;
1262 totem_config->interfaces[i].knet_pong_count = KNET_PONG_COUNT;
1263 }
1264 }
1265 if (icmap_get_string("totem.cluster_name", &cluster_name) != CS_OK) {
1266 cluster_name = NULL;
1267 }
1268
1269 iter = icmap_iter_init("totem.interface.");
1270 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
1271 res = sscanf(iter_key, "totem.interface.%[^.].%s", linknumber_key, tmp_key);
1272 if (res != 2) {
1273 continue;
1274 }
1275
1276 if (strcmp(tmp_key, "bindnetaddr") != 0 && totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
1277 continue;
1278 }
1279
1280 member_count = 0;
1281 linknumber = atoi(linknumber_key);
1282
1283 if (linknumber >= INTERFACE_MAX) {
1284 free(cluster_name);
1285
1286 snprintf (error_string_response, sizeof(error_string_response),
1287 "parse error in config: interface ring number %u is bigger than allowed maximum %u\n",
1288 linknumber, INTERFACE_MAX - 1);
1289
1290 *error_string = error_string_response;
1291 return -1;
1292 }
1293
1294 /* These things are only valid for the initial read */
1295 if (!reload) {
1296 /*
1297 * Get the bind net address
1298 */
1299 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", linknumber);
1300
1301 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1302 res = totemip_parse (&totem_config->interfaces[linknumber].bindnet, str,
1303 totem_config->ip_version);
1304 free(str);
1305 }
1306
1307 /*
1308 * Get interface multicast address
1309 */
1310 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", linknumber);
1311 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1312 res = totemip_parse (&totem_config->interfaces[linknumber].mcast_addr, str, totem_config->ip_version);
1313 free(str);
1314 } else {
1315 /*
1316 * User not specified address -> autogenerate one from cluster_name key
1317 * (if available). Return code is intentionally ignored, because
1318 * udpu doesn't need mcastaddr and validity of mcastaddr for udp is
1319 * checked later anyway.
1320 */
1321 (void)get_cluster_mcast_addr (cluster_name,
1322 linknumber,
1323 totem_config->ip_version,
1324 &totem_config->interfaces[linknumber].mcast_addr);
1325 }
1326
1327 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", linknumber);
1328 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1329 if (strcmp (str, "yes") == 0) {
1330 totem_config->broadcast_use = 1;
1331 }
1332 free(str);
1333 }
1334 }
1335
1336 /* These things are only valid for the initial read OR a newly-defined link */
1337 if (!reload || (totem_config->interfaces[linknumber].configured == 0)) {
1338
1339 /*
1340 * Get mcast port
1341 */
1342 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", linknumber);
1343 if (icmap_get_uint16(tmp_key, &totem_config->interfaces[linknumber].ip_port) != CS_OK) {
1344 if (totem_config->broadcast_use) {
1345 totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + (2 * linknumber);
1346 } else {
1347 totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + linknumber;
1348 }
1349 }
1350
1351 /*
1352 * Get the TTL
1353 */
1354 totem_config->interfaces[linknumber].ttl = 1;
1355
1356 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", linknumber);
1357
1358 if (icmap_get_uint8(tmp_key, &u8) == CS_OK) {
1359 totem_config->interfaces[linknumber].ttl = u8;
1360 }
1361
1362 totem_config->interfaces[linknumber].knet_transport = KNET_DEFAULT_TRANSPORT;
1363 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_transport", linknumber);
1364 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1365 if (strcmp(str, "sctp") == 0) {
1366 totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_SCTP;
1367 }
1368 else if (strcmp(str, "udp") == 0) {
1369 totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_UDP;
1370 }
1371 else {
1372 *error_string = "Unrecognised knet_transport. expected 'udp' or 'sctp'";
1373 return -1;
1374 }
1375 }
1376 }
1377 totem_config->interfaces[linknumber].configured = 1;
1378
1379 /*
1380 * Get the knet link params
1381 */
1382 totem_config->interfaces[linknumber].knet_link_priority = 1;
1383 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_link_priority", linknumber);
1384
1385 if (icmap_get_uint8(tmp_key, &u8) == CS_OK) {
1386 totem_config->interfaces[linknumber].knet_link_priority = u8;
1387 }
1388
1389 totem_config->interfaces[linknumber].knet_ping_interval = 0; /* real default applied later */
1390 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_interval", linknumber);
1391 if (icmap_get_uint32(tmp_key, &u32) == CS_OK) {
1392 totem_config->interfaces[linknumber].knet_ping_interval = u32;
1393 }
1394 totem_config->interfaces[linknumber].knet_ping_timeout = 0; /* real default applied later */
1395 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_timeout", linknumber);
1396 if (icmap_get_uint32(tmp_key, &u32) == CS_OK) {
1397 totem_config->interfaces[linknumber].knet_ping_timeout = u32;
1398 }
1399 totem_config->interfaces[linknumber].knet_ping_precision = KNET_PING_PRECISION;
1400 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_ping_precision", linknumber);
1401 if (icmap_get_uint32(tmp_key, &u32) == CS_OK) {
1402 totem_config->interfaces[linknumber].knet_ping_precision = u32;
1403 }
1404 totem_config->interfaces[linknumber].knet_pong_count = KNET_PONG_COUNT;
1405 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_pong_count", linknumber);
1406 if (icmap_get_uint32(tmp_key, &u32) == CS_OK) {
1407 totem_config->interfaces[linknumber].knet_pong_count = u32;
1408 }
1409
1410 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.", linknumber);
1411 member_iter = icmap_iter_init(tmp_key);
1412 while ((member_iter_key = icmap_iter_next(member_iter, NULL, NULL)) != NULL) {
1413 if (member_count == 0) {
1414 if (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK) {
1415 free(str);
1416 *warnings |= TOTEM_CONFIG_WARNING_MEMBERS_IGNORED;
1417 break;
1418 } else {
1419 *warnings |= TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED;
1420 }
1421 }
1422
1423 if (icmap_get_string(member_iter_key, &str) == CS_OK) {
1424 res = totemip_parse (&totem_config->interfaces[linknumber].member_list[member_count++],
1425 str, totem_config->ip_version);
1426 }
1427 }
1428 icmap_iter_finalize(member_iter);
1429
1430 totem_config->interfaces[linknumber].member_count = member_count;
1431
1432 }
1433 icmap_iter_finalize(iter);
1434
1435 return 0;
1436 }
1437
1438 extern int totem_config_read (
1439 struct totem_config *totem_config,
1440 const char **error_string,
1441 uint64_t *warnings)
1442 {
1443 int res = 0;
1444 char *str, *ring0_addr_str;
1445 char tmp_key[ICMAP_KEYNAME_MAXLEN];
1446 uint16_t u16;
1447 int i;
1448 int local_node_pos;
1449 int nodeid_set;
1450
1451 *warnings = 0;
1452
1453 memset (totem_config, 0, sizeof (struct totem_config));
1454 totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
1455 if (totem_config->interfaces == 0) {
1456 *error_string = "Out of memory trying to allocate ethernet interface storage area";
1457 return -1;
1458 }
1459
1460 totem_config->transport_number = TOTEM_TRANSPORT_KNET;
1461 if (icmap_get_string("totem.transport", &str) == CS_OK) {
1462 if (strcmp (str, "udpu") == 0) {
1463 totem_config->transport_number = TOTEM_TRANSPORT_UDPU;
1464 }
1465
1466 if (strcmp (str, "udp") == 0) {
1467 totem_config->transport_number = TOTEM_TRANSPORT_UDP;
1468 }
1469
1470 if (strcmp (str, "knet") == 0) {
1471 totem_config->transport_number = TOTEM_TRANSPORT_KNET;
1472 }
1473
1474 free(str);
1475 }
1476
1477 memset (totem_config->interfaces, 0,
1478 sizeof (struct totem_interface) * INTERFACE_MAX);
1479
1480 strcpy (totem_config->link_mode, "passive");
1481
1482 icmap_get_uint32("totem.version", (uint32_t *)&totem_config->version);
1483
1484 if (totem_get_crypto(totem_config, error_string) != 0) {
1485 return -1;
1486 }
1487
1488 if (icmap_get_string("totem.link_mode", &str) == CS_OK) {
1489 if (strlen(str) >= TOTEM_LINK_MODE_BYTES) {
1490 *error_string = "totem.link_mode is too long";
1491 free(str);
1492
1493 return -1;
1494 }
1495 strcpy (totem_config->link_mode, str);
1496 free(str);
1497 }
1498
1499 icmap_get_uint32("totem.nodeid", &totem_config->node_id);
1500
1501 totem_config->clear_node_high_bit = 0;
1502 if (icmap_get_string("totem.clear_node_high_bit", &str) == CS_OK) {
1503 if (strcmp (str, "yes") == 0) {
1504 totem_config->clear_node_high_bit = 1;
1505 }
1506 free(str);
1507 }
1508
1509 icmap_get_uint32("totem.threads", &totem_config->threads);
1510
1511 icmap_get_uint32("totem.netmtu", &totem_config->net_mtu);
1512
1513 totem_config->ip_version = totem_config_get_ip_version(totem_config);
1514
1515 if (icmap_get_string("totem.interface.0.bindnetaddr", &str) != CS_OK) {
1516 /*
1517 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
1518 */
1519 config_convert_nodelist_to_interface(totem_config);
1520 } else {
1521 if (icmap_get_string("nodelist.node.0.ring0_addr", &ring0_addr_str) == CS_OK) {
1522 /*
1523 * Both bindnetaddr and ring0_addr are set.
1524 * Log warning information, and use nodelist instead
1525 */
1526 *warnings |= TOTEM_CONFIG_BINDNETADDR_NODELIST_SET;
1527
1528 config_convert_nodelist_to_interface(totem_config);
1529
1530 free(ring0_addr_str);
1531 }
1532
1533 free(str);
1534 }
1535
1536 /*
1537 * Broadcast option is global but set in interface section,
1538 * so reset before processing interfaces.
1539 */
1540 totem_config->broadcast_use = 0;
1541
1542 res = get_interface_params(totem_config, error_string, warnings, 0);
1543 if (res < 0) {
1544 return res;
1545 }
1546
1547 /*
1548 * Use broadcast is global, so if set, make sure to fill mcast addr correctly
1549 * broadcast is only supported for UDP so just do interface 0;
1550 */
1551 if (totem_config->broadcast_use) {
1552 totemip_parse (&totem_config->interfaces[0].mcast_addr,
1553 "255.255.255.255", 0);
1554 }
1555
1556
1557 /*
1558 * Store automatically generated items back to icmap only for UDP
1559 */
1560 if (totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
1561 for (i = 0; i < INTERFACE_MAX; i++) {
1562 if (!totem_config->interfaces[i].configured) {
1563 continue;
1564 }
1565 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", i);
1566 if (icmap_get_string(tmp_key, &str) == CS_OK) {
1567 free(str);
1568 } else {
1569 str = (char *)totemip_print(&totem_config->interfaces[i].mcast_addr);
1570 icmap_set_string(tmp_key, str);
1571 }
1572
1573 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", i);
1574 if (icmap_get_uint16(tmp_key, &u16) != CS_OK) {
1575 icmap_set_uint16(tmp_key, totem_config->interfaces[i].ip_port);
1576 }
1577 }
1578 }
1579
1580 /*
1581 * Check existence of nodelist
1582 */
1583 if ((icmap_get_string("nodelist.node.0.name", &str) == CS_OK) ||
1584 (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK)) {
1585 free(str);
1586 /*
1587 * find local node
1588 */
1589 local_node_pos = find_local_node(1);
1590 if (local_node_pos != -1) {
1591
1592 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", local_node_pos);
1593
1594 nodeid_set = (totem_config->node_id != 0);
1595 if (icmap_get_uint32(tmp_key, &totem_config->node_id) == CS_OK && nodeid_set) {
1596 *warnings |= TOTEM_CONFIG_WARNING_TOTEM_NODEID_IGNORED;
1597 }
1598 if ((totem_config->transport_number == TOTEM_TRANSPORT_KNET) && (!totem_config->node_id)) {
1599 *error_string = "With knet, you must specify nodeid for current node";
1600 return -1;
1601 }
1602
1603 /* Users must not change this */
1604 icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
1605 }
1606
1607 put_nodelist_members_to_config(totem_config, 0);
1608 }
1609
1610 /*
1611 * Get things that might change in the future (and can depend on totem_config->interfaces);
1612 */
1613 totem_volatile_config_read(totem_config, NULL);
1614
1615 calc_knet_ping_timers(totem_config);
1616
1617 icmap_set_uint8("config.totemconfig_reload_in_progress", 0);
1618
1619 add_totem_config_notification(totem_config);
1620
1621 return 0;
1622 }
1623
1624
1625 int totem_config_validate (
1626 struct totem_config *totem_config,
1627 const char **error_string)
1628 {
1629 static char local_error_reason[512];
1630 char parse_error[512];
1631 const char *error_reason = local_error_reason;
1632 int i,j;
1633 uint32_t u32;
1634 int num_configured = 0;
1635 unsigned int interface_max = INTERFACE_MAX;
1636
1637 for (i = 0; i < INTERFACE_MAX; i++) {
1638 if (totem_config->interfaces[i].configured) {
1639 num_configured++;
1640 }
1641 }
1642 if (num_configured == 0) {
1643 error_reason = "No interfaces defined";
1644 goto parse_error;
1645 }
1646
1647 /* Check we found a local node name */
1648 if (icmap_get_uint32("nodelist.local_node_pos", &u32) != CS_OK) {
1649 error_reason = "No valid name found for local host";
1650 goto parse_error;
1651 }
1652
1653 for (i = 0; i < INTERFACE_MAX; i++) {
1654 /*
1655 * Some error checking of parsed data to make sure its valid
1656 */
1657
1658 struct totem_ip_address null_addr;
1659
1660 if (!totem_config->interfaces[i].configured) {
1661 continue;
1662 }
1663
1664 memset (&null_addr, 0, sizeof (struct totem_ip_address));
1665
1666 if ((totem_config->transport_number == TOTEM_TRANSPORT_UDP) &&
1667 memcmp (&totem_config->interfaces[i].mcast_addr, &null_addr,
1668 sizeof (struct totem_ip_address)) == 0) {
1669 error_reason = "No multicast address specified";
1670 goto parse_error;
1671 }
1672
1673 if (totem_config->interfaces[i].ip_port == 0) {
1674 error_reason = "No multicast port specified";
1675 goto parse_error;
1676 }
1677
1678 if (totem_config->interfaces[i].ttl > 255) {
1679 error_reason = "Invalid TTL (should be 0..255)";
1680 goto parse_error;
1681 }
1682 if (totem_config->transport_number != TOTEM_TRANSPORT_UDP &&
1683 totem_config->interfaces[i].ttl != 1) {
1684 error_reason = "Can only set ttl on multicast transport types";
1685 goto parse_error;
1686 }
1687 if (totem_config->interfaces[i].knet_link_priority > 255) {
1688 error_reason = "Invalid link priority (should be 0..255)";
1689 goto parse_error;
1690 }
1691 if (totem_config->transport_number != TOTEM_TRANSPORT_KNET &&
1692 totem_config->interfaces[i].knet_link_priority != 1) {
1693 error_reason = "Can only set link priority on knet transport type";
1694 goto parse_error;
1695 }
1696
1697 if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 &&
1698 totem_config->node_id == 0) {
1699
1700 error_reason = "An IPV6 network requires that a node ID be specified.";
1701 goto parse_error;
1702 }
1703
1704 if (totem_config->broadcast_use == 0 && totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
1705 if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) {
1706 error_reason = "Multicast address family does not match bind address family";
1707 goto parse_error;
1708 }
1709
1710 if (totemip_is_mcast (&totem_config->interfaces[i].mcast_addr) != 0) {
1711 error_reason = "mcastaddr is not a correct multicast address.";
1712 goto parse_error;
1713 }
1714 }
1715 /* Verify that all nodes on the same knet link have the same IP family */
1716 for (j=1; j<totem_config->interfaces[i].member_count; j++) {
1717 if (totem_config->interfaces[i].configured) {
1718 if (totem_config->interfaces[i].member_list[j].family !=
1719 totem_config->interfaces[i].member_list[0].family) {
1720 snprintf (local_error_reason, sizeof(local_error_reason),
1721 "Nodes for link %d have different IP families", i);
1722 goto parse_error;
1723 }
1724 }
1725 }
1726 }
1727
1728 if (totem_config->version != 2) {
1729 error_reason = "This totem parser can only parse version 2 configurations.";
1730 goto parse_error;
1731 }
1732
1733 if (totem_volatile_config_validate(totem_config, error_string) == -1) {
1734 return (-1);
1735 }
1736
1737 if (check_for_duplicate_nodeids(totem_config, error_string) == -1) {
1738 return (-1);
1739 }
1740
1741 /*
1742 * KNET Link values validation
1743 */
1744 if (strcmp (totem_config->link_mode, "active") &&
1745 strcmp (totem_config->link_mode, "rr") &&
1746 strcmp (totem_config->link_mode, "passive")) {
1747 snprintf (local_error_reason, sizeof(local_error_reason),
1748 "The Knet link mode \"%s\" specified is invalid. It must be active, passive or rr.\n", totem_config->link_mode);
1749 goto parse_error;
1750 }
1751
1752 /* Only Knet does multiple interfaces */
1753 if (totem_config->transport_number != TOTEM_TRANSPORT_KNET) {
1754 interface_max = 1;
1755 }
1756
1757 if (interface_max < num_configured) {
1758 snprintf (parse_error, sizeof(parse_error),
1759 "%d is too many configured interfaces for non-Knet transport.",
1760 num_configured);
1761 error_reason = parse_error;
1762 goto parse_error;
1763 }
1764
1765 /* Only knet allows crypto */
1766 if (totem_config->transport_number != TOTEM_TRANSPORT_KNET) {
1767 if ((strcmp(totem_config->crypto_cipher_type, "none") != 0) ||
1768 (strcmp(totem_config->crypto_hash_type, "none") != 0)) {
1769
1770 snprintf (parse_error, sizeof(parse_error),
1771 "crypto_cipher & crypto_hash are only valid for the Knet transport.");
1772 error_reason = parse_error;
1773 goto parse_error;
1774 }
1775 }
1776
1777 if (totem_config->net_mtu == 0) {
1778 if (totem_config->transport_number == TOTEM_TRANSPORT_KNET) {
1779 totem_config->net_mtu = KNET_MAX_PACKET_SIZE;
1780 }
1781 else {
1782 totem_config->net_mtu = 1500;
1783 }
1784 }
1785
1786 return 0;
1787
1788 parse_error:
1789 snprintf (error_string_response, sizeof(error_string_response),
1790 "parse error in config: %s\n", error_reason);
1791 *error_string = error_string_response;
1792 return (-1);
1793
1794 }
1795
1796 static int read_keyfile (
1797 const char *key_location,
1798 struct totem_config *totem_config,
1799 const char **error_string)
1800 {
1801 int fd;
1802 int res;
1803 int saved_errno;
1804 char error_str[100];
1805 const char *error_ptr;
1806
1807 fd = open (key_location, O_RDONLY);
1808 if (fd == -1) {
1809 error_ptr = qb_strerror_r(errno, error_str, sizeof(error_str));
1810 snprintf (error_string_response, sizeof(error_string_response),
1811 "Could not open %s: %s\n",
1812 key_location, error_ptr);
1813 goto parse_error;
1814 }
1815
1816 res = read (fd, totem_config->private_key, TOTEM_PRIVATE_KEY_LEN_MAX);
1817 saved_errno = errno;
1818 close (fd);
1819
1820 if (res == -1) {
1821 error_ptr = qb_strerror_r (saved_errno, error_str, sizeof(error_str));
1822 snprintf (error_string_response, sizeof(error_string_response),
1823 "Could not read %s: %s\n",
1824 key_location, error_ptr);
1825 goto parse_error;
1826 }
1827
1828 if (res < TOTEM_PRIVATE_KEY_LEN_MIN) {
1829 snprintf (error_string_response, sizeof(error_string_response),
1830 "Could only read %d bits of minimum %u bits from %s.\n",
1831 res * 8, TOTEM_PRIVATE_KEY_LEN_MIN * 8, key_location);
1832 goto parse_error;
1833 }
1834
1835 totem_config->private_key_len = res;
1836
1837 return 0;
1838
1839 parse_error:
1840 *error_string = error_string_response;
1841 return (-1);
1842 }
1843
1844 int totem_config_keyread (
1845 struct totem_config *totem_config,
1846 const char **error_string)
1847 {
1848 int got_key = 0;
1849 char *key_location = NULL;
1850 int res;
1851 size_t key_len;
1852
1853 memset (totem_config->private_key, 0, sizeof(totem_config->private_key));
1854 totem_config->private_key_len = 0;
1855
1856 if (strcmp(totem_config->crypto_cipher_type, "none") == 0 &&
1857 strcmp(totem_config->crypto_hash_type, "none") == 0) {
1858 return (0);
1859 }
1860
1861 /* cmap may store the location of the key file */
1862 if (icmap_get_string("totem.keyfile", &key_location) == CS_OK) {
1863 res = read_keyfile(key_location, totem_config, error_string);
1864 free(key_location);
1865 if (res) {
1866 goto key_error;
1867 }
1868 got_key = 1;
1869 } else { /* Or the key itself may be in the cmap */
1870 if (icmap_get("totem.key", NULL, &key_len, NULL) == CS_OK) {
1871 if (key_len > sizeof(totem_config->private_key)) {
1872 sprintf(error_string_response, "key is too long");
1873 goto key_error;
1874 }
1875 if (key_len < TOTEM_PRIVATE_KEY_LEN_MIN) {
1876 sprintf(error_string_response, "key is too short");
1877 goto key_error;
1878 }
1879 if (icmap_get("totem.key", totem_config->private_key, &key_len, NULL) == CS_OK) {
1880 totem_config->private_key_len = key_len;
1881 got_key = 1;
1882 } else {
1883 sprintf(error_string_response, "can't load private key");
1884 goto key_error;
1885 }
1886 }
1887 }
1888
1889 /* In desperation we read the default filename */
1890 if (!got_key) {
1891 const char *filename = getenv("COROSYNC_TOTEM_AUTHKEY_FILE");
1892 if (!filename)
1893 filename = COROSYSCONFDIR "/authkey";
1894 res = read_keyfile(filename, totem_config, error_string);
1895 if (res)
1896 goto key_error;
1897
1898 }
1899
1900 return (0);
1901
1902 key_error:
1903 *error_string = error_string_response;
1904 return (-1);
1905
1906 }
1907
1908 static void debug_dump_totem_config(const struct totem_config *totem_config)
1909 {
1910
1911 log_printf(LOGSYS_LEVEL_DEBUG, "Token Timeout (%d ms) retransmit timeout (%d ms)",
1912 totem_config->token_timeout, totem_config->token_retransmit_timeout);
1913 log_printf(LOGSYS_LEVEL_DEBUG, "token hold (%d ms) retransmits before loss (%d retrans)",
1914 totem_config->token_hold_timeout, totem_config->token_retransmits_before_loss_const);
1915 log_printf(LOGSYS_LEVEL_DEBUG, "join (%d ms) send_join (%d ms) consensus (%d ms) merge (%d ms)",
1916 totem_config->join_timeout, totem_config->send_join_timeout, totem_config->consensus_timeout,
1917 totem_config->merge_timeout);
1918 log_printf(LOGSYS_LEVEL_DEBUG, "downcheck (%d ms) fail to recv const (%d msgs)",
1919 totem_config->downcheck_timeout, totem_config->fail_to_recv_const);
1920 log_printf(LOGSYS_LEVEL_DEBUG,
1921 "seqno unchanged const (%d rotations) Maximum network MTU %d",
1922 totem_config->seqno_unchanged_const, totem_config->net_mtu);
1923 log_printf(LOGSYS_LEVEL_DEBUG,
1924 "window size per rotation (%d messages) maximum messages per rotation (%d messages)",
1925 totem_config->window_size, totem_config->max_messages);
1926 log_printf(LOGSYS_LEVEL_DEBUG, "missed count const (%d messages)", totem_config->miss_count_const);
1927 log_printf(LOGSYS_LEVEL_DEBUG, "heartbeat_failures_allowed (%d)",
1928 totem_config->heartbeat_failures_allowed);
1929 log_printf(LOGSYS_LEVEL_DEBUG, "max_network_delay (%d ms)", totem_config->max_network_delay);
1930 }
1931
1932 static void totem_change_notify(
1933 int32_t event,
1934 const char *key_name,
1935 struct icmap_notify_value new_val,
1936 struct icmap_notify_value old_val,
1937 void *user_data)
1938 {
1939 struct totem_config *totem_config = (struct totem_config *)user_data;
1940 uint32_t *param;
1941 uint8_t reloading;
1942 const char *deleted_key = NULL;
1943 const char *error_string;
1944
1945 /*
1946 * If a full reload is in progress then don't do anything until it's done and
1947 * can reconfigure it all atomically
1948 */
1949 if (icmap_get_uint8("config.reload_in_progress", &reloading) == CS_OK && reloading)
1950 return;
1951
1952 param = totem_get_param_by_name((struct totem_config *)user_data, key_name);
1953 /*
1954 * Process change only if changed key is found in totem_config (-> param is not NULL)
1955 * or for special key token_coefficient. token_coefficient key is not stored in
1956 * totem_config, but it is used for computation of token timeout.
1957 */
1958 if (!param && strcmp(key_name, "totem.token_coefficient") != 0)
1959 return;
1960
1961 /*
1962 * Values other than UINT32 are not supported, or needed (yet)
1963 */
1964 switch (event) {
1965 case ICMAP_TRACK_DELETE:
1966 deleted_key = key_name;
1967 break;
1968 case ICMAP_TRACK_ADD:
1969 case ICMAP_TRACK_MODIFY:
1970 deleted_key = NULL;
1971 break;
1972 default:
1973 break;
1974 }
1975
1976 totem_volatile_config_read (totem_config, deleted_key);
1977 log_printf(LOGSYS_LEVEL_DEBUG, "Totem related config key changed. Dumping actual totem config.");
1978 debug_dump_totem_config(totem_config);
1979 if (totem_volatile_config_validate(totem_config, &error_string) == -1) {
1980 log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string);
1981 /*
1982 * TODO: Consider corosync exit and/or load defaults for volatile
1983 * values. For now, log error seems to be enough
1984 */
1985 }
1986 }
1987
1988 static void totem_reload_notify(
1989 int32_t event,
1990 const char *key_name,
1991 struct icmap_notify_value new_val,
1992 struct icmap_notify_value old_val,
1993 void *user_data)
1994 {
1995 struct totem_config *totem_config = (struct totem_config *)user_data;
1996 const char *error_string;
1997 uint64_t warnings;
1998
1999 /* Reload has completed */
2000 if (*(uint8_t *)new_val.data == 0) {
2001
2002 totem_config->orig_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
2003 assert(totem_config->orig_interfaces != NULL);
2004 memcpy(totem_config->orig_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
2005
2006 get_interface_params(totem_config, &error_string, &warnings, 1);
2007 put_nodelist_members_to_config (totem_config, 1);
2008 totem_volatile_config_read (totem_config, NULL);
2009
2010 calc_knet_ping_timers(totem_config);
2011
2012 log_printf(LOGSYS_LEVEL_DEBUG, "Configuration reloaded. Dumping actual totem config.");
2013 debug_dump_totem_config(totem_config);
2014 if (totem_volatile_config_validate(totem_config, &error_string) == -1) {
2015 log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string);
2016 /*
2017 * TODO: Consider corosync exit and/or load defaults for volatile
2018 * values. For now, log error seems to be enough
2019 */
2020 }
2021
2022 /* Reinstate the local_node_pos */
2023 (void)find_local_node(0);
2024
2025 /* Reconfigure network params as appropriate */
2026 totempg_reconfigure();
2027
2028 free(totem_config->orig_interfaces);
2029
2030 icmap_set_uint8("config.totemconfig_reload_in_progress", 0);
2031 } else {
2032 icmap_set_uint8("config.totemconfig_reload_in_progress", 1);
2033 }
2034 }
2035
2036 static void add_totem_config_notification(struct totem_config *totem_config)
2037 {
2038 icmap_track_t icmap_track;
2039
2040 icmap_track_add("totem.",
2041 ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY | ICMAP_TRACK_PREFIX,
2042 totem_change_notify,
2043 totem_config,
2044 &icmap_track);
2045
2046 icmap_track_add("config.reload_in_progress",
2047 ICMAP_TRACK_ADD | ICMAP_TRACK_MODIFY,
2048 totem_reload_notify,
2049 totem_config,
2050 &icmap_track);
2051
2052 icmap_track_add("nodelist.node.",
2053 ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY | ICMAP_TRACK_PREFIX,
2054 nodelist_dynamic_notify,
2055 (void *)totem_config,
2056 &icmap_track);
2057 }