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