]> git.proxmox.com Git - mirror_corosync.git/blob - exec/totemconfig.c
crypto: drop < 2.3 protocols and onwire compat
[mirror_corosync.git] / exec / totemconfig.c
1 /*
2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006-2012 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 <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <sys/param.h>
51
52 #include <corosync/swab.h>
53 #include <corosync/list.h>
54 #include <qb/qbdefs.h>
55 #include <corosync/totem/totem.h>
56 #include <corosync/config.h>
57 #include <corosync/logsys.h>
58 #include <corosync/icmap.h>
59
60 #include "util.h"
61 #include "totemconfig.h"
62
63 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
64 #define TOKEN_TIMEOUT 1000
65 #define JOIN_TIMEOUT 50
66 #define MERGE_TIMEOUT 200
67 #define DOWNCHECK_TIMEOUT 1000
68 #define FAIL_TO_RECV_CONST 2500
69 #define SEQNO_UNCHANGED_CONST 30
70 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3
71 #define MAX_NETWORK_DELAY 50
72 #define WINDOW_SIZE 50
73 #define MAX_MESSAGES 17
74 #define MISS_COUNT_CONST 5
75 #define RRP_PROBLEM_COUNT_TIMEOUT 2000
76 #define RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT 10
77 #define RRP_PROBLEM_COUNT_THRESHOLD_MIN 2
78 #define RRP_AUTORECOVERY_CHECK_TIMEOUT 1000
79
80 #define DEFAULT_PORT 5405
81
82 static char error_string_response[512];
83
84 static void add_totem_config_notification(struct totem_config *totem_config);
85
86 static void totem_volatile_config_read (struct totem_config *totem_config)
87 {
88 char *str;
89
90 icmap_get_uint32("totem.token", &totem_config->token_timeout);
91 icmap_get_uint32("totem.token_retransmit", &totem_config->token_retransmit_timeout);
92 icmap_get_uint32("totem.hold", &totem_config->token_hold_timeout);
93 icmap_get_uint32("totem.token_retransmits_before_loss_const", &totem_config->token_retransmits_before_loss_const);
94 icmap_get_uint32("totem.join", &totem_config->join_timeout);
95 icmap_get_uint32("totem.send_join", &totem_config->send_join_timeout);
96 icmap_get_uint32("totem.consensus", &totem_config->consensus_timeout);
97 icmap_get_uint32("totem.merge", &totem_config->merge_timeout);
98 icmap_get_uint32("totem.downcheck", &totem_config->downcheck_timeout);
99 icmap_get_uint32("totem.fail_recv_const", &totem_config->fail_to_recv_const);
100 icmap_get_uint32("totem.seqno_unchanged_const", &totem_config->seqno_unchanged_const);
101 icmap_get_uint32("totem.rrp_token_expired_timeout", &totem_config->rrp_token_expired_timeout);
102 icmap_get_uint32("totem.rrp_problem_count_timeout", &totem_config->rrp_problem_count_timeout);
103 icmap_get_uint32("totem.rrp_problem_count_threshold", &totem_config->rrp_problem_count_threshold);
104 icmap_get_uint32("totem.rrp_problem_count_mcast_threshold", &totem_config->rrp_problem_count_mcast_threshold);
105 icmap_get_uint32("totem.rrp_autorecovery_check_timeout", &totem_config->rrp_autorecovery_check_timeout);
106 icmap_get_uint32("totem.heartbeat_failures_allowed", &totem_config->heartbeat_failures_allowed);
107 icmap_get_uint32("totem.max_network_delay", &totem_config->max_network_delay);
108 icmap_get_uint32("totem.window_size", &totem_config->window_size);
109 icmap_get_uint32("totem.max_messages", &totem_config->max_messages);
110 icmap_get_uint32("totem.miss_count_const", &totem_config->miss_count_const);
111 if (icmap_get_string("totem.vsftype", &str) == CS_OK) {
112 totem_config->vsf_type = str;
113 }
114 }
115
116
117 static void totem_get_crypto(struct totem_config *totem_config)
118 {
119 char *str;
120 const char *tmp_cipher;
121 const char *tmp_hash;
122
123 tmp_hash = "sha1";
124 tmp_cipher = "aes256";
125
126 if (icmap_get_string("totem.secauth", &str) == CS_OK) {
127 if (strcmp (str, "off") == 0) {
128 tmp_hash = "none";
129 tmp_cipher = "none";
130 }
131 free(str);
132 }
133
134 if (icmap_get_string("totem.crypto_cipher", &str) == CS_OK) {
135 if (strcmp(str, "none") == 0) {
136 tmp_cipher = "none";
137 }
138 if (strcmp(str, "aes256") == 0) {
139 tmp_cipher = "aes256";
140 }
141 if (strcmp(str, "aes192") == 0) {
142 tmp_cipher = "aes192";
143 }
144 if (strcmp(str, "aes128") == 0) {
145 tmp_cipher = "aes128";
146 }
147 if (strcmp(str, "3des") == 0) {
148 tmp_cipher = "3des";
149 }
150 free(str);
151 }
152
153 if (icmap_get_string("totem.crypto_hash", &str) == CS_OK) {
154 if (strcmp(str, "none") == 0) {
155 tmp_hash = "none";
156 }
157 if (strcmp(str, "md5") == 0) {
158 tmp_hash = "md5";
159 }
160 if (strcmp(str, "sha1") == 0) {
161 tmp_hash = "sha1";
162 }
163 if (strcmp(str, "sha256") == 0) {
164 tmp_hash = "sha256";
165 }
166 if (strcmp(str, "sha384") == 0) {
167 tmp_hash = "sha384";
168 }
169 if (strcmp(str, "sha512") == 0) {
170 tmp_hash = "sha512";
171 }
172 free(str);
173 }
174
175 free(totem_config->crypto_cipher_type);
176 free(totem_config->crypto_hash_type);
177
178 totem_config->crypto_cipher_type = strdup(tmp_cipher);
179 totem_config->crypto_hash_type = strdup(tmp_hash);
180 }
181
182 static uint16_t generate_cluster_id (const char *cluster_name)
183 {
184 int i;
185 int value = 0;
186
187 for (i = 0; i < strlen(cluster_name); i++) {
188 value <<= 1;
189 value += cluster_name[i];
190 }
191
192 return (value & 0xFFFF);
193 }
194
195 static int get_cluster_mcast_addr (
196 const char *cluster_name,
197 const struct totem_ip_address *bindnet,
198 unsigned int ringnumber,
199 int ip_version,
200 struct totem_ip_address *res)
201 {
202 uint16_t clusterid;
203 char addr[INET6_ADDRSTRLEN + 1];
204 int err;
205
206 if (cluster_name == NULL) {
207 return (-1);
208 }
209
210 clusterid = generate_cluster_id(cluster_name) + ringnumber;
211 memset (res, 0, sizeof(res));
212
213 switch (bindnet->family) {
214 case AF_INET:
215 snprintf(addr, sizeof(addr), "239.192.%d.%d", clusterid >> 8, clusterid % 0xFF);
216 break;
217 case AF_INET6:
218 snprintf(addr, sizeof(addr), "ff15::%x", clusterid);
219 break;
220 default:
221 /*
222 * Unknown family
223 */
224 return (-1);
225 }
226
227 err = totemip_parse (res, addr, ip_version);
228
229 return (err);
230 }
231
232 static int find_local_node_in_nodelist(struct totem_config *totem_config)
233 {
234 icmap_iter_t iter;
235 const char *iter_key;
236 int res = 0;
237 int node_pos;
238 int local_node_pos = -1;
239 struct totem_ip_address bind_addr;
240 int interface_up, interface_num;
241 char tmp_key[ICMAP_KEYNAME_MAXLEN];
242 char *node_addr_str;
243 struct totem_ip_address node_addr;
244
245 res = totemip_iface_check(&totem_config->interfaces[0].bindnet,
246 &bind_addr, &interface_up, &interface_num,
247 totem_config->clear_node_high_bit);
248 if (res == -1) {
249 return (-1);
250 }
251
252 iter = icmap_iter_init("nodelist.node.");
253 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
254 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
255 if (res != 2) {
256 continue;
257 }
258
259 if (strcmp(tmp_key, "ring0_addr") != 0) {
260 continue;
261 }
262
263 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos);
264 if (icmap_get_string(tmp_key, &node_addr_str) != CS_OK) {
265 continue;
266 }
267
268 res = totemip_parse (&node_addr, node_addr_str, totem_config->ip_version);
269 free(node_addr_str);
270 if (res == -1) {
271 continue ;
272 }
273
274 if (totemip_equal(&bind_addr, &node_addr)) {
275 local_node_pos = node_pos;
276 }
277 }
278 icmap_iter_finalize(iter);
279
280 return (local_node_pos);
281 }
282
283 static void put_nodelist_members_to_config(struct totem_config *totem_config)
284 {
285 icmap_iter_t iter, iter2;
286 const char *iter_key, *iter_key2;
287 int res = 0;
288 int node_pos;
289 char tmp_key[ICMAP_KEYNAME_MAXLEN];
290 char tmp_key2[ICMAP_KEYNAME_MAXLEN];
291 char *node_addr_str;
292 int member_count;
293 unsigned int ringnumber = 0;
294
295 iter = icmap_iter_init("nodelist.node.");
296 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
297 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
298 if (res != 2) {
299 continue;
300 }
301
302 if (strcmp(tmp_key, "ring0_addr") != 0) {
303 continue;
304 }
305
306 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
307 iter2 = icmap_iter_init(tmp_key);
308 while ((iter_key2 = icmap_iter_next(iter2, NULL, NULL)) != NULL) {
309 res = sscanf(iter_key2, "nodelist.node.%u.ring%u%s", &node_pos, &ringnumber, tmp_key2);
310 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
311 continue;
312 }
313
314 if (icmap_get_string(iter_key2, &node_addr_str) != CS_OK) {
315 continue;
316 }
317
318 member_count = totem_config->interfaces[ringnumber].member_count;
319
320 res = totemip_parse(&totem_config->interfaces[ringnumber].member_list[member_count],
321 node_addr_str, totem_config->ip_version);
322 if (res != -1) {
323 totem_config->interfaces[ringnumber].member_count++;
324 }
325 free(node_addr_str);
326 }
327
328 icmap_iter_finalize(iter2);
329 }
330
331 icmap_iter_finalize(iter);
332 }
333
334 static void config_convert_nodelist_to_interface(struct totem_config *totem_config)
335 {
336 icmap_iter_t iter;
337 const char *iter_key;
338 int res = 0;
339 int node_pos;
340 char tmp_key[ICMAP_KEYNAME_MAXLEN];
341 char tmp_key2[ICMAP_KEYNAME_MAXLEN];
342 char *node_addr_str;
343 unsigned int ringnumber = 0;
344 struct list_head addrs;
345 struct list_head *list;
346 struct totem_ip_if_address *if_addr;
347 struct totem_ip_address node_addr;
348 int node_found;
349
350 if (totemip_getifaddrs(&addrs) == -1) {
351 return ;
352 }
353
354 iter = icmap_iter_init("nodelist.node.");
355 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
356 res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
357 if (res != 2) {
358 continue;
359 }
360
361 if (strcmp(tmp_key, "ring0_addr") != 0) {
362 continue;
363 }
364
365 if (icmap_get_string(iter_key, &node_addr_str) != CS_OK) {
366 continue ;
367 }
368
369 if (totemip_parse(&node_addr, node_addr_str, totem_config->ip_version) == -1) {
370 free(node_addr_str);
371 continue ;
372 }
373 free(node_addr_str);
374
375 /*
376 * Try to find node in if_addrs
377 */
378 node_found = 0;
379 for (list = addrs.next; list != &addrs; list = list->next) {
380 if_addr = list_entry(list, struct totem_ip_if_address, list);
381
382 if (totemip_equal(&node_addr, &if_addr->ip_addr)) {
383 node_found = 1;
384 break;
385 }
386 }
387
388 if (node_found) {
389 break ;
390 }
391 }
392
393 icmap_iter_finalize(iter);
394
395 if (node_found) {
396 /*
397 * We found node, so create interface section
398 */
399 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.", node_pos);
400 iter = icmap_iter_init(tmp_key);
401 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
402 res = sscanf(iter_key, "nodelist.node.%u.ring%u%s", &node_pos, &ringnumber, tmp_key2);
403 if (res != 3 || strcmp(tmp_key2, "_addr") != 0) {
404 continue ;
405 }
406
407 if (icmap_get_string(iter_key, &node_addr_str) != CS_OK) {
408 continue;
409 }
410
411 snprintf(tmp_key2, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.bindnetaddr", ringnumber);
412 icmap_set_string(tmp_key2, node_addr_str);
413 free(node_addr_str);
414 }
415 icmap_iter_finalize(iter);
416 }
417 }
418
419
420 extern int totem_config_read (
421 struct totem_config *totem_config,
422 const char **error_string,
423 uint64_t *warnings)
424 {
425 int res = 0;
426 char *str;
427 unsigned int ringnumber = 0;
428 int member_count = 0;
429 icmap_iter_t iter, member_iter;
430 const char *iter_key;
431 const char *member_iter_key;
432 char ringnumber_key[ICMAP_KEYNAME_MAXLEN];
433 char tmp_key[ICMAP_KEYNAME_MAXLEN];
434 uint8_t u8;
435 uint16_t u16;
436 char *cluster_name = NULL;
437 int i;
438 int local_node_pos;
439 int nodeid_set;
440
441 *warnings = 0;
442
443 memset (totem_config, 0, sizeof (struct totem_config));
444 totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
445 if (totem_config->interfaces == 0) {
446 *error_string = "Out of memory trying to allocate ethernet interface storage area";
447 return -1;
448 }
449
450 memset (totem_config->interfaces, 0,
451 sizeof (struct totem_interface) * INTERFACE_MAX);
452
453 strcpy (totem_config->rrp_mode, "none");
454
455 icmap_get_uint32("totem.version", (uint32_t *)&totem_config->version);
456
457 totem_get_crypto(totem_config);
458
459 if (icmap_get_string("totem.rrp_mode", &str) == CS_OK) {
460 strcpy (totem_config->rrp_mode, str);
461 free(str);
462 }
463
464 icmap_get_uint32("totem.nodeid", &totem_config->node_id);
465
466 totem_config->clear_node_high_bit = 0;
467 if (icmap_get_string("totem.clear_node_high_bit", &str) == CS_OK) {
468 if (strcmp (str, "yes") == 0) {
469 totem_config->clear_node_high_bit = 1;
470 }
471 free(str);
472 }
473
474 icmap_get_uint32("totem.threads", &totem_config->threads);
475
476 icmap_get_uint32("totem.netmtu", &totem_config->net_mtu);
477
478 icmap_get_string("totem.cluster_name", &cluster_name);
479
480 totem_config->ip_version = AF_INET;
481 if (icmap_get_string("totem.ip_version", &str) == CS_OK) {
482 if (strcmp(str, "ipv4") == 0) {
483 totem_config->ip_version = AF_INET;
484 }
485 if (strcmp(str, "ipv6") == 0) {
486 totem_config->ip_version = AF_INET6;
487 }
488 free(str);
489 }
490
491 /*
492 * Get things that might change in the future
493 */
494 totem_volatile_config_read(totem_config);
495
496 if (icmap_get_string("totem.interface.0.bindnetaddr", &str) != CS_OK) {
497 /*
498 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
499 */
500 config_convert_nodelist_to_interface(totem_config);
501 } else {
502 free(str);
503 }
504
505 iter = icmap_iter_init("totem.interface.");
506 while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
507 res = sscanf(iter_key, "totem.interface.%[^.].%s", ringnumber_key, tmp_key);
508 if (res != 2) {
509 continue;
510 }
511
512 if (strcmp(tmp_key, "bindnetaddr") != 0) {
513 continue;
514 }
515
516 member_count = 0;
517
518 ringnumber = atoi(ringnumber_key);
519
520 if (ringnumber >= INTERFACE_MAX) {
521 snprintf (error_string_response, sizeof(error_string_response),
522 "parse error in config: interface ring number %u is bigger then allowed maximum %u\n",
523 ringnumber, INTERFACE_MAX - 1);
524
525 *error_string = error_string_response;
526 return -1;
527 }
528
529 /*
530 * Get the bind net address
531 */
532 if (icmap_get_string(iter_key, &str) == CS_OK) {
533 res = totemip_parse (&totem_config->interfaces[ringnumber].bindnet, str,
534 totem_config->interfaces[ringnumber].mcast_addr.family);
535 free(str);
536 }
537
538 /*
539 * Get interface multicast address
540 */
541 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", ringnumber);
542 if (icmap_get_string(tmp_key, &str) == CS_OK) {
543 res = totemip_parse (&totem_config->interfaces[ringnumber].mcast_addr, str, totem_config->ip_version);
544 free(str);
545 } else {
546 /*
547 * User not specified address -> autogenerate one from cluster_name key
548 * (if available)
549 */
550 res = get_cluster_mcast_addr (cluster_name,
551 &totem_config->interfaces[ringnumber].bindnet,
552 ringnumber,
553 totem_config->ip_version,
554 &totem_config->interfaces[ringnumber].mcast_addr);
555 }
556
557 totem_config->broadcast_use = 0;
558 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", ringnumber);
559 if (icmap_get_string(tmp_key, &str) == CS_OK) {
560 if (strcmp (str, "yes") == 0) {
561 totem_config->broadcast_use = 1;
562 totemip_parse (
563 &totem_config->interfaces[ringnumber].mcast_addr,
564 "255.255.255.255", totem_config->ip_version);
565 }
566 free(str);
567 }
568
569 /*
570 * Get mcast port
571 */
572 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", ringnumber);
573 if (icmap_get_uint16(tmp_key, &totem_config->interfaces[ringnumber].ip_port) != CS_OK) {
574 if (totem_config->broadcast_use) {
575 totem_config->interfaces[ringnumber].ip_port = DEFAULT_PORT + (2 * ringnumber);
576 } else {
577 totem_config->interfaces[ringnumber].ip_port = DEFAULT_PORT;
578 }
579 }
580
581 /*
582 * Get the TTL
583 */
584 totem_config->interfaces[ringnumber].ttl = 1;
585
586 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", ringnumber);
587
588 if (icmap_get_uint8(tmp_key, &u8) == CS_OK) {
589 totem_config->interfaces[ringnumber].ttl = u8;
590 }
591
592 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.", ringnumber);
593 member_iter = icmap_iter_init(tmp_key);
594 while ((member_iter_key = icmap_iter_next(member_iter, NULL, NULL)) != NULL) {
595 if (member_count == 0) {
596 if (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK) {
597 free(str);
598 *warnings |= TOTEM_CONFIG_WARNING_MEMBERS_IGNORED;
599 break;
600 } else {
601 *warnings |= TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED;
602 }
603 }
604
605 if (icmap_get_string(member_iter_key, &str) == CS_OK) {
606 res = totemip_parse (&totem_config->interfaces[ringnumber].member_list[member_count++],
607 str, totem_config->ip_version);
608 }
609 }
610 icmap_iter_finalize(member_iter);
611
612 totem_config->interfaces[ringnumber].member_count = member_count;
613 totem_config->interface_count++;
614 }
615 icmap_iter_finalize(iter);
616
617 /*
618 * Store automatically generated items back to icmap
619 */
620 for (i = 0; i < totem_config->interface_count; i++) {
621 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", i);
622 if (icmap_get_string(tmp_key, &str) == CS_OK) {
623 free(str);
624 } else {
625 str = (char *)totemip_print(&totem_config->interfaces[i].mcast_addr);
626 icmap_set_string(tmp_key, str);
627 }
628
629 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", i);
630 if (icmap_get_uint16(tmp_key, &u16) != CS_OK) {
631 icmap_set_uint16(tmp_key, totem_config->interfaces[i].ip_port);
632 }
633 }
634
635 totem_config->transport_number = TOTEM_TRANSPORT_UDP;
636 if (icmap_get_string("totem.transport", &str) == CS_OK) {
637 if (strcmp (str, "udpu") == 0) {
638 totem_config->transport_number = TOTEM_TRANSPORT_UDPU;
639 }
640
641 if (strcmp (str, "iba") == 0) {
642 totem_config->transport_number = TOTEM_TRANSPORT_RDMA;
643 }
644 free(str);
645 }
646
647 free(cluster_name);
648
649 /*
650 * Check existence of nodelist
651 */
652 if (icmap_get_string("nodelist.node.0.ring0_addr", &str) == CS_OK) {
653 free(str);
654 /*
655 * find local node
656 */
657 local_node_pos = find_local_node_in_nodelist(totem_config);
658 if (local_node_pos != -1) {
659 icmap_set_uint32("nodelist.local_node_pos", local_node_pos);
660
661 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", local_node_pos);
662
663 nodeid_set = (totem_config->node_id != 0);
664 if (icmap_get_uint32(tmp_key, &totem_config->node_id) == CS_OK && nodeid_set) {
665 *warnings |= TOTEM_CONFIG_WARNING_TOTEM_NODEID_IGNORED;
666 }
667
668 /*
669 * Make localnode ring0_addr read only, so we can be sure that local
670 * node never changes. If rebinding to other IP would be in future
671 * supported, this must be changed and handled properly!
672 */
673 snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", local_node_pos);
674 icmap_set_ro_access(tmp_key, 0, 1);
675 icmap_set_ro_access("nodelist.local_node_pos", 0, 1);
676 }
677
678 put_nodelist_members_to_config(totem_config);
679 }
680
681 add_totem_config_notification(totem_config);
682
683 return 0;
684 }
685
686 int totem_config_validate (
687 struct totem_config *totem_config,
688 const char **error_string)
689 {
690 static char local_error_reason[512];
691 char parse_error[512];
692 const char *error_reason = local_error_reason;
693 int i;
694 unsigned int interface_max = INTERFACE_MAX;
695
696 if (totem_config->interface_count == 0) {
697 error_reason = "No interfaces defined";
698 goto parse_error;
699 }
700
701 for (i = 0; i < totem_config->interface_count; i++) {
702 /*
703 * Some error checking of parsed data to make sure its valid
704 */
705
706 struct totem_ip_address null_addr;
707 memset (&null_addr, 0, sizeof (struct totem_ip_address));
708
709 if ((totem_config->transport_number == 0) &&
710 memcmp (&totem_config->interfaces[i].mcast_addr, &null_addr,
711 sizeof (struct totem_ip_address)) == 0) {
712 error_reason = "No multicast address specified";
713 goto parse_error;
714 }
715
716 if (totem_config->interfaces[i].ip_port == 0) {
717 error_reason = "No multicast port specified";
718 goto parse_error;
719 }
720
721 if (totem_config->interfaces[i].ttl > 255) {
722 error_reason = "Invalid TTL (should be 0..255)";
723 goto parse_error;
724 }
725 if (totem_config->transport_number != TOTEM_TRANSPORT_UDP &&
726 totem_config->interfaces[i].ttl != 1) {
727 error_reason = "Can only set ttl on multicast transport types";
728 goto parse_error;
729 }
730
731 if (totem_config->interfaces[i].mcast_addr.family == AF_INET6 &&
732 totem_config->node_id == 0) {
733
734 error_reason = "An IPV6 network requires that a node ID be specified.";
735 goto parse_error;
736 }
737
738 if (totem_config->broadcast_use == 0 && totem_config->transport_number == 0) {
739 if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) {
740 error_reason = "Multicast address family does not match bind address family";
741 goto parse_error;
742 }
743
744 if (totem_config->interfaces[i].mcast_addr.family != totem_config->interfaces[i].bindnet.family) {
745 error_reason = "Not all bind address belong to the same IP family";
746 goto parse_error;
747 }
748 if (totemip_is_mcast (&totem_config->interfaces[i].mcast_addr) != 0) {
749 error_reason = "mcastaddr is not a correct multicast address.";
750 goto parse_error;
751 }
752 }
753 }
754
755 if (totem_config->version != 2) {
756 error_reason = "This totem parser can only parse version 2 configurations.";
757 goto parse_error;
758 }
759
760
761 if (totem_config->token_retransmits_before_loss_const == 0) {
762 totem_config->token_retransmits_before_loss_const =
763 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST;
764 }
765
766 /*
767 * Setup timeout values that are not setup by user
768 */
769 if (totem_config->token_timeout == 0) {
770 totem_config->token_timeout = TOKEN_TIMEOUT;
771 }
772
773 if (totem_config->max_network_delay == 0) {
774 totem_config->max_network_delay = MAX_NETWORK_DELAY;
775 }
776
777 if (totem_config->max_network_delay < MINIMUM_TIMEOUT) {
778 snprintf (local_error_reason, sizeof(local_error_reason),
779 "The max_network_delay parameter (%d ms) may not be less then (%d ms).",
780 totem_config->max_network_delay, MINIMUM_TIMEOUT);
781 goto parse_error;
782 }
783
784 if (totem_config->window_size == 0) {
785 totem_config->window_size = WINDOW_SIZE;
786 }
787
788 if (totem_config->max_messages == 0) {
789 totem_config->max_messages = MAX_MESSAGES;
790 }
791
792 if (totem_config->miss_count_const == 0) {
793 totem_config->miss_count_const = MISS_COUNT_CONST;
794 }
795
796 if (totem_config->token_timeout < MINIMUM_TIMEOUT) {
797 snprintf (local_error_reason, sizeof(local_error_reason),
798 "The token timeout parameter (%d ms) may not be less then (%d ms).",
799 totem_config->token_timeout, MINIMUM_TIMEOUT);
800 goto parse_error;
801 }
802
803 if (totem_config->token_retransmit_timeout == 0) {
804 totem_config->token_retransmit_timeout =
805 (int)(totem_config->token_timeout /
806 (totem_config->token_retransmits_before_loss_const + 0.2));
807 }
808 if (totem_config->token_hold_timeout == 0) {
809 totem_config->token_hold_timeout =
810 (int)(totem_config->token_retransmit_timeout * 0.8 -
811 (1000/HZ));
812 }
813 if (totem_config->token_retransmit_timeout < MINIMUM_TIMEOUT) {
814 snprintf (local_error_reason, sizeof(local_error_reason),
815 "The token retransmit timeout parameter (%d ms) may not be less then (%d ms).",
816 totem_config->token_retransmit_timeout, MINIMUM_TIMEOUT);
817 goto parse_error;
818 }
819
820 if (totem_config->token_hold_timeout < MINIMUM_TIMEOUT) {
821 snprintf (local_error_reason, sizeof(local_error_reason),
822 "The token hold timeout parameter (%d ms) may not be less then (%d ms).",
823 totem_config->token_hold_timeout, MINIMUM_TIMEOUT);
824 goto parse_error;
825 }
826
827 if (totem_config->join_timeout == 0) {
828 totem_config->join_timeout = JOIN_TIMEOUT;
829 }
830
831 if (totem_config->join_timeout < MINIMUM_TIMEOUT) {
832 snprintf (local_error_reason, sizeof(local_error_reason),
833 "The join timeout parameter (%d ms) may not be less then (%d ms).",
834 totem_config->join_timeout, MINIMUM_TIMEOUT);
835 goto parse_error;
836 }
837
838 if (totem_config->consensus_timeout == 0) {
839 totem_config->consensus_timeout = (int)(float)(1.2 * totem_config->token_timeout);
840 }
841
842 if (totem_config->consensus_timeout < MINIMUM_TIMEOUT) {
843 snprintf (local_error_reason, sizeof(local_error_reason),
844 "The consensus timeout parameter (%d ms) may not be less then (%d ms).",
845 totem_config->consensus_timeout, MINIMUM_TIMEOUT);
846 goto parse_error;
847 }
848
849 if (totem_config->merge_timeout == 0) {
850 totem_config->merge_timeout = MERGE_TIMEOUT;
851 }
852
853 if (totem_config->merge_timeout < MINIMUM_TIMEOUT) {
854 snprintf (local_error_reason, sizeof(local_error_reason),
855 "The merge timeout parameter (%d ms) may not be less then (%d ms).",
856 totem_config->merge_timeout, MINIMUM_TIMEOUT);
857 goto parse_error;
858 }
859
860 if (totem_config->downcheck_timeout == 0) {
861 totem_config->downcheck_timeout = DOWNCHECK_TIMEOUT;
862 }
863
864 if (totem_config->downcheck_timeout < MINIMUM_TIMEOUT) {
865 snprintf (local_error_reason, sizeof(local_error_reason),
866 "The downcheck timeout parameter (%d ms) may not be less then (%d ms).",
867 totem_config->downcheck_timeout, MINIMUM_TIMEOUT);
868 goto parse_error;
869 }
870
871 /*
872 * RRP values validation
873 */
874 if (strcmp (totem_config->rrp_mode, "none") &&
875 strcmp (totem_config->rrp_mode, "active") &&
876 strcmp (totem_config->rrp_mode, "passive")) {
877 snprintf (local_error_reason, sizeof(local_error_reason),
878 "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config->rrp_mode);
879 goto parse_error;
880 }
881 if (totem_config->rrp_problem_count_timeout == 0) {
882 totem_config->rrp_problem_count_timeout = RRP_PROBLEM_COUNT_TIMEOUT;
883 }
884 if (totem_config->rrp_problem_count_timeout < MINIMUM_TIMEOUT) {
885 snprintf (local_error_reason, sizeof(local_error_reason),
886 "The RRP problem count timeout parameter (%d ms) may not be less then (%d ms).",
887 totem_config->rrp_problem_count_timeout, MINIMUM_TIMEOUT);
888 goto parse_error;
889 }
890 if (totem_config->rrp_problem_count_threshold == 0) {
891 totem_config->rrp_problem_count_threshold = RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT;
892 }
893 if (totem_config->rrp_problem_count_mcast_threshold == 0) {
894 totem_config->rrp_problem_count_mcast_threshold = totem_config->rrp_problem_count_threshold * 10;
895 }
896 if (totem_config->rrp_problem_count_threshold < RRP_PROBLEM_COUNT_THRESHOLD_MIN) {
897 snprintf (local_error_reason, sizeof(local_error_reason),
898 "The RRP problem count threshold (%d problem count) may not be less then (%d problem count).",
899 totem_config->rrp_problem_count_threshold, RRP_PROBLEM_COUNT_THRESHOLD_MIN);
900 goto parse_error;
901 }
902 if (totem_config->rrp_problem_count_mcast_threshold < RRP_PROBLEM_COUNT_THRESHOLD_MIN) {
903 snprintf (local_error_reason, sizeof(local_error_reason),
904 "The RRP multicast problem count threshold (%d problem count) may not be less then (%d problem count).",
905 totem_config->rrp_problem_count_mcast_threshold, RRP_PROBLEM_COUNT_THRESHOLD_MIN);
906 goto parse_error;
907 }
908 if (totem_config->rrp_token_expired_timeout == 0) {
909 totem_config->rrp_token_expired_timeout =
910 totem_config->token_retransmit_timeout;
911 }
912
913 if (totem_config->rrp_token_expired_timeout < MINIMUM_TIMEOUT) {
914 snprintf (local_error_reason, sizeof(local_error_reason),
915 "The RRP token expired timeout parameter (%d ms) may not be less then (%d ms).",
916 totem_config->rrp_token_expired_timeout, MINIMUM_TIMEOUT);
917 goto parse_error;
918 }
919
920 if (totem_config->rrp_autorecovery_check_timeout == 0) {
921 totem_config->rrp_autorecovery_check_timeout = RRP_AUTORECOVERY_CHECK_TIMEOUT;
922 }
923
924 if (strcmp (totem_config->rrp_mode, "none") == 0) {
925 interface_max = 1;
926 }
927 if (interface_max < totem_config->interface_count) {
928 snprintf (parse_error, sizeof(parse_error),
929 "%d is too many configured interfaces for the rrp_mode setting %s.",
930 totem_config->interface_count,
931 totem_config->rrp_mode);
932 error_reason = parse_error;
933 goto parse_error;
934 }
935
936
937 if (totem_config->fail_to_recv_const == 0) {
938 totem_config->fail_to_recv_const = FAIL_TO_RECV_CONST;
939 }
940 if (totem_config->seqno_unchanged_const == 0) {
941 totem_config->seqno_unchanged_const = SEQNO_UNCHANGED_CONST;
942 }
943 if (totem_config->net_mtu == 0) {
944 totem_config->net_mtu = 1500;
945 }
946
947 if ((MESSAGE_QUEUE_MAX) < totem_config->max_messages) {
948 snprintf (local_error_reason, sizeof(local_error_reason),
949 "The max_messages parameter (%d messages) may not be greater then (%d messages).",
950 totem_config->max_messages, MESSAGE_QUEUE_MAX);
951 goto parse_error;
952 }
953
954 if (totem_config->threads > SEND_THREADS_MAX) {
955 totem_config->threads = SEND_THREADS_MAX;
956 }
957 if (totem_config->net_mtu > FRAME_SIZE_MAX) {
958 error_reason = "This net_mtu parameter is greater then the maximum frame size";
959 goto parse_error;
960 }
961 if (totem_config->vsf_type == NULL) {
962 totem_config->vsf_type = "none";
963 }
964
965 return (0);
966
967 parse_error:
968 snprintf (error_string_response, sizeof(error_string_response),
969 "parse error in config: %s\n", error_reason);
970 *error_string = error_string_response;
971 return (-1);
972 }
973
974 static int read_keyfile (
975 const char *key_location,
976 struct totem_config *totem_config,
977 const char **error_string)
978 {
979 int fd;
980 int res;
981 ssize_t expected_key_len = sizeof (totem_config->private_key);
982 int saved_errno;
983 char error_str[100];
984 const char *error_ptr;
985
986 fd = open (key_location, O_RDONLY);
987 if (fd == -1) {
988 error_ptr = qb_strerror_r(errno, error_str, sizeof(error_str));
989 snprintf (error_string_response, sizeof(error_string_response),
990 "Could not open %s: %s\n",
991 key_location, error_ptr);
992 goto parse_error;
993 }
994
995 res = read (fd, totem_config->private_key, expected_key_len);
996 saved_errno = errno;
997 close (fd);
998
999 if (res == -1) {
1000 error_ptr = qb_strerror_r (saved_errno, error_str, sizeof(error_str));
1001 snprintf (error_string_response, sizeof(error_string_response),
1002 "Could not read %s: %s\n",
1003 key_location, error_ptr);
1004 goto parse_error;
1005 }
1006
1007 totem_config->private_key_len = expected_key_len;
1008
1009 if (res != expected_key_len) {
1010 snprintf (error_string_response, sizeof(error_string_response),
1011 "Could only read %d bits of 1024 bits from %s.\n",
1012 res * 8, key_location);
1013 goto parse_error;
1014 }
1015
1016 return 0;
1017
1018 parse_error:
1019 *error_string = error_string_response;
1020 return (-1);
1021 }
1022
1023 int totem_config_keyread (
1024 struct totem_config *totem_config,
1025 const char **error_string)
1026 {
1027 int got_key = 0;
1028 char *key_location = NULL;
1029 int res;
1030 size_t key_len;
1031
1032 memset (totem_config->private_key, 0, 128);
1033 totem_config->private_key_len = 128;
1034
1035 if (strcmp(totem_config->crypto_cipher_type, "none") == 0 &&
1036 strcmp(totem_config->crypto_hash_type, "none") == 0) {
1037 return (0);
1038 }
1039
1040 /* cmap may store the location of the key file */
1041 if (icmap_get_string("totem.keyfile", &key_location) == CS_OK) {
1042 res = read_keyfile(key_location, totem_config, error_string);
1043 free(key_location);
1044 if (res) {
1045 goto key_error;
1046 }
1047 got_key = 1;
1048 } else { /* Or the key itself may be in the cmap */
1049 if (icmap_get("totem.key", NULL, &key_len, NULL) == CS_OK) {
1050 if (key_len > sizeof (totem_config->private_key)) {
1051 sprintf(error_string_response, "key is too long");
1052 goto key_error;
1053 }
1054 if (icmap_get("totem.key", totem_config->private_key, &key_len, NULL) == CS_OK) {
1055 totem_config->private_key_len = key_len;
1056 got_key = 1;
1057 } else {
1058 sprintf(error_string_response, "can't store private key");
1059 goto key_error;
1060 }
1061 }
1062 }
1063
1064 /* In desperation we read the default filename */
1065 if (!got_key) {
1066 const char *filename = getenv("COROSYNC_TOTEM_AUTHKEY_FILE");
1067 if (!filename)
1068 filename = COROSYSCONFDIR "/authkey";
1069 res = read_keyfile(filename, totem_config, error_string);
1070 if (res)
1071 goto key_error;
1072
1073 }
1074
1075 return (0);
1076
1077 key_error:
1078 *error_string = error_string_response;
1079 return (-1);
1080
1081 }
1082
1083 static void totem_change_notify(
1084 int32_t event,
1085 const char *key_name,
1086 struct icmap_notify_value new_val,
1087 struct icmap_notify_value old_val,
1088 void *user_data)
1089 {
1090 totem_volatile_config_read((struct totem_config *)user_data);
1091 }
1092
1093 static void add_totem_config_notification(struct totem_config *totem_config)
1094 {
1095 icmap_track_t icmap_track;
1096
1097 icmap_track_add("totem.",
1098 ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY | ICMAP_TRACK_PREFIX,
1099 totem_change_notify,
1100 totem_config,
1101 &icmap_track);
1102 }