2 * Copyright (c) 2002-2005 MontaVista Software, Inc.
3 * Copyright (c) 2006 RedHat, Inc.
7 * Author: Steven Dake (sdake@mvista.com)
9 * This software licensed under BSD license, the text of which follows:
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
14 * - Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * - Neither the name of the MontaVista Software, Inc. nor the names of its
20 * contributors may be used to endorse or promote products derived from this
21 * software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
41 #include <sys/socket.h>
42 #include <sys/types.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <sys/param.h>
53 #include "totemconfig.h"
56 #include "tlist.h" /* for HZ */
58 #define TOKEN_RETRANSMITS_BEFORE_LOSS_CONST 4
59 #define TOKEN_TIMEOUT 1000
60 #define TOKEN_RETRANSMIT_TIMEOUT (int)(TOKEN_TIMEOUT / (TOKEN_RETRANSMITS_BEFORE_LOSS_CONST + 0.2))
61 #define TOKEN_HOLD_TIMEOUT (int)(TOKEN_RETRANSMIT_TIMEOUT * 0.8 - (1000/(int)HZ))
62 #define JOIN_TIMEOUT 50
63 #define CONSENSUS_TIMEOUT 800
64 #define MERGE_TIMEOUT 200
65 #define DOWNCHECK_TIMEOUT 1000
66 #define FAIL_TO_RECV_CONST 50
67 #define SEQNO_UNCHANGED_CONST 30
68 #define MINIMUM_TIMEOUT (int)(1000/HZ)*3
69 #define MAX_NETWORK_DELAY 50
70 #define WINDOW_SIZE 50
71 #define MAX_MESSAGES 17
72 #define RRP_PROBLEM_COUNT_TIMEOUT 2000
73 #define RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT 10
74 #define RRP_PROBLEM_COUNT_THRESHOLD_MIN 5
76 static char error_string_response
[512];
78 /* These just makes the code below a little neater */
79 static inline int objdb_get_string (
80 struct objdb_iface_ver0
*objdb
, unsigned int object_service_handle
,
81 char *key
, char **value
)
86 if ( !(res
= objdb
->object_key_get (object_service_handle
,
97 static inline void objdb_get_int (
98 struct objdb_iface_ver0
*objdb
, unsigned int object_service_handle
,
99 char *key
, unsigned int *intvalue
)
103 if (!objdb
->object_key_get (object_service_handle
,
109 *intvalue
= atoi(value
);
115 extern int totem_config_read (
116 struct objdb_iface_ver0
*objdb
,
117 struct totem_config
*totem_config
,
121 unsigned int object_totem_handle
;
122 unsigned int object_interface_handle
;
124 unsigned int ringnumber
= 0;
126 memset (totem_config
, 0, sizeof (struct totem_config
));
127 totem_config
->interfaces
= malloc (sizeof (struct totem_interface
) * INTERFACE_MAX
);
128 if (totem_config
->interfaces
== 0) {
129 *error_string
= "Out of memory trying to allocate ethernet interface storage area";
133 memset (totem_config
->interfaces
, 0,
134 sizeof (struct totem_interface
) * INTERFACE_MAX
);
136 totem_config
->secauth
= 1;
138 strcpy (totem_config
->rrp_mode
, "none");
140 objdb
->object_find_reset (OBJECT_PARENT_HANDLE
);
142 if (objdb
->object_find (
143 OBJECT_PARENT_HANDLE
,
146 &object_totem_handle
) == 0 ||
148 OBJECT_PARENT_HANDLE
,
151 &object_totem_handle
) == 0) {
153 if (!objdb_get_string (objdb
,object_totem_handle
, "version", &str
)) {
154 if (strcmp (str
, "2") == 0) {
155 totem_config
->version
= 2;
158 if (!objdb_get_string (objdb
,object_totem_handle
, "secauth", &str
)) {
159 if (strcmp (str
, "on") == 0) {
160 totem_config
->secauth
= 1;
162 if (strcmp (str
, "off") == 0) {
163 totem_config
->secauth
= 0;
166 if (!objdb_get_string (objdb
, object_totem_handle
, "rrp_mode", &str
)) {
167 strcpy (totem_config
->rrp_mode
, str
);
171 * Get interface node id
173 objdb_get_int (objdb
, object_totem_handle
, "nodeid", &totem_config
->node_id
);
175 objdb_get_int (objdb
,object_totem_handle
, "threads", &totem_config
->threads
);
178 objdb_get_int (objdb
,object_totem_handle
, "netmtu", &totem_config
->net_mtu
);
180 objdb_get_int (objdb
,object_totem_handle
, "token", &totem_config
->token_timeout
);
182 objdb_get_int (objdb
,object_totem_handle
, "token_retransmit", &totem_config
->token_retransmit_timeout
);
184 objdb_get_int (objdb
,object_totem_handle
, "hold", &totem_config
->token_hold_timeout
);
186 objdb_get_int (objdb
,object_totem_handle
, "token_retransmits_before_loss_const", &totem_config
->token_retransmits_before_loss_const
);
188 objdb_get_int (objdb
,object_totem_handle
, "join", &totem_config
->join_timeout
);
189 objdb_get_int (objdb
,object_totem_handle
, "send_join", &totem_config
->send_join_timeout
);
191 objdb_get_int (objdb
,object_totem_handle
, "consensus", &totem_config
->consensus_timeout
);
193 objdb_get_int (objdb
,object_totem_handle
, "merge", &totem_config
->merge_timeout
);
195 objdb_get_int (objdb
,object_totem_handle
, "downcheck", &totem_config
->downcheck_timeout
);
197 objdb_get_int (objdb
,object_totem_handle
, "fail_recv_const", &totem_config
->fail_to_recv_const
);
199 objdb_get_int (objdb
,object_totem_handle
, "seqno_unchanged_const", &totem_config
->seqno_unchanged_const
);
201 objdb_get_int (objdb
,object_totem_handle
, "rrp_token_expired_timeout", &totem_config
->rrp_token_expired_timeout
);
203 objdb_get_int (objdb
,object_totem_handle
, "rrp_problem_count_timeout", &totem_config
->rrp_problem_count_timeout
);
205 objdb_get_int (objdb
,object_totem_handle
, "rrp_problem_count_threshold", &totem_config
->rrp_problem_count_threshold
);
207 objdb_get_int (objdb
,object_totem_handle
, "heartbeat_failures_allowed", &totem_config
->heartbeat_failures_allowed
);
209 objdb_get_int (objdb
,object_totem_handle
, "max_network_delay", &totem_config
->max_network_delay
);
211 objdb_get_int (objdb
,object_totem_handle
, "window_size", &totem_config
->window_size
);
212 objdb_get_string (objdb
, object_totem_handle
, "vsftype", &totem_config
->vsf_type
);
214 objdb_get_int (objdb
,object_totem_handle
, "max_messages", &totem_config
->max_messages
);
216 while (objdb
->object_find (
219 strlen ("interface"),
220 &object_interface_handle
) == 0) {
222 objdb_get_int (objdb
, object_interface_handle
, "ringnumber", &ringnumber
);
225 * Get interface multicast address
227 if (!objdb_get_string (objdb
, object_interface_handle
, "mcastaddr", &str
)) {
228 res
= totemip_parse (&totem_config
->interfaces
[ringnumber
].mcast_addr
, str
, 0);
234 if (!objdb_get_string (objdb
, object_interface_handle
, "mcastport", &str
)) {
235 totem_config
->interfaces
[ringnumber
].ip_port
= atoi (str
);
239 * Get the bind net address
241 if (!objdb_get_string (objdb
, object_interface_handle
, "bindnetaddr", &str
)) {
243 res
= totemip_parse (&totem_config
->interfaces
[ringnumber
].bindnet
, str
,
244 totem_config
->interfaces
[ringnumber
].mcast_addr
.family
);
246 totem_config
->interface_count
++;
254 int totem_config_validate (
255 struct totem_config
*totem_config
,
258 static char local_error_reason
[512];
259 char parse_error
[512];
260 char *error_reason
= local_error_reason
;
262 unsigned int interface_max
= INTERFACE_MAX
;
264 if (totem_config
->interface_count
== 0) {
265 error_reason
= "No interfaces defined";
269 for (i
= 0; i
< totem_config
->interface_count
; i
++) {
271 * Some error checking of parsed data to make sure its valid
273 if ((int *)&totem_config
->interfaces
[i
].mcast_addr
.addr
== 0) {
274 error_reason
= "No multicast address specified";
278 if (totem_config
->interfaces
[i
].ip_port
== 0) {
279 error_reason
= "No multicast port specified";
283 if (totem_config
->interfaces
[i
].mcast_addr
.family
== AF_INET6
&&
284 totem_config
->node_id
== 0) {
286 error_reason
= "An IPV6 network requires that a node ID be specified.";
290 if (totem_config
->interfaces
[i
].mcast_addr
.family
!= totem_config
->interfaces
[i
].bindnet
.family
) {
291 error_reason
= "Multicast address family does not match bind address family";
295 if (totem_config
->interfaces
[i
].mcast_addr
.family
!= totem_config
->interfaces
[i
].bindnet
.family
) {
296 error_reason
= "Not all bind address belong to the same IP family";
301 if (totem_config
->version
!= 2) {
302 error_reason
= "This totem parser can only parse version 2 configurations.";
307 if (totem_config
->token_retransmits_before_loss_const
== 0) {
308 totem_config
->token_retransmits_before_loss_const
=
309 TOKEN_RETRANSMITS_BEFORE_LOSS_CONST
;
313 * Setup timeout values that are not setup by user
315 if (totem_config
->token_timeout
== 0) {
316 totem_config
->token_timeout
= TOKEN_TIMEOUT
;
317 if (totem_config
->token_retransmits_before_loss_const
== 0) {
318 totem_config
->token_retransmits_before_loss_const
= TOKEN_RETRANSMITS_BEFORE_LOSS_CONST
;
321 if (totem_config
->token_retransmit_timeout
== 0) {
322 totem_config
->token_retransmit_timeout
=
323 (int)(totem_config
->token_timeout
/
324 (totem_config
->token_retransmits_before_loss_const
+ 0.2));
326 if (totem_config
->token_hold_timeout
== 0) {
327 totem_config
->token_hold_timeout
=
328 (int)(totem_config
->token_retransmit_timeout
* 0.8 -
333 if (totem_config
->max_network_delay
== 0) {
334 totem_config
->max_network_delay
= MAX_NETWORK_DELAY
;
337 if (totem_config
->max_network_delay
< MINIMUM_TIMEOUT
) {
338 sprintf (local_error_reason
, "The max_network_delay parameter (%d ms) may not be less then (%d ms).",
339 totem_config
->max_network_delay
, MINIMUM_TIMEOUT
);
343 if (totem_config
->window_size
== 0) {
344 totem_config
->window_size
= WINDOW_SIZE
;
347 if (totem_config
->max_messages
== 0) {
348 totem_config
->max_messages
= MAX_MESSAGES
;
351 if (totem_config
->token_timeout
< MINIMUM_TIMEOUT
) {
352 sprintf (local_error_reason
, "The token timeout parameter (%d ms) may not be less then (%d ms).",
353 totem_config
->token_timeout
, MINIMUM_TIMEOUT
);
357 if (totem_config
->token_retransmit_timeout
== 0) {
358 totem_config
->token_retransmit_timeout
=
359 (int)(totem_config
->token_timeout
/
360 (totem_config
->token_retransmits_before_loss_const
+ 0.2));
362 if (totem_config
->token_hold_timeout
== 0) {
363 totem_config
->token_hold_timeout
=
364 (int)(totem_config
->token_retransmit_timeout
* 0.8 -
367 if (totem_config
->token_retransmit_timeout
< MINIMUM_TIMEOUT
) {
368 sprintf (local_error_reason
, "The token retransmit timeout parameter (%d ms) may not be less then (%d ms).",
369 totem_config
->token_retransmit_timeout
, MINIMUM_TIMEOUT
);
373 if (totem_config
->token_hold_timeout
== 0) {
374 totem_config
->token_hold_timeout
= TOKEN_HOLD_TIMEOUT
;
377 if (totem_config
->token_hold_timeout
< MINIMUM_TIMEOUT
) {
378 sprintf (local_error_reason
, "The token hold timeout parameter (%d ms) may not be less then (%d ms).",
379 totem_config
->token_hold_timeout
, MINIMUM_TIMEOUT
);
383 if (totem_config
->join_timeout
== 0) {
384 totem_config
->join_timeout
= JOIN_TIMEOUT
;
387 if (totem_config
->join_timeout
< MINIMUM_TIMEOUT
) {
388 sprintf (local_error_reason
, "The join timeout parameter (%d ms) may not be less then (%d ms).",
389 totem_config
->join_timeout
, MINIMUM_TIMEOUT
);
393 if (totem_config
->consensus_timeout
== 0) {
394 totem_config
->consensus_timeout
= CONSENSUS_TIMEOUT
;
397 if (totem_config
->consensus_timeout
< MINIMUM_TIMEOUT
) {
398 sprintf (local_error_reason
, "The consensus timeout parameter (%d ms) may not be less then (%d ms).",
399 totem_config
->consensus_timeout
, MINIMUM_TIMEOUT
);
403 if (totem_config
->merge_timeout
== 0) {
404 totem_config
->merge_timeout
= MERGE_TIMEOUT
;
407 if (totem_config
->merge_timeout
< MINIMUM_TIMEOUT
) {
408 sprintf (local_error_reason
, "The merge timeout parameter (%d ms) may not be less then (%d ms).",
409 totem_config
->merge_timeout
, MINIMUM_TIMEOUT
);
413 if (totem_config
->downcheck_timeout
== 0) {
414 totem_config
->downcheck_timeout
= DOWNCHECK_TIMEOUT
;
417 if (totem_config
->downcheck_timeout
< MINIMUM_TIMEOUT
) {
418 sprintf (local_error_reason
, "The downcheck timeout parameter (%d ms) may not be less then (%d ms).",
419 totem_config
->downcheck_timeout
, MINIMUM_TIMEOUT
);
424 * RRP values validation
426 if (strcmp (totem_config
->rrp_mode
, "none") &&
427 strcmp (totem_config
->rrp_mode
, "active") &&
428 strcmp (totem_config
->rrp_mode
, "passive")) {
429 sprintf (local_error_reason
, "The RRP mode \"%s\" specified is invalid. It must be none, active, or passive.\n", totem_config
->rrp_mode
);
432 if (totem_config
->rrp_problem_count_timeout
== 0) {
433 totem_config
->rrp_problem_count_timeout
= RRP_PROBLEM_COUNT_TIMEOUT
;
435 if (totem_config
->rrp_problem_count_timeout
< MINIMUM_TIMEOUT
) {
436 sprintf (local_error_reason
, "The RRP problem count timeout parameter (%d ms) may not be less then (%d ms).",
437 totem_config
->rrp_problem_count_timeout
, MINIMUM_TIMEOUT
);
440 if (totem_config
->rrp_problem_count_threshold
== 0) {
441 totem_config
->rrp_problem_count_threshold
= RRP_PROBLEM_COUNT_THRESHOLD_DEFAULT
;
443 if (totem_config
->rrp_problem_count_threshold
< RRP_PROBLEM_COUNT_THRESHOLD_MIN
) {
444 sprintf (local_error_reason
, "The RRP problem count threshold (%d problem count) may not be less then (%d problem count).",
445 totem_config
->rrp_problem_count_threshold
, RRP_PROBLEM_COUNT_THRESHOLD_MIN
);
448 if (totem_config
->rrp_token_expired_timeout
== 0) {
449 totem_config
->rrp_token_expired_timeout
=
450 totem_config
->token_retransmit_timeout
;
453 if (totem_config
->rrp_token_expired_timeout
< MINIMUM_TIMEOUT
) {
454 sprintf (local_error_reason
, "The RRP token expired timeout parameter (%d ms) may not be less then (%d ms).",
455 totem_config
->rrp_token_expired_timeout
, MINIMUM_TIMEOUT
);
459 if (strcmp (totem_config
->rrp_mode
, "none") == 0) {
462 if (interface_max
< totem_config
->interface_count
) {
463 sprintf (parse_error
,
464 "%d is too many configured interfaces for the rrp_mode setting %s.",
465 totem_config
->interface_count
,
466 totem_config
->rrp_mode
);
467 error_reason
= parse_error
;
472 if (totem_config
->fail_to_recv_const
== 0) {
473 totem_config
->fail_to_recv_const
= FAIL_TO_RECV_CONST
;
475 if (totem_config
->seqno_unchanged_const
== 0) {
476 totem_config
->seqno_unchanged_const
= SEQNO_UNCHANGED_CONST
;
478 if (totem_config
->net_mtu
== 0) {
479 totem_config
->net_mtu
= 1500;
482 if ((MESSAGE_SIZE_MAX
/ totem_config
->net_mtu
) < totem_config
->max_messages
) {
483 sprintf (local_error_reason
, "The max_messages parameter (%d messages) may not be greater then (%d messages).",
484 totem_config
->max_messages
, MESSAGE_SIZE_MAX
/ totem_config
->net_mtu
);
488 if (totem_config
->threads
> SEND_THREADS_MAX
) {
489 totem_config
->threads
= SEND_THREADS_MAX
;
491 if (totem_config
->secauth
== 0) {
492 totem_config
->threads
= 0;
494 if (totem_config
->net_mtu
> FRAME_SIZE_MAX
) {
495 error_reason
= "This net_mtu parameter is greater then the maximum frame size";
498 if (totem_config
->vsf_type
== NULL
) {
499 totem_config
->vsf_type
= "none";
505 sprintf (error_string_response
,
506 "parse error in config: %s\n", error_reason
);
507 *error_string
= error_string_response
;
511 static int read_keyfile (
513 struct totem_config
*totem_config
,
519 fd
= open (key_location
, O_RDONLY
);
521 sprintf (error_string_response
, "Could not open %s: %s\n",
522 key_location
, strerror (errno
));
526 res
= read (fd
, totem_config
->private_key
, 128);
529 sprintf (error_string_response
, "Could not read %s: %s\n",
530 key_location
, strerror (errno
));
534 totem_config
->private_key_len
= 128;
538 sprintf (error_string_response
, "Could only read %d bits of 1024 bits from %s.\n",
539 res
* 8, key_location
);
545 *error_string
= error_string_response
;
549 int totem_config_keyread (
550 struct objdb_iface_ver0
*objdb
,
551 struct totem_config
*totem_config
,
555 char *key_location
= NULL
;
556 unsigned int object_service_handle
;
559 memset (totem_config
->private_key
, 0, 128);
560 totem_config
->private_key_len
= 128;
562 if (totem_config
->secauth
== 0) {
566 if (objdb
->object_find (
567 OBJECT_PARENT_HANDLE
,
570 &object_service_handle
) == 0 ||
572 OBJECT_PARENT_HANDLE
,
575 &object_service_handle
) == 0) {
577 /* objdb may store the location of the key file */
578 if (!objdb_get_string (objdb
,object_service_handle
, "keyfile", &key_location
)
580 res
= read_keyfile(key_location
, totem_config
, error_string
);
585 else { /* Or the key itself may be in the objdb */
588 res
= objdb
->object_key_get (object_service_handle
,
593 if (res
== 0 && key
) {
594 memcpy(totem_config
->private_key
, key
, key_len
);
595 totem_config
->private_key_len
= key_len
;
601 /* In desperation we read the default filename */
603 char *filename
= getenv("OPENAIS_TOTEM_AUTHKEY_FILE");
605 filename
= "/etc/ais/authkey";
606 res
= read_keyfile(filename
, totem_config
, error_string
);
614 *error_string
= error_string_response
;