2 * Copyright (c) 2002-2006 MontaVista Software, Inc.
3 * Copyright (c) 2006 Red Hat, Inc.
4 * Copyright (c) 2006 Sun Microsystems, Inc.
8 * Author: Steven Dake (sdake@mvista.com)
10 * This software licensed under BSD license, the text of which follows:
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * - Neither the name of the MontaVista Software, Inc. nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/types.h>
44 #include <sys/socket.h>
47 #include <sys/resource.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
60 #include "../include/saAis.h"
61 #include "../include/list.h"
62 #include "../include/queue.h"
63 #include "../lcr/lcr_ifact.h"
68 #include "mainconfig.h"
69 #include "totemconfig.h"
85 LOGSYS_DECLARE_SYSTEM ("openais",
86 LOG_MODE_OUTPUT_STDERR
| LOG_MODE_OUTPUT_SYSLOG_THREADED
| LOG_MODE_DISPLAY_DEBUG
| LOG_MODE_BUFFER_BEFORE_CONFIG
,
90 LOGSYS_DECLARE_SUBSYS ("MAIN", LOG_INFO
);
92 #define SERVER_BACKLOG 5
94 static int ais_uid
= 0;
96 static int gid_valid
= 0;
98 static unsigned int service_count
= 32;
100 static pthread_mutex_t serialize_mutex
= PTHREAD_MUTEX_INITIALIZER
;
102 static struct totem_logging_configuration totem_logging_configuration
;
104 static char delivery_data
[MESSAGE_SIZE_MAX
];
106 SaClmClusterNodeT
*(*main_clm_get_by_nodeid
) (unsigned int node_id
);
108 static void sigusr2_handler (int num
)
112 for (i
= 0; ais_service
[i
]; i
++) {
113 if (ais_service
[i
]->exec_dump_fn
) {
114 ais_service
[i
]->exec_dump_fn ();
119 static void sigsegv_handler (int num
)
121 signal (SIGSEGV
, SIG_DFL
);
126 static void sigabrt_handler (int num
)
128 signal (SIGABRT
, SIG_DFL
);
133 #define LOCALHOST_IP inet_addr("127.0.0.1")
135 totempg_groups_handle openais_group_handle
;
137 struct totempg_group openais_group
= {
142 void sigintr_handler (int signum
)
146 int stats_inuse
[MEMPOOL_GROUP_SIZE
];
147 int stats_avail
[MEMPOOL_GROUP_SIZE
];
148 int stats_memoryused
[MEMPOOL_GROUP_SIZE
];
151 mempool_getstats (stats_inuse
, stats_avail
, stats_memoryused
);
152 log_printf (LOG_LEVEL_DEBUG
, "Memory pools:\n");
153 for (i
= 0; i
< MEMPOOL_GROUP_SIZE
; i
++) {
154 log_printf (LOG_LEVEL_DEBUG
, "order %d size %d inuse %d avail %d memory used %d\n",
155 i
, 1<<i
, stats_inuse
[i
], stats_avail
[i
], stats_memoryused
[i
]);
160 openais_exit_error (AIS_DONE_EXIT
);
164 static int pool_sizes
[] = { 0, 0, 0, 0, 0, 4096, 0, 1, 0, /* 256 */
165 1024, 0, 1, 4096, 0, 0, 0, 0, /* 65536 */
166 1, 1, 1, 1, 1, 1, 1, 1, 1 };
168 void serialize_mutex_lock (void)
170 pthread_mutex_lock (&serialize_mutex
);
173 void serialize_mutex_unlock (void)
175 pthread_mutex_unlock (&serialize_mutex
);
179 static void openais_sync_completed (void)
183 static int openais_sync_callbacks_retrieve (int sync_id
,
184 struct sync_callbacks
*callbacks
)
186 unsigned int ais_service_index
;
187 unsigned int ais_services_found
= 0;
189 for (ais_service_index
= 0;
190 ais_service_index
< SERVICE_HANDLER_MAXIMUM_COUNT
;
191 ais_service_index
++) {
193 if (ais_service
[ais_service_index
] != NULL
) {
194 if (ais_services_found
== sync_id
) {
197 ais_services_found
+= 1;
200 if (ais_service_index
== SERVICE_HANDLER_MAXIMUM_COUNT
) {
201 memset (callbacks
, 0, sizeof (struct sync_callbacks
));
204 callbacks
->name
= ais_service
[ais_service_index
]->name
;
205 callbacks
->sync_init
= ais_service
[ais_service_index
]->sync_init
;
206 callbacks
->sync_process
= ais_service
[ais_service_index
]->sync_process
;
207 callbacks
->sync_activate
= ais_service
[ais_service_index
]->sync_activate
;
208 callbacks
->sync_abort
= ais_service
[ais_service_index
]->sync_abort
;
212 static struct memb_ring_id aisexec_ring_id
;
214 static void confchg_fn (
215 enum totem_configuration_type configuration_type
,
216 unsigned int *member_list
, int member_list_entries
,
217 unsigned int *left_list
, int left_list_entries
,
218 unsigned int *joined_list
, int joined_list_entries
,
219 struct memb_ring_id
*ring_id
)
223 memcpy (&aisexec_ring_id
, ring_id
, sizeof (struct memb_ring_id
));
226 * Call configuration change for all services
228 for (i
= 0; i
< service_count
; i
++) {
229 if (ais_service
[i
] && ais_service
[i
]->confchg_fn
) {
230 ais_service
[i
]->confchg_fn (configuration_type
,
231 member_list
, member_list_entries
,
232 left_list
, left_list_entries
,
233 joined_list
, joined_list_entries
, ring_id
);
238 static void aisexec_uid_determine (struct main_config
*main_config
)
240 struct passwd
*passwd
;
242 passwd
= getpwnam(main_config
->user
);
244 log_printf (LOG_LEVEL_ERROR
, "ERROR: The '%s' user is not found in /etc/passwd, please read the documentation.\n", main_config
->user
);
245 openais_exit_error (AIS_DONE_UID_DETERMINE
);
247 ais_uid
= passwd
->pw_uid
;
251 static void aisexec_gid_determine (struct main_config
*main_config
)
254 group
= getgrnam (main_config
->group
);
256 log_printf (LOG_LEVEL_ERROR
, "ERROR: The '%s' group is not found in /etc/group, please read the documentation.\n", group
->gr_name
);
257 openais_exit_error (AIS_DONE_GID_DETERMINE
);
259 gid_valid
= group
->gr_gid
;
263 static void aisexec_priv_drop (void)
270 static void aisexec_mempool_init (void)
274 res
= mempool_init (pool_sizes
);
276 log_printf (LOG_LEVEL_ERROR
, "Couldn't allocate memory pools, not enough memory");
277 openais_exit_error (AIS_DONE_MEMPOOL_INIT
);
281 static void aisexec_tty_detach (void)
284 struct rlimit oflimits
;
287 * Disconnect from TTY if this is not a debug run
291 openais_exit_error (AIS_DONE_FORK
);
295 * child which is disconnected, run this process
303 /* Create new session */
307 * Map stdin/out/err to /dev/null.
309 fd
= open("/dev/null", O_RDWR
);
311 /* dup2 to 0 / 1 / 2 (stdin / stdout / stderr) */
312 dup2(fd
, STDIN_FILENO
); /* 0 */
313 dup2(fd
, STDOUT_FILENO
); /* 1 */
314 dup2(fd
, STDERR_FILENO
); /* 2 */
316 /* Should be 0, but just in case it isn't... */
322 static void aisexec_setscheduler (void)
324 #if ! defined(TS_CLASS) && (defined(OPENAIS_BSD) || defined(OPENAIS_LINUX) || defined(OPENAIS_SOLARIS))
325 struct sched_param sched_param
;
328 res
= sched_get_priority_max (SCHED_RR
);
330 sched_param
.sched_priority
= 1;//res;
331 res
= sched_setscheduler (0, SCHED_RR
, &sched_param
);
333 log_printf (LOG_LEVEL_WARNING
, "Could not set SCHED_RR at priority %d: %s\n",
334 sched_param
.sched_priority
, strerror (errno
));
337 log_printf (LOG_LEVEL_WARNING
, "Could not get maximum scheduler priority: %s\n", strerror (errno
));
339 log_printf(LOG_LEVEL_WARNING
, "Scheduler priority left to default value (no OS support)\n");
343 static void aisexec_mlockall (void)
345 #if !defined(OPENAIS_BSD)
348 struct rlimit rlimit
;
350 rlimit
.rlim_cur
= RLIM_INFINITY
;
351 rlimit
.rlim_max
= RLIM_INFINITY
;
352 #ifndef OPENAIS_SOLARIS
353 setrlimit (RLIMIT_MEMLOCK
, &rlimit
);
355 setrlimit (RLIMIT_VMEM
, &rlimit
);
358 #if defined(OPENAIS_BSD)
359 /* under FreeBSD a process with locked page cannot call dlopen
360 * code disabled until FreeBSD bug i386/93396 was solved
362 log_printf (LOG_LEVEL_WARNING
, "Could not lock memory of service to avoid page faults\n");
364 res
= mlockall (MCL_CURRENT
| MCL_FUTURE
);
366 log_printf (LOG_LEVEL_WARNING
, "Could not lock memory of service to avoid page faults: %s\n", strerror (errno
));
372 static void deliver_fn (
376 int endian_conversion_required
)
378 mar_req_header_t
*header
;
385 * Build buffer without iovecs to make processing easier
386 * This is only used for messages which are multicast with iovecs
387 * and self-delivered. All other mechanisms avoid the copy.
390 for (i
= 0; i
< iov_len
; i
++) {
391 memcpy (&delivery_data
[pos
], iovec
[i
].iov_base
, iovec
[i
].iov_len
);
392 pos
+= iovec
[i
].iov_len
;
393 assert (pos
< MESSAGE_SIZE_MAX
);
395 header
= (mar_req_header_t
*)delivery_data
;
397 header
= (mar_req_header_t
*)iovec
[0].iov_base
;
399 if (endian_conversion_required
) {
400 header
->id
= swab32 (header
->id
);
401 header
->size
= swab32 (header
->size
);
404 // assert(iovec->iov_len == header->size);
407 * Call the proper executive handler
409 service
= header
->id
>> 16;
410 fn_id
= header
->id
& 0xffff;
411 if (endian_conversion_required
) {
412 assert(ais_service
[service
]->exec_service
[fn_id
].exec_endian_convert_fn
!= NULL
);
413 ais_service
[service
]->exec_service
[fn_id
].exec_endian_convert_fn
417 ais_service
[service
]->exec_service
[fn_id
].exec_handler_fn
421 int main (int argc
, char **argv
)
424 struct main_config main_config
;
425 struct totem_config totem_config
;
426 unsigned int objdb_handle
;
427 unsigned int config_handle
;
428 unsigned int config_version
= 0;
429 struct objdb_iface_ver0
*objdb
;
431 struct config_iface_ver0
*config
;
436 int background
, setprio
;
437 int totem_log_service
;
439 /* default configuration
444 while ((ch
= getopt (argc
, argv
, "fp")) != EOF
) {
449 logsys_config_mode_set (LOG_MODE_OUTPUT_STDERR
|LOG_MODE_FLUSH_AFTER_CONFIG
);
457 " -f : Start application in foreground.\n"\
458 " -p : Do not set process priority. \n");
464 aisexec_tty_detach ();
466 log_printf (LOG_LEVEL_NOTICE
, "AIS Executive Service RELEASE '%s'\n", RELEASE_VERSION
);
467 log_printf (LOG_LEVEL_NOTICE
, "Copyright (C) 2002-2006 MontaVista Software, Inc and contributors.\n");
468 log_printf (LOG_LEVEL_NOTICE
, "Copyright (C) 2006-2007 Red Hat, Inc.\n");
470 signal (SIGINT
, sigintr_handler
);
471 signal (SIGUSR2
, sigusr2_handler
);
472 signal (SIGSEGV
, sigsegv_handler
);
473 signal (SIGABRT
, sigabrt_handler
);
476 serialize_mutex_lock
,
477 serialize_mutex_unlock
);
479 log_printf (LOG_LEVEL_NOTICE
, "AIS Executive Service: started and ready to provide service.\n");
481 aisexec_poll_handle
= poll_create (
482 serialize_mutex_lock
,
483 serialize_mutex_unlock
);
486 * Load the object database interface
488 res
= lcr_ifact_reference (
495 log_printf (LOG_LEVEL_ERROR
, "AIS Executive couldn't open configuration object database component.\n");
496 openais_exit_error (AIS_DONE_OBJDB
);
499 objdb
= (struct objdb_iface_ver0
*)objdb_p
;
501 objdb
->objdb_init ();
503 /* User's bootstrap config service */
504 config_iface
= getenv("OPENAIS_DEFAULT_CONFIG_IFACE");
506 config_iface
= "aisparser";
509 /* Make a copy so we can deface it with strtok */
510 config_iface
= strdup(config_iface
);
512 iface
= strtok(config_iface
, ":");
515 res
= lcr_ifact_reference (
522 config
= (struct config_iface_ver0
*)config_p
;
524 log_printf (LOG_LEVEL_ERROR
, "AIS Executive couldn't open configuration component '%s'\n", iface
);
525 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
528 res
= config
->config_readconfig(objdb
, &error_string
);
530 log_printf (LOG_LEVEL_ERROR
, error_string
);
531 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
533 log_printf (LOG_LEVEL_NOTICE
, error_string
);
535 iface
= strtok(NULL
, ":");
540 openais_service_default_objdb_set (objdb
);
542 res
= openais_service_link_all (objdb
);
544 log_printf (LOG_LEVEL_ERROR
, "Could not load services\n");
545 openais_exit_error (AIS_DONE_DYNAMICLOAD
);
548 res
= openais_main_config_read (objdb
, &error_string
, &main_config
);
550 log_printf (LOG_LEVEL_ERROR
, error_string
);
551 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
554 res
= totem_config_read (objdb
, &totem_config
, &error_string
);
556 log_printf (LOG_LEVEL_ERROR
, error_string
);
557 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
560 res
= totem_config_keyread (objdb
, &totem_config
, &error_string
);
562 log_printf (LOG_LEVEL_ERROR
, error_string
);
563 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
566 res
= totem_config_validate (&totem_config
, &error_string
);
568 log_printf (LOG_LEVEL_ERROR
, error_string
);
569 openais_exit_error (AIS_DONE_MAINCONFIGREAD
);
572 logsys_config_facility_set ("openais", main_config
.syslog_facility
);
573 logsys_config_mode_set (main_config
.logmode
);
575 res
= logsys_config_file_set (&error_string
, main_config
.logfile
);
577 log_printf (LOG_LEVEL_ERROR
, error_string
);
578 openais_exit_error (AIS_DONE_LOGSETUP
);
581 aisexec_uid_determine (&main_config
);
583 aisexec_gid_determine (&main_config
);
586 * Set round robin realtime scheduling with priority 99
587 * Lock all memory to avoid page faults which may interrupt
588 * application healthchecking
591 aisexec_setscheduler ();
595 totem_config
.totem_logging_configuration
= totem_logging_configuration
;
596 totem_log_service
= _logsys_subsys_create ("TOTEM", LOG_INFO
);
597 totem_config
.totem_logging_configuration
.log_level_security
= logsys_mkpri (LOG_LEVEL_SECURITY
, totem_log_service
);
598 totem_config
.totem_logging_configuration
.log_level_error
= logsys_mkpri (LOG_LEVEL_ERROR
, totem_log_service
);
599 totem_config
.totem_logging_configuration
.log_level_warning
= logsys_mkpri (LOG_LEVEL_WARNING
, totem_log_service
);
600 totem_config
.totem_logging_configuration
.log_level_notice
= logsys_mkpri (LOG_LEVEL_NOTICE
, totem_log_service
);
601 totem_config
.totem_logging_configuration
.log_level_debug
= logsys_mkpri (LOG_LEVEL_DEBUG
, totem_log_service
);
602 totem_config
.totem_logging_configuration
.log_printf
= logsys_log_printf
;
605 * Sleep for a while to let other nodes in the cluster
606 * understand that this node has been away (if it was
607 * an aisexec restart).
610 // TODO what is this hack for? usleep(totem_config.token_timeout * 2000);
613 * if totempg_initialize doesn't have root priveleges, it cannot
614 * bind to a specific interface. This only matters if
615 * there is more then one interface in a system, so
616 * in this case, only a warning is printed
619 * Join multicast group and setup delivery
620 * and configuration change functions
626 totempg_groups_initialize (
627 &openais_group_handle
,
631 totempg_groups_join (
632 openais_group_handle
,
637 * This must occur after totempg is initialized because "this_ip" must be set
639 res
= openais_service_init_all (service_count
, objdb
);
641 log_printf (LOG_LEVEL_ERROR
, "Could not init services\n");
642 openais_exit_error (AIS_DONE_INIT_SERVICES
);
645 sync_register (openais_sync_callbacks_retrieve
, openais_sync_completed
,
646 totem_config
.vsf_type
);
649 res
= openais_flow_control_initialize ();
652 * Drop root privleges to user 'ais'
653 * TODO: Don't really need full root capabilities;
654 * needed capabilities are:
655 * CAP_NET_RAW (bindtodevice)
656 * CAP_SYS_NICE (setscheduler)
657 * CAP_IPC_LOCK (mlockall)
659 aisexec_priv_drop ();
661 aisexec_mempool_init ();
664 serialize_mutex_lock
,
665 serialize_mutex_unlock
,
669 * Start main processing loop
671 poll_run (aisexec_poll_handle
);