From e993689ac54a811e8a4b3e4d951fe892d3bedcef Mon Sep 17 00:00:00 2001 From: Hans Feldt Date: Tue, 20 Jun 2006 06:45:16 +0000 Subject: [PATCH] Refactoring of AMF into several files (based on classed in inf. model). A central header file (amf.h) keeps all the definitions and prototypes needed. New things apart from that: - some doxygen html generated from AMF e.g. each file has a description - saAmfHAStateGet() now works - component invoked healthchecks implemented (but not tested) git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@1071 fd59a12c-fef9-0310-b244-a6a79926bd2f --- Doxyfile | 2 +- exec/Makefile | 85 +- exec/amf.c | 2453 +++---------------------------- exec/amf.h | 679 +++++++++ exec/amfapp.c | 113 ++ exec/amfcluster.c | 123 ++ exec/amfcomp.c | 1521 +++++++++++++++++++ exec/amfconfig.h | 378 ----- exec/amfnode.c | 107 ++ exec/amfsg.c | 422 ++++++ exec/amfsi.c | 132 ++ exec/amfsu.c | 456 ++++++ exec/{amfconfig.c => amfutil.c} | 300 ++-- include/saAmf.h | 2 +- test/testamf1.c | 13 +- 15 files changed, 4034 insertions(+), 2752 deletions(-) create mode 100644 exec/amf.h create mode 100644 exec/amfapp.c create mode 100644 exec/amfcluster.c create mode 100644 exec/amfcomp.c delete mode 100644 exec/amfconfig.h create mode 100644 exec/amfnode.c create mode 100644 exec/amfsg.c create mode 100644 exec/amfsi.c create mode 100644 exec/amfsu.c rename exec/{amfconfig.c => amfutil.c} (82%) diff --git a/Doxyfile b/Doxyfile index 752e913e..32a2ddfe 100644 --- a/Doxyfile +++ b/Doxyfile @@ -49,7 +49,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = lib include +INPUT = lib include exec FILE_PATTERNS = *.c *.h RECURSIVE = YES EXAMPLE_PATH = diff --git a/exec/Makefile b/exec/Makefile index 1f753b27..2a846ecc 100644 --- a/exec/Makefile +++ b/exec/Makefile @@ -48,9 +48,13 @@ TOTEM_SRC = aispoll.c totemip.c totemnet.c totemrrp.c totemsrp.c totemmrp.c tote TOTEM_OBJS = aispoll.o totemip.o totemnet.o totemrrp.o totemsrp.o totemmrp.o totempg.o crypto.o wthread.o EXEC_LIBS = libtotem_pg.a +# AMF objects +AMF_SRC = amf.c amfutil.c amfnode.c amfcluster.c amfapp.c amfsg.c amfsu.c amfcomp.c amfsi.c +AMF_OBJS = amf.o amfutil.o amfnode.o amfcluster.o amfapp.o amfsg.o amfsu.o amfcomp.o amfsi.o + # LCR objects -LCR_SRC = evs.c clm.c amf.c ckpt.c evt.c lck.c msg.c cfg.c cpg.c amfconfig.c aisparser.c vsf_ykd.c -LCR_OBJS = evs.o clm.o amf.o ckpt.o evt.o lck.o msg.o cfg.o cpg.o amfconfig.o aisparser.o vsf_ykd.o +LCR_SRC = evs.c clm.c ckpt.c evt.c lck.c msg.c cfg.c cpg.c aisparser.c vsf_ykd.c $(AMF_SRC) +LCR_OBJS = evs.o clm.o ckpt.o evt.o lck.o msg.o cfg.o cpg.o aisparser.o vsf_ykd.o $(AMF_OBJS) # main executive objects MAIN_SRC = main.c print.c mempool.c util.c sync.c service.c ipc.c timer.c \ @@ -83,8 +87,8 @@ service_evs.lcrso: evs.o service_clm.lcrso: clm.o $(CC) $(LDFLAGS) -bundle $(LDFLAGS) -bundle_loader ./aisexec -bind_at_load clm.o -o $@ -service_amf.lcrso: amf.o amfconfig.o - $(CC) $(LDFLAGS) -bundle $(LDFLAGS) -bundle_loader ./aisexec -bind_at_load amf.o amfconfig.o -o $@ +service_amf.lcrso: $(AMF_OBJS) + $(CC) $(LDFLAGS) -bundle $(LDFLAGS) -bundle_loader ./aisexec -bind_at_load $(AMF_OBJS) -o $@ service_ckpt.lcrso: ckpt.o $(CC) $(LDFLAGS) -bundle $(LDFLAGS) -bundle_loader ./aisexec -bind_at_load ckpt.o -o $@ @@ -122,8 +126,8 @@ service_evs.lcrso: evs.o service_clm.lcrso: clm.o $(CC) -shared -Wl,-soname,service_clm.lcrso clm.o -o $@ -service_amf.lcrso: amf.o amfconfig.o - $(CC) -shared -Wl,-soname,service_amf.lcrso amf.o amfconfig.o -o $@ +service_amf.lcrso: $(AMF_OBJS) + $(CC) -shared -Wl,-soname,service_amf.lcrso $(AMF_OBJS) -o $@ service_ckpt.lcrso: ckpt.o $(CC) -shared -Wl,-soname,service_ckpt.lcrso ckpt.o -o $@ @@ -274,24 +278,19 @@ totempg.o: totemmrp.h swab.h tlist.o: ../include/list.h tlist.h crypto.o: crypto.h wthread.o: wthread.h ../include/queue.h -evs.o: ../include/saAis.h ../include/ipc_gen.h ../exec/totemip.h -evs.o: ../include/ipc_evs.h ../include/saAis.h ../include/evs.h -evs.o: ../include/ipc_gen.h ../include/list.h ../include/queue.h -evs.o: ../lcr/lcr_comp.h aispoll.h totempg.h totemsrp.h totem.h totemip.h +evs.o: totem.h totemip.h ../include/saAis.h ../include/ipc_gen.h +evs.o: ../exec/totemip.h ../include/ipc_evs.h ../include/saAis.h +evs.o: ../include/evs.h ../include/ipc_gen.h ../include/list.h +evs.o: ../include/queue.h ../lcr/lcr_comp.h aispoll.h totempg.h totemsrp.h evs.o: main.h ../include/saClm.h mainconfig.h objdb.h mempool.h service.h evs.o: print.h -clm.o: ../include/saAis.h ../include/saClm.h ../include/saAis.h -clm.o: ../include/ipc_gen.h ../exec/totemip.h ../include/ipc_clm.h -clm.o: ../include/saClm.h ../include/ipc_gen.h ../include/list.h -clm.o: ../include/queue.h ../lcr/lcr_comp.h aispoll.h totempg.h totemsrp.h -clm.o: totem.h totemip.h main.h mainconfig.h objdb.h mempool.h service.h -clm.o: print.h -amf.o: ../include/saAis.h ../include/saAmf.h ../include/saAis.h -amf.o: ../include/ipc_gen.h ../exec/totemip.h ../include/ipc_amf.h -amf.o: ../include/ipc_gen.h ../include/ais_amf.h ../include/list.h -amf.o: ../include/queue.h ../lcr/lcr_comp.h totempg.h aispoll.h totemsrp.h -amf.o: totem.h totemip.h mempool.h util.h amfconfig.h main.h -amf.o: ../include/saClm.h mainconfig.h objdb.h service.h print.h +clm.o: totem.h totemip.h ../include/saAis.h ../include/saClm.h +clm.o: ../include/saAis.h ../include/ipc_gen.h ../exec/totemip.h +clm.o: ../include/ipc_clm.h ../include/saClm.h ../include/ipc_gen.h +clm.o: ../include/mar_clm.h ../include/mar_gen.h ../include/mar_gen.h +clm.o: ../include/mar_clm.h ../include/list.h ../include/queue.h +clm.o: ../lcr/lcr_comp.h aispoll.h totempg.h totemsrp.h main.h mainconfig.h +clm.o: objdb.h mempool.h service.h swab.h print.h ckpt.o: ../include/saAis.h ../include/saCkpt.h ../include/ipc_ckpt.h ckpt.o: ../include/saAis.h ../include/saCkpt.h ../include/ipc_gen.h ckpt.o: ../include/list.h ../include/queue.h ../include/hdb.h @@ -327,12 +326,46 @@ cpg.o: ../include/ipc_gen.h ../exec/totemip.h ../include/ipc_cpg.h cpg.o: ../include/ipc_gen.h ../include/list.h ../include/queue.h cpg.o: ../lcr/lcr_comp.h aispoll.h totempg.h totemsrp.h totem.h totemip.h cpg.o: main.h mainconfig.h objdb.h mempool.h service.h jhash.h swab.h print.h -amfconfig.o: ../include/saAis.h ../include/saAmf.h ../include/saAis.h -amfconfig.o: ../include/ipc_amf.h ../include/ipc_gen.h ../include/ais_amf.h -amfconfig.o: ../include/list.h util.h amfconfig.h aispoll.h mempool.h totem.h -amfconfig.o: totemip.h aisparser.o: ../lcr/lcr_comp.h objdb.h config.h mempool.h ../include/list.h +aisparser.o: util.h ../include/saAis.h vsf_ykd.o: main.h ../include/saAis.h ../include/saClm.h ../include/saAis.h vsf_ykd.o: ../include/queue.h ../include/ipc_gen.h ../exec/totemip.h vsf_ykd.o: mainconfig.h ../include/list.h aispoll.h totemsrp.h totem.h vsf_ykd.o: totemip.h totempg.h objdb.h print.h swab.h vsf.h ../lcr/lcr_comp.h +amf.o: ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amf.o: ../include/ipc_gen.h ../exec/totemip.h ../include/ipc_amf.h +amf.o: ../include/ipc_gen.h ../include/ais_amf.h ../include/list.h +amf.o: ../lcr/lcr_comp.h totempg.h aispoll.h totemsrp.h totem.h totemip.h +amf.o: mempool.h util.h amf.h objdb.h main.h ../include/saClm.h +amf.o: ../include/queue.h mainconfig.h service.h print.h +amfutil.o: ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amfutil.o: ../include/ipc_amf.h ../include/ipc_gen.h ../include/ais_amf.h +amfutil.o: ../include/list.h util.h amf.h ../include/ipc_gen.h +amfutil.o: ../exec/totemip.h aispoll.h objdb.h totem.h totemip.h print.h +amfutil.o: mainconfig.h totemsrp.h totempg.h +amfcluster.o: print.h mainconfig.h ../include/saAis.h ../include/list.h +amfcluster.o: aispoll.h totemsrp.h totem.h totemip.h totempg.h objdb.h amf.h +amfcluster.o: ../include/saAmf.h ../include/saAis.h ../include/ipc_gen.h +amfcluster.o: ../exec/totemip.h util.h main.h ../include/saClm.h +amfcluster.o: ../include/queue.h +amfapp.o: amf.h ../include/saAis.h ../include/saAmf.h +amfapp.o: ../include/saAis.h ../include/list.h ../include/ipc_gen.h +amfapp.o: ../exec/totemip.h aispoll.h objdb.h print.h mainconfig.h +amfapp.o: totemsrp.h totem.h totemip.h totempg.h +amfsg.o: amf.h ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amfsg.o: ../include/list.h ../include/ipc_gen.h ../exec/totemip.h aispoll.h +amfsg.o: objdb.h print.h mainconfig.h totemsrp.h totem.h totemip.h totempg.h +amfsg.o: main.h ../include/saClm.h ../include/queue.h +amfsu.o: amf.h ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amfsu.o: ../include/list.h ../include/ipc_gen.h ../exec/totemip.h aispoll.h +amfsu.o: objdb.h util.h print.h mainconfig.h totemsrp.h totem.h totemip.h +amfsu.o: totempg.h main.h ../include/saClm.h ../include/queue.h +amfcomp.o: ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amfcomp.o: ../include/ipc_gen.h ../exec/totemip.h ../include/ipc_amf.h +amfcomp.o: ../include/ipc_gen.h ../include/ais_amf.h totempg.h aispoll.h +amfcomp.o: totemsrp.h totem.h totemip.h main.h ../include/saClm.h +amfcomp.o: ../include/queue.h mainconfig.h ../include/list.h objdb.h +amfcomp.o: service.h util.h amf.h print.h +amfsi.o: amf.h ../include/saAis.h ../include/saAmf.h ../include/saAis.h +amfsi.o: ../include/list.h ../include/ipc_gen.h ../exec/totemip.h aispoll.h +amfsi.o: objdb.h print.h mainconfig.h totemsrp.h totem.h totemip.h totempg.h diff --git a/exec/amf.c b/exec/amf.c index 20367bf6..0905ac21 100644 --- a/exec/amf.c +++ b/exec/amf.c @@ -1,12 +1,15 @@ -/* +/** @file exec/amf.c + * * Copyright (c) 2002-2006 MontaVista Software, Inc. * Author: Steven Dake (sdake@mvista.com) * * Copyright (c) 2006 Ericsson AB. * Author: Hans Feldt - * Description: - Introduced AMF B.02 information model - * - Use DN in API and multicast messages - * - (Re-)Introduction of event based multicast messages + * Description: + * - Introduced AMF B.02 information model + * - Use DN in API and multicast messages + * - (Re-)Introduction of event based multicast messages + * - Refactoring of code into several AMF files * * All rights reserved. * @@ -36,6 +39,27 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Main + * + * The functions in this file are responsible for: + * - starting the AMF service (amf_exec_init_fn) + * - build the information model from the configuration file or by + * synchronising the state with an already started AMF node + * - receiving AMF library requests (message_handler_req_lib_*) + * - distributing AMF library requests to the cluster + * - receiving multicasts (message_handler_req_exec_*) and dispatch the + * requests to a component instance + * - send responses to the AMF library (return values for API calls) + * - handling EVS configuration change events (node leave/join) + * - handling node synchronisation events (amf_sync_*) + * - printing the AMF runtime attributes upon user request (USR2 signal) + * + * Some API requests are responded to directly in the lib message_handler. + * This is normally done when the API request parameters are wrong, e.g. a + * component cannot be found. In that case, the error handling must be taken + * care of in the lib message handler. + * */ #include #include @@ -62,11 +86,11 @@ #include "../include/list.h" #include "../lcr/lcr_comp.h" #include "totempg.h" +#include "aispoll.h" #include "mempool.h" #include "util.h" -#include "amfconfig.h" +#include "amf.h" #include "main.h" -#include "timer.h" #include "service.h" #include "objdb.h" #include "print.h" @@ -75,242 +99,52 @@ #define LOG_LEVEL_FROM_GMI LOG_LEVEL_DEBUG #define LOG_LEVEL_ENTER_FUNC LOG_LEVEL_DEBUG -enum amf_message_req_types { - MESSAGE_REQ_EXEC_AMF_COMPONENT_REGISTER = 0, - MESSAGE_REQ_EXEC_AMF_COMPONENT_ERROR_REPORT = 1, - MESSAGE_REQ_EXEC_AMF_CLC_CLEANUP_COMPLETED = 2, - MESSAGE_REQ_EXEC_AMF_HEALTHCHECK_TMO = 3, - MESSAGE_REQ_EXEC_AMF_RESPONSE = 4 -}; - #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 255 #endif -struct invocation { - void *data; - int interface; - int active; -}; - -static struct invocation *invocation_entries = 0; - -static int invocation_entries_size = 0; -static int waiting = 0; - -enum amf_response_interfaces { - AMF_RESPONSE_HEALTHCHECKCALLBACK = 1, - AMF_RESPONSE_CSISETCALLBACK = 2, - AMF_RESPONSE_CSIREMOVECALLBACK = 3, - AMF_RESPONSE_COMPONENTTERMINATECALLBACK = 4 -}; - -struct component_terminate_callback_data { - struct amf_comp *comp; -}; - static void amf_confchg_fn ( enum totem_configuration_type configuration_type, unsigned int *member_list, int member_list_entries, unsigned int *left_list, int left_list_entries, unsigned int *joined_list, int joined_list_entries, struct memb_ring_id *ring_id); - static int amf_lib_exit_fn (void *conn); - static int amf_exec_init_fn (struct objdb_iface_ver0 *objdb); - static int amf_lib_init_fn (void *conn); - static void message_handler_req_lib_amf_componentregister (void *conn, void *msg); - static void message_handler_req_lib_amf_componentunregister (void *conn, void *msg); - static void message_handler_req_lib_amf_pmstart (void *conn, void *msg); - static void message_handler_req_lib_amf_pmstop (void *conn, void *msg); - static void message_handler_req_lib_amf_healthcheckstart (void *conn, void *msg); - static void message_handler_req_lib_amf_healthcheckconfirm (void *conn, void *msg); - static void message_handler_req_lib_amf_healthcheckstop (void *conn, void *msg); - static void message_handler_req_lib_amf_hastateget (void *conn, void *message); - static void message_handler_req_lib_amf_csiquiescingcomplete (void *conn, void *msg); - static void message_handler_req_lib_amf_protectiongrouptrack (void *conn, void *msg); - static void message_handler_req_lib_amf_protectiongrouptrackstop (void *conn, void *msg); - static void message_handler_req_lib_amf_componenterrorreport (void *conn, void *msg); - static void message_handler_req_lib_amf_componenterrorclear (void *conn, void *msg); - static void message_handler_req_lib_amf_response (void *conn, void *msg); - static void message_handler_req_exec_amf_comp_register ( - void *message, - unsigned int nodeid); - + void *message, unsigned int nodeid); static void message_handler_req_exec_amf_comp_error_report ( - void *message, - unsigned int nodeid); - + void *message, unsigned int nodeid); static void message_handler_req_exec_amf_clc_cleanup_completed ( - void *message, - unsigned int nodeid); - + void *message, unsigned int nodeid); static void message_handler_req_exec_amf_healthcheck_tmo ( - void *message, - unsigned int nodeid); - + void *message, unsigned int nodeid); static void message_handler_req_exec_amf_response ( - void *message, - unsigned int nodeid); + void *message, unsigned int nodeid); +static void amf_dump_fn (void); +static void amf_sync_init (void); +static int amf_sync_process (void); +static void amf_sync_abort (void); +static void amf_sync_activate (void); -static void comp_presence_state_set ( - struct amf_comp *comp, - SaAmfPresenceStateT presence_state); - -static void comp_operational_state_set ( - struct amf_comp *comp, - SaAmfOperationalStateT operational_state); - -static void su_operational_state_set ( - struct amf_su *unit, - SaAmfOperationalStateT operational_state); - -static void su_presence_state_set ( - struct amf_su *su, - SaAmfPresenceStateT presence_state); - -static void sg_assign_si (struct amf_sg *group); -static int clc_instantiate (struct amf_comp *comp); -#if 0 -static int clc_terminate (struct amf_comp *comp); -#endif -static int clc_cli_instantiate (struct amf_comp *comp); -static int clc_instantiate_callback (struct amf_comp *comp); -static int clc_csi_set_callback (struct amf_comp *comp); -static int clc_cli_terminate (struct amf_comp *comp); -static int clc_terminate_callback (struct amf_comp *comp); -static int clc_csi_remove_callback (struct amf_comp *comp); -static int clc_cli_cleanup (struct amf_comp *comp); -static int clc_cli_cleanup_local (struct amf_comp *comp); -static void healthcheck_activate (struct amf_healthcheck *healthcheck_active); -static void healthcheck_deactivate (struct amf_healthcheck *healthcheck_active); -//static void comp_healthcheck_activate (struct amf_comp *comp); -static void comp_healthcheck_deactivate (struct amf_comp *comp); -static void escalation_policy_restart (struct amf_comp *comp); -static void amf_runtime_attributes_print (void); -static void clc_su_instantiate (struct amf_su *unit); -static void cluster_start_applications (void *data); - -static char *presence_state_text[] = { - "UNKNOWN", - "UNINSTANTIATED", - "INSTANTIATING", - "INSTANTIATED", - "TERMINATING", - "RESTARTING", - "INSTANTION_FAILED", - "TERMINIATION-FAILED" -}; - -static char *oper_state_text[] = { - "UNKNOWN", - "ENABLED", - "DISABLED" -}; - -static char *admin_state_text[] = { - "UNKNOWN", - "UNLOCKED", - "LOCKED", - "LOCKED-INSTANTIATION", - "SHUTTING-DOWN" -}; - -static char *readiness_state_text[] = { - "UNKNOWN", - "OUT-OF-SERVICE", - "IN-SERVICE", -}; - -static char *ha_state_text[] = { - "UNKNOWN", - "ACTIVE", - "STANDBY", - "QUIESCED", - "QUIESCING", -}; - -static char *assignment_state_text[] = { - "UNKNOWN", - "UNASSIGNED", - "FULLY-ASSIGNED", - "PARTIALLY-ASSIGNED" -}; - -struct libamf_ci_trackentry { - int active; - SaUint8T trackFlags; - SaAmfProtectionGroupNotificationT *notificationBufferAddress; - SaNameT csiName; -}; - -struct amf_comp; struct amf_pd { struct amf_comp *comp; struct list_head list; -/* - struct libamf_ci_trackentry *tracks; - int trackEntries; - int trackActive; -*/ -}; - - -struct clc_interface { - int (*instantiate) (struct amf_comp *comp); - int (*terminate) (struct amf_comp *comp); - int (*cleanup) (struct amf_comp *comp); -}; - -/* - * Life cycle functions - */ -static struct clc_interface clc_interface_sa_aware = { - clc_cli_instantiate, - clc_terminate_callback, - clc_cli_cleanup -}; - -static struct clc_interface clc_interface_proxied_pre = { - clc_instantiate_callback, - clc_terminate_callback, - clc_cli_cleanup -}; - -static struct clc_interface clc_interface_proxied_non_pre = { - clc_csi_set_callback, - clc_csi_remove_callback, - clc_cli_cleanup_local -}; - -static struct clc_interface clc_interface_non_proxied_non_saware = { - clc_cli_instantiate, - clc_cli_terminate, - clc_cli_cleanup_local -}; - -static struct clc_interface *clc_interfaces[4] = { - &clc_interface_sa_aware, - &clc_interface_proxied_pre, - &clc_interface_proxied_non_pre, - &clc_interface_non_proxied_non_saware }; /* @@ -404,6 +238,9 @@ static struct openais_lib_handler amf_lib_service[] = }, }; +/* + * Multicast message handlers + */ static struct openais_exec_handler amf_exec_service[] = { { .exec_handler_fn = message_handler_req_exec_amf_comp_register, @@ -437,11 +274,15 @@ static struct openais_service_handler amf_service_handler = { .exec_service = amf_exec_service, .exec_service_count = sizeof (amf_exec_service) / sizeof (struct openais_exec_handler), .confchg_fn = amf_confchg_fn, - .exec_dump_fn = amf_runtime_attributes_print + .exec_dump_fn = amf_dump_fn, + .sync_init = amf_sync_init, + .sync_process = amf_sync_process, + .sync_activate = amf_sync_activate, + .sync_abort = amf_sync_abort, }; -static struct amf_node *this_amf_node; -static struct amf_cluster amf_cluster; +struct amf_node *this_amf_node; +struct amf_cluster amf_cluster; static struct openais_service_handler *amf_get_handler_ver0 (void); @@ -473,24 +314,12 @@ static struct openais_service_handler *amf_get_handler_ver0 (void) return (&amf_service_handler); } -__attribute__ ((constructor)) static void register_this_component (void) { - lcr_interfaces_set (&openais_amf_ver0[0], &amf_service_handler_iface); - +__attribute__ ((constructor)) static void register_this_component (void) +{ + lcr_interfaces_set (&openais_amf_ver0[0], &amf_service_handler_iface); lcr_component_register (&amf_comp_ver0); } -enum clc_command_run_operation_type { - CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE = 1, - CLC_COMMAND_RUN_OPERATION_TYPE_TERMINATE = 2, - CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP = 3 -}; - -struct clc_command_run_data { - struct amf_comp *comp; - enum clc_command_run_operation_type type; - void (*completion_callback) (void *context); -}; - struct req_exec_amf_comp_register { struct req_header header; SaNameT compName; @@ -506,578 +335,33 @@ struct req_exec_amf_comp_error_report { SaNtfIdentifierT ntfIdentifier; }; -struct req_exec_amf_clc_cleanup_completed { - struct req_header header; - SaNameT compName; -}; - -struct req_exec_amf_healthcheck_tmo { - struct req_header header; - SaNameT compName; -}; - struct req_exec_amf_response { struct req_header header; - SaNameT compName; - SaNameT csiName; - unsigned int interface; + SaInvocationT invocation; SaAisErrorT error; }; -static char *comp_dn_make (struct amf_comp *comp, SaNameT *name) -{ - int i = snprintf((char*) name->value, SA_MAX_NAME_LENGTH, - "safComp=%s,safSu=%s,safSg=%s,safApp=%s", - comp->name.value, comp->su->name.value, - comp->su->sg->name.value, comp->su->sg->application->name.value); - assert (i <= SA_MAX_NAME_LENGTH); - name->length = i; - return (char *)name->value; -} - -static char *csi_dn_make (struct amf_csi *csi, SaNameT *name) -{ - int i = snprintf((char*) name->value, SA_MAX_NAME_LENGTH, - "safCsi=%s,safSi=%s,safApp=%s", - csi->name.value, csi->si->name.value, - csi->si->application->name.value); - assert (i <= SA_MAX_NAME_LENGTH); - name->length = i; - return (char *)name->value; -} - -static int invocation_create ( - int interface, - void *data) -{ - struct invocation *invocation_addr = 0; - struct invocation *invocation_temp; - int i; - int loc = 0; - - for (i = 0; i < invocation_entries_size; i++) { - if (invocation_entries[i].active == 0) { - invocation_addr = &invocation_entries[i]; - loc = i; - break; - } - } - if (invocation_addr == 0) { - invocation_temp = (struct invocation *)realloc (invocation_entries, - (invocation_entries_size + 1) * sizeof (struct invocation)); - if (invocation_temp == 0) { - return (-1); - } - invocation_entries = invocation_temp; - invocation_addr = &invocation_entries[invocation_entries_size]; - loc = invocation_entries_size; - invocation_entries_size += 1; - } - invocation_addr->interface = interface; - invocation_addr->data = data; - invocation_addr->active = 1; - - return (loc); -} - -static int invocation_get_and_destroy (int invocation, int *interface, - void **data) -{ - if (invocation > invocation_entries_size) { - return (-1); - } - if (invocation_entries[invocation].active == 0) { - return (-1); - } - - *interface = invocation_entries[invocation].interface; - *data = invocation_entries[invocation].data; - memset (&invocation_entries[invocation], 0, sizeof (struct invocation)); - - return (0); -} - -static void invocation_destroy_by_data (void *data) -{ - int i; - - for (i = 0; i < invocation_entries_size; i++) { - if (invocation_entries[i].data == data) { - memset (&invocation_entries[i], 0, - sizeof (struct invocation)); - break; - } - } -} - -static void *clc_command_run (void *context) -{ - struct clc_command_run_data *clc_command_run_data = - (struct clc_command_run_data *)context; - pid_t pid; - int res; - char *argv[10]; - char *envp[10]; - int status; - char path[PATH_MAX]; - char *cmd = 0; - char *comp_argv = 0; - char comp_name[SA_MAX_NAME_LENGTH]; - int i; - - ENTER_VOID(); - - pid = fork(); - - if (pid == -1) { - dprintf ("Couldn't fork process %s\n", strerror (errno)); - return (0); - } - - if (pid) { - waiting = 1; - dprintf ("waiting for pid %d to finish\n", pid); - waitpid (pid, &status, 0); - dprintf ("process (%d) finished with %d\n", pid, status); - if (clc_command_run_data->completion_callback) { - clc_command_run_data->completion_callback (context); - } - pthread_exit(0); - } - - switch (clc_command_run_data->type) { - case CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE: - cmd = clc_command_run_data->comp->saAmfCompInstantiateCmd; - comp_argv = clc_command_run_data->comp->saAmfCompInstantiateCmdArgv; - break; - - case CLC_COMMAND_RUN_OPERATION_TYPE_TERMINATE: - cmd = clc_command_run_data->comp->saAmfCompTerminateCmd; - comp_argv = clc_command_run_data->comp->saAmfCompTerminateCmdArgv; - break; - - case CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP: - cmd = clc_command_run_data->comp->saAmfCompCleanupCmd; - comp_argv = clc_command_run_data->comp->saAmfCompCleanupCmdArgv; - break; - default: - assert (0 != 1); - break; - } - - /* If command is not an absolute path, search for paths in parent objects */ - if (cmd[0] != '/') { - if (strlen (clc_command_run_data->comp->clccli_path)) { - sprintf (path, "%s/%s", - clc_command_run_data->comp->clccli_path, cmd); - } else if (strlen (clc_command_run_data->comp->su->clccli_path)) { - sprintf (path, "%s/%s", - clc_command_run_data->comp->su->clccli_path, cmd); - } else if (strlen (clc_command_run_data->comp->su->sg->clccli_path)) { - sprintf (path, "%s/%s", - clc_command_run_data->comp->su->sg->clccli_path, cmd); - } else if (strlen (clc_command_run_data->comp->su->sg->application->clccli_path)) { - sprintf (path, "%s/%s", - clc_command_run_data->comp->su->sg->application->clccli_path, cmd); - } - cmd = path; - } - - argv[0] = cmd; - { - /* make a proper argv array */ - i = 1; - char *ptrptr; - char *arg = strtok_r(comp_argv, " ", &ptrptr); - while (arg) { - argv[i] = arg; - arg = strtok_r(NULL, " ", & ptrptr); - i++; - } - } - argv[i] = NULL; - - envp[0] = comp_name; - i = snprintf(comp_name, SA_MAX_NAME_LENGTH, - "SA_AMF_COMPONENT_NAME=safComp=%s,safSu=%s,safSg=%s,safApp=%s", - clc_command_run_data->comp->name.value, - clc_command_run_data->comp->su->name.value, - clc_command_run_data->comp->su->sg->name.value, - clc_command_run_data->comp->su->sg->application->name.value); - assert (i <= SA_MAX_NAME_LENGTH); - - for (i = 1; clc_command_run_data->comp->saAmfCompCmdEnv && - clc_command_run_data->comp->saAmfCompCmdEnv[i - 1]; i++) { - envp[i] = clc_command_run_data->comp->saAmfCompCmdEnv[i - 1]; - } - envp[i] = NULL; - - dprintf ("running command '%s' with environment:\n", cmd); - for (i = 0; envp[i] != NULL; i++) { - dprintf (" %s\n", envp[i]); - } - dprintf (" and argv:\n", cmd); - for (i = 0; argv[i] != NULL; i++) { - dprintf (" %s\n", argv[i]); - } - - res = execve (cmd, argv, envp); - if (res == -1) { - log_printf (LOG_LEVEL_ERROR, "Couldn't exec program %s (%s)\n", - cmd, strerror (errno)); - } - assert (res != -1); - return (0); -} - -/* - * Instantiate possible operations - */ -static int clc_cli_instantiate (struct amf_comp *comp) -{ - int res; - pthread_t thread; - pthread_attr_t thread_attr; /* thread attribute */ - - struct clc_command_run_data *clc_command_run_data; - - ENTER("comp '%s'\n", getSaNameT (&comp->name)); - - clc_command_run_data = malloc (sizeof (struct clc_command_run_data)); - if (clc_command_run_data == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - clc_command_run_data->comp = comp; - clc_command_run_data->type = CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE; - clc_command_run_data->completion_callback = NULL; - pthread_attr_init (&thread_attr); - pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED); - res = pthread_create (&thread, &thread_attr, clc_command_run, (void *)clc_command_run_data); - if (res != 0) { - log_printf (LOG_LEVEL_ERROR, "pthread_create failed: %d", res); - } -// TODO error code from pthread_create - return (res); -} - -static int clc_instantiate_callback (struct amf_comp *comp) -{ - ENTER("comp %s\n", getSaNameT (&comp->name)); - return (0); -} - -static int clc_csi_set_callback (struct amf_comp *comp) -{ - ENTER("comp %s\n", getSaNameT (&comp->name)); - return (0); -} - -/* - * Terminate possible operations - */ -static int clc_cli_terminate (struct amf_comp *comp) -{ - ENTER("comp %s\n", getSaNameT (&comp->name)); - return (0); -} - -static int clc_terminate_callback (struct amf_comp *comp) -{ - struct res_lib_amf_componentterminatecallback res_lib_amf_componentterminatecallback; - struct component_terminate_callback_data *component_terminate_callback_data; - - ENTER("comp %s\n", getSaNameT (&comp->name)); - - if (comp->saAmfCompPresenceState != SA_AMF_PRESENCE_INSTANTIATED) { - dprintf ("component terminated but not instantiated %s - %d\n", - getSaNameT (&comp->name), comp->saAmfCompPresenceState); - assert (0); - return (0); - } - - dprintf ("component name terminating %s\n", getSaNameT (&comp->name)); - dprintf ("component presence state %d\n", comp->saAmfCompPresenceState); - - res_lib_amf_componentterminatecallback.header.id = MESSAGE_RES_AMF_COMPONENTTERMINATECALLBACK; - res_lib_amf_componentterminatecallback.header.size = sizeof (struct res_lib_amf_componentterminatecallback); - res_lib_amf_componentterminatecallback.header.error = SA_AIS_OK; - - - memcpy (&res_lib_amf_componentterminatecallback.compName, - &comp->name, sizeof (SaNameT)); - - component_terminate_callback_data = - malloc (sizeof (struct component_terminate_callback_data)); - if (component_terminate_callback_data == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - component_terminate_callback_data->comp = comp; - - res_lib_amf_componentterminatecallback.invocation = - invocation_create ( - AMF_RESPONSE_COMPONENTTERMINATECALLBACK, - component_terminate_callback_data); - dprintf ("Creating invocation %llu", - (unsigned long long)res_lib_amf_componentterminatecallback.invocation); - - openais_conn_send_response ( - openais_conn_partner_get (comp->conn), - &res_lib_amf_componentterminatecallback, - sizeof (struct res_lib_amf_componentterminatecallback)); - - return (0); -} - -static int clc_csi_remove_callback (struct amf_comp *comp) -{ - dprintf ("clc_tcsi_remove_callback\n"); - return (0); -} - -/* - * Clean up completed - */ -static void clc_cleanup_completion_callback (void *context) { - struct clc_command_run_data *clc_command_run_data = - (struct clc_command_run_data *)context; - struct req_exec_amf_clc_cleanup_completed req; - struct iovec iovec; - - TRACE2("CLC cleanup done for '%s'", clc_command_run_data->comp->name.value); - - req.header.size = sizeof (struct req_exec_amf_clc_cleanup_completed); - req.header.id = SERVICE_ID_MAKE (AMF_SERVICE, - MESSAGE_REQ_EXEC_AMF_CLC_CLEANUP_COMPLETED); - - comp_dn_make (clc_command_run_data->comp, &req.compName); - iovec.iov_base = (char *)&req; - iovec.iov_len = sizeof (req); - - assert (totempg_groups_mcast_joined (openais_group_handle, - &iovec, 1, TOTEMPG_AGREED) == 0); -} - -/* - * Cleanup possible operations - */ -static int clc_cli_cleanup (struct amf_comp *comp) -{ - int res; - pthread_t thread; - pthread_attr_t thread_attr; /* thread attribute */ - - struct clc_command_run_data *clc_command_run_data; - - dprintf ("clc_cli_cleanup\n"); - clc_command_run_data = malloc (sizeof (struct clc_command_run_data)); - if (clc_command_run_data == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - clc_command_run_data->comp = comp; - clc_command_run_data->type = CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP; - clc_command_run_data->completion_callback = clc_cleanup_completion_callback; - - pthread_attr_init (&thread_attr); - pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED); - res = pthread_create (&thread, &thread_attr, clc_command_run, (void *)clc_command_run_data); - if (res != 0) { - log_printf (LOG_LEVEL_ERROR, "pthread_create failed: %d", res); - } -// TODO error code from pthread_create - return (res); -} - -static int clc_cli_cleanup_local (struct amf_comp *comp) -{ - dprintf ("clc_cli_cleanup_local\n"); - return (0); -} - -static int clc_instantiate (struct amf_comp *comp) -{ - int res = 0; - - dprintf ("clc instantiate for comp '%s'\n", getSaNameT (&comp->name)); - - if (comp->saAmfCompPresenceState != SA_AMF_PRESENCE_RESTARTING) { - comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATING); - } - - if (comp->su->is_local) { - res = clc_interfaces[comp->comptype]->instantiate (comp); - } - - return res; -} - -#if 0 -static int clc_terminate (struct amf_comp *comp) -{ - int res; - - dprintf ("clc terminate for comp %s\n", getSaNameT (&comp->name)); - assert (0); - operational_state_comp_set (comp, SA_AMF_OPERATIONAL_DISABLED); - comp_presence_state_set (comp, SA_AMF_PRESENCE_TERMINATING); - - res = clc_interfaces[comp->comptype]->terminate (comp); - return (0); -} -#endif - -static int presence_state_all_comps_in_su_are_set (struct amf_su *su, SaAmfPresenceStateT state) -{ - int all_set = 1; - struct amf_comp *comp; - - for (comp = su->comp_head; comp != NULL; comp = comp->next) { - if (comp->saAmfCompPresenceState != state) { - all_set = 0; - } - } - - return all_set; -} - -static int clc_cleanup (struct amf_comp *comp) -{ - int res = 0; - dprintf ("clc cleanup for comp %s\n", getSaNameT (&comp->name)); - comp_healthcheck_deactivate (comp); - comp_presence_state_set (comp, SA_AMF_PRESENCE_RESTARTING); - - /* when all components in su are restarting, the SU becomes restarting */ - if (presence_state_all_comps_in_su_are_set(comp->su, SA_AMF_PRESENCE_RESTARTING)) { - su_presence_state_set (comp->su, SA_AMF_PRESENCE_RESTARTING); - } - - if (comp->su->is_local) { - res = clc_interfaces[comp->comptype]->cleanup (comp); - } - - return res; -} - /* IMPL */ -static void amf_runtime_attributes_print (void) +static void amf_sync_init (void) { - struct amf_node *node; - struct amf_application *app; - struct amf_sg *sg; - struct amf_su *su; - struct amf_comp *comp; - struct amf_si *si; - struct amf_csi *csi; - struct amf_si_assignment *si_assignment; - struct amf_csi_assignment *csi_assignment; - - dprintf("AMF runtime attributes:"); - dprintf("==================================================="); - dprintf("safCluster=%s", getSaNameT(&amf_cluster.name)); - dprintf(" admin state: %s\n", admin_state_text[amf_cluster.saAmfClusterAdminState]); - for (node = amf_cluster.node_head; node != NULL; node = node->next) { - dprintf(" safNode=%s\n", getSaNameT (&node->name)); - dprintf(" admin state: %s\n", admin_state_text[node->saAmfNodeAdminState]); - dprintf(" oper state: %s\n", oper_state_text[node->saAmfNodeOperState]); - } - for (app = amf_cluster.application_head; app != NULL; app = app->next) { - dprintf(" safApp=%s\n", getSaNameT(&app->name)); - dprintf(" admin state: %s\n", admin_state_text[app->saAmfApplicationAdminState]); - dprintf(" num_sg: %d\n", app->saAmfApplicationCurrNumSG); - for (sg = app->sg_head; sg != NULL; sg = sg->next) { - dprintf(" safSG=%s\n", getSaNameT(&sg->name)); - dprintf(" admin state: %s\n", admin_state_text[sg->saAmfSGAdminState]); - dprintf(" assigned SUs %d\n", sg->saAmfSGNumCurrAssignedSUs); - dprintf(" non inst. spare SUs %d\n", sg->saAmfSGNumCurrNonInstantiatedSpareSUs); - dprintf(" inst. spare SUs %d\n", sg->saAmfSGNumCurrInstantiatedSpareSUs); - for (su = sg->su_head; su != NULL; su = su->next) { - dprintf(" safSU=%s\n", getSaNameT(&su->name)); - dprintf(" oper state: %s\n", oper_state_text[su->saAmfSUOperState]); - dprintf(" admin state: %s\n", admin_state_text[su->saAmfSUAdminState]); - dprintf(" readiness state: %s\n", readiness_state_text[su->saAmfSUReadinessState]); - dprintf(" presence state: %s\n", presence_state_text[su->saAmfSUPresenceState]); - dprintf(" hosted by node %s\n", su->saAmfSUHostedByNode.value); - dprintf(" num active SIs %d\n", su->saAmfSUNumCurrActiveSIs); - dprintf(" num standby SIs %d\n", su->saAmfSUNumCurrStandbySIs); - dprintf(" restart count %d\n", su->saAmfSURestartCount); - dprintf(" escalation level %d\n", su->escalation_level); - dprintf(" SU failover cnt %d\n", su->su_failover_cnt); - dprintf(" assigned SIs:"); - for (si_assignment = su->assigned_sis; si_assignment != NULL; - si_assignment = si_assignment->next) { - dprintf(" safSi=%s\n", si_assignment->si->name.value); - dprintf(" HA state: %s\n", - ha_state_text[si_assignment->saAmfSISUHAState]); - } - for (comp = su->comp_head; comp != NULL; comp = comp->next) { - dprintf(" safComp=%s\n", getSaNameT(&comp->name)); - dprintf(" oper state: %s\n", - oper_state_text[comp->saAmfCompOperState]); - dprintf(" readiness state: %s\n", - readiness_state_text[comp->saAmfCompReadinessState]); - dprintf(" presence state: %s\n", - presence_state_text[comp->saAmfCompPresenceState]); - dprintf(" num active CSIs %d\n", - comp->saAmfCompNumCurrActiveCsi); - dprintf(" num standby CSIs %d\n", - comp->saAmfCompNumCurrStandbyCsi); - dprintf(" restart count %d\n", comp->saAmfCompRestartCount); - dprintf(" assigned CSIs:"); - for (csi_assignment = comp->assigned_csis; csi_assignment != NULL; - csi_assignment = csi_assignment->comp_next) { - dprintf(" safCSI=%s\n", csi_assignment->csi->name.value); - dprintf(" HA state: %s\n", - ha_state_text[csi_assignment->saAmfCSICompHASate]); - } - } - } - } - for (si = app->si_head; si != NULL; si = si->next) { - dprintf(" safSi=%s\n", getSaNameT(&si->name)); - dprintf(" admin state: %s\n", admin_state_text[si->saAmfSIAdminState]); - dprintf(" assignm. state: %s\n", assignment_state_text[si->saAmfSIAssignmentState]); - dprintf(" active assignments: %d\n", si->saAmfSINumCurrActiveAssignments); - dprintf(" standby assignments: %d\n", si->saAmfSINumCurrStandbyAssignments); - for (csi = si->csi_head; csi != NULL; csi = csi->next) { - dprintf(" safCsi=%s\n", getSaNameT(&csi->name)); - } - } - } - dprintf("==================================================="); + ENTER(""); } -/* to be removed... */ -static int amf_enabled (struct objdb_iface_ver0 *objdb) +static int amf_sync_process (void) { - unsigned int object_service_handle; - char *value; - int enabled = 0; + ENTER(""); + return 0; /* ready */ +} - objdb->object_find_reset (OBJECT_PARENT_HANDLE); - if (objdb->object_find ( - OBJECT_PARENT_HANDLE, - "amf", - strlen ("amf"), - &object_service_handle) == 0) { +static void amf_sync_abort (void) +{ + ENTER(""); +} - value = NULL; - if ( !objdb->object_key_get (object_service_handle, - "mode", - strlen ("mode"), - (void *)&value, - NULL) && value) { - - if (strcmp (value, "enabled") == 0) { - enabled = 1; - } else - if (strcmp (value, "disabled") == 0) { - enabled = 0; - } - } - } - - return enabled; +static void amf_sync_activate (void) +{ + ENTER(""); } static int amf_exec_init_fn (struct objdb_iface_ver0 *objdb) @@ -1112,16 +396,19 @@ static int amf_exec_init_fn (struct objdb_iface_ver0 *objdb) } if (this_amf_node != NULL) { - this_amf_node->saAmfNodeOperState = SA_AMF_OPERATIONAL_ENABLED; + amf_cluster_init(); + amf_application_init(); + amf_sg_init(); + amf_su_init(); + amf_comp_init(); + amf_si_init(); - /* wait a while before starting applications as the AMF spec. says. */ - openais_timer_add( - amf_cluster.saAmfClusterStartupTimeout, - NULL, - cluster_start_applications, - &amf_cluster.timeout_handle); + this_amf_node->saAmfNodeOperState = SA_AMF_OPERATIONAL_ENABLED; + amf_cluster_start (&amf_cluster); } else { - log_printf (LOG_LEVEL_INFO, "This CLM node (%s) is not configured as an AMF node, disabling...", hostname); + log_printf (LOG_LEVEL_INFO, + "This CLM node (%s) is not configured as an AMF node, disabling.", + hostname); } return (0); @@ -1134,35 +421,9 @@ static void amf_confchg_fn ( unsigned int *joined_list, int joined_list_entries, struct memb_ring_id *ring_id) { -#ifdef COMPILE_OUT - - int i; - - log_printf (LOG_LEVEL_FROM_GMI, "Executive: amf_confchg_fn : type = %d,mnum = %d,jnum = %d,lnum = %d\n", configuration_type,member_list_entries,joined_list_entries,left_list_entries); - - recovery = 1; - /* - * If node join, component register - */ - if ( joined_list_entries > 0 ) { - enumerate_components (amf_confchg_njoin, NULL); - } - - /* - * If node leave, component unregister - */ - for (i = 0; inext) { - - conn_info = list_entry (list, struct conn_info, conn_list); - for (i = 0; i < conn_info->ais_ci.u.libamf_ci.trackEntries; i++) { - if (conn_info->ais_ci.u.libamf_ci.tracks[i].active) { - - if (conn_info->ais_ci.u.libamf_ci.tracks[i].csiName.length - != changedComponent->amf_pg->name.length) { - continue; - } - if (memcmp (conn_info->ais_ci.u.libamf_ci.tracks[i].csiName.value, - changedComponent->amf_pg->name.value, - conn_info->ais_ci.u.libamf_ci.tracks[i].csiName.length)) { - continue; - } - -#ifdef COMPILE_OUT - protectiongroup_notification_send (conn_info, - conn_info->ais_ci.u.libamf_ci.tracks[i].notificationBufferAddress, - changedComponent->saAmfProtectionGroup, - changedComponent, - changeToComponent, - conn_info->ais_ci.u.libamf_ci.tracks[i].trackFlags); -#endif - - } /* if track flags active */ - } /* for all track entries */ - } /* for all connection entries */ -} -#endif - -#ifdef COMPILE_OUT -static int make_protectiongroup_notification_allcomponent ( - struct amf_comp *changedComponent, - SaAmfProtectionGroupChangesT changeToComponent, - SaAmfProtectionGroupNotificationT **notification ) -{ - SaAmfProtectionGroupNotificationT *protectionGroupNotification = 0; - int notifyEntries = 0; - struct amf_comp *component; - struct list_head *AmfGroupList; - struct list_head *AmfUnitList; - struct list_head *AmfComponentList; - struct saAmfGroup *saAmfGroup; - struct saAmfUnit *AmfUnit; - - for (AmfGroupList = saAmfGroupHead.next; AmfGroupList != &saAmfGroupHead; AmfGroupList = AmfGroupList->next) { - - saAmfGroup = list_entry (AmfGroupList, struct saAmfGroup, saAmfGroupList); - /* - * Search all units - */ - for (AmfUnitList = saAmfGroup->saAmfUnitHead.next; - AmfUnitList != &saAmfGroup->saAmfUnitHead; - AmfUnitList = AmfUnitList->next) { - - AmfUnit = list_entry (AmfUnitList, struct saAmfUnit, saAmfUnitList); - - /* - * Search all components - */ - for (AmfComponentList = AmfUnit->amf_compHead.next; - AmfComponentList != &AmfUnit->amf_compHead; - AmfComponentList = AmfComponentList->next) { - - component = list_entry (AmfComponentList, struct amf_comp, amf_compList); - - protectionGroupNotification = - (SaAmfProtectionGroupNotificationT *)mempool_realloc (protectionGroupNotification, - sizeof (SaAmfProtectionGroupNotificationT) * (notifyEntries + 1)); - memset (&protectionGroupNotification[notifyEntries], - 0,sizeof (SaAmfProtectionGroupNotificationT)); - memcpy (&protectionGroupNotification[notifyEntries].member.compName, - &component->name, sizeof (SaNameT)); -// memcpy (&protectionGroupNotification[notifyEntries].member.readinessState, -// &component->currentReadinessState, sizeof (SaAmfReadinessStateT)); - memcpy (&protectionGroupNotification[notifyEntries].member.haState, - &component->currentHAState, sizeof (SaAmfHAStateT)); - if (component == changedComponent) { - protectionGroupNotification[notifyEntries].change = changeToComponent; - } else { - protectionGroupNotification[notifyEntries].change - = SA_AMF_PROTECTION_GROUP_NO_CHANGE; - } - notifyEntries += 1; - } - } - } - - if (notifyEntries) { - *notification = protectionGroupNotification; - } - return (notifyEntries); -} -#endif - -#ifdef COMPILE_OUT -static int make_protectiongroup_notification ( - struct saAmfProtectionGroup *amfProtectionGroup, - struct amf_comp *changedComponent, - SaAmfProtectionGroupChangesT changeToComponent, - SaAmfProtectionGroupNotificationT **notification ) -{ - struct res_lib_amf_protectiongrouptrackcallback res_lib_amf_protectiongrouptrackcallback; - int notifyEntries = 0; - struct amf_comp *component; - struct list_head *componentList; - SaAmfProtectionGroupNotificationT *protectionGroupNotification = 0; - - memset (&res_lib_amf_protectiongrouptrackcallback,0,sizeof(res_lib_amf_protectiongrouptrackcallback)); - for (componentList = amfProtectionGroup->saAmfMembersHead.next; - componentList != &amfProtectionGroup->saAmfMembersHead; - componentList = componentList->next) { - - component = list_entry (componentList, struct amf_comp, saAmfProtectionGroupList); - - protectionGroupNotification = - (SaAmfProtectionGroupNotificationT *)mempool_realloc (protectionGroupNotification, - sizeof (SaAmfProtectionGroupNotificationT) * (notifyEntries + 1)); - memset (&protectionGroupNotification[notifyEntries],0,sizeof (SaAmfProtectionGroupNotificationT)); - memcpy (&protectionGroupNotification[notifyEntries].member.compName, - &component->name, sizeof (SaNameT)); - // memcpy (&protectionGroupNotification[notifyEntries].member.readinessState, - // &component->currentReadinessState, sizeof (SaAmfReadinessStateT)); - memcpy (&protectionGroupNotification[notifyEntries].member.haState, - &component->currentHAState, sizeof (SaAmfHAStateT)); - if (component == changedComponent) { - protectionGroupNotification[notifyEntries].change = changeToComponent; - } else { - protectionGroupNotification[notifyEntries].change = SA_AMF_PROTECTION_GROUP_NO_CHANGE; - } - notifyEntries += 1; - } /* for */ - - if (notifyEntries) { - *notification = protectionGroupNotification; - } - - return (notifyEntries); - return (0); -} -#endif - -#ifdef COMPILE_OUT -static void protectiongroup_notification_send (struct conn_info *conn_info, - SaAmfProtectionGroupNotificationT *notificationBufferAddress, - struct saAmfProtectionGroup *amfProtectionGroup, - struct amf_comp *changedComponent, - SaAmfProtectionGroupChangesT changeToComponent, - SaUint8T trackFlags) -{ - //struct res_lib_amf_protectiongrouptrackcallback res_lib_amf_protectiongrouptrackcallback; - SaAmfProtectionGroupNotificationT *protectionGroupNotification = 0; - int notifyEntries; - - /* - * Step through all components and generate protection group list for csi - */ - memset (&res_lib_amf_protectiongrouptrackcallback, 0, sizeof(res_lib_amf_protectiongrouptrackcallback)); - if ( trackFlags == SA_TRACK_CHANGES ) { - notifyEntries = make_protectiongroup_notification_allcomponent (changedComponent, - changeToComponent, &protectionGroupNotification); - - }else if (trackFlags == SA_TRACK_CHANGES_ONLY) { - notifyEntries = make_protectiongroup_notification (amfProtectionGroup, - changedComponent, changeToComponent, &protectionGroupNotification ); - }else{ - notifyEntries = 0; - } - - /* - * Send track callback - */ - if (notifyEntries) { - res_lib_amf_protectiongrouptrackcallback.header.size = - sizeof (struct res_lib_amf_protectiongrouptrackcallback) + - (notifyEntries * sizeof (SaAmfProtectionGroupNotificationT)); -// res_lib_amf_protectiongrouptrackcallback.header.id = MESSAGE_RES_AMF_PROTECTIONGROUPTRACKCALLBACK; - res_lib_amf_protectiongrouptrackcallback.header.error = SA_AIS_OK; - res_lib_amf_protectiongrouptrackcallback.numberOfItems = notifyEntries; - res_lib_amf_protectiongrouptrackcallback.numberOfMembers = notifyEntries; - memcpy (&res_lib_amf_protectiongrouptrackcallback.csiName, - &amfProtectionGroup->name, sizeof (SaNameT)); - - res_lib_amf_protectiongrouptrackcallback.notificationBufferAddress = notificationBufferAddress; - openais_conn_send_response (conno, &res_lib_amf_protectiongrouptrackcallback, - sizeof (struct res_lib_amf_protectiongrouptrackcallback)); - - openais_conn_send_response (conno, protectionGroupNotification, - sizeof (SaAmfProtectionGroupNotificationT) * notifyEntries); - - mempool_free (protectionGroupNotification); - } -} - -#endif - -#define INVOCATION_DONT_COMPARE 0xFFFFFFFFULL -#if 0 -static struct healthcheck_active *find_healthcheck_active ( - struct amf_comp *comp, - SaAmfHealthcheckKeyT *key, - SaAmfHealthcheckInvocationT invocation) -{ - struct list_head *list; - struct healthcheck_active *ret_healthcheck_active = 0; - struct healthcheck_active *healthcheck_active; - - for (list = comp->healthcheck_head.next; - list != &comp->healthcheck_head; - list = list->next) { - - healthcheck_active = list_entry (list, - struct healthcheck_active, list); - - if ((memcmp (key, &healthcheck_active->key, - sizeof (SaAmfHealthcheckKeyT)) == 0) && - - (invocation == INVOCATION_DONT_COMPARE || - healthcheck_active->invocationType == invocation)) { - - ret_healthcheck_active = healthcheck_active; - break; - } - } - return (ret_healthcheck_active); -} - -static void comp_healthcheck_activate (struct amf_comp *comp) -{ - struct amf_healthcheck *healthcheck; - - if (!comp->is_local) - return; - - for (healthcheck = comp->healthcheck_head; - healthcheck != NULL; - healthcheck = healthcheck->next) { - - if (healthcheck->active == 0) { - healthcheck_activate (healthcheck); - } - } -} -#endif - -static void comp_healthcheck_deactivate ( - struct amf_comp *comp) -{ - struct amf_healthcheck *healthcheck; - - if (!comp->su->is_local) - return; - - ENTER ("'%s'\n", getSaNameT (&comp->name)); - - for (healthcheck = comp->healthcheck_head; - healthcheck != NULL; - healthcheck = healthcheck->next) { - - if (healthcheck->active) { - healthcheck_deactivate (healthcheck); - } - } -} - -static void comp_presence_state_set (struct amf_comp *comp, - SaAmfPresenceStateT presence_state) -{ - comp->saAmfCompPresenceState = presence_state; - TRACE1 ("Setting comp '%s' presence state: %s\n", - comp->name.value, presence_state_text[comp->saAmfCompPresenceState]); - - /* - * If all comp presence states are INSTANTIATED, then SU should be instantated - */ - if ((presence_state == SA_AMF_PRESENCE_INSTANTIATED) && - presence_state_all_comps_in_su_are_set (comp->su, SA_AMF_PRESENCE_INSTANTIATED)) { - - su_presence_state_set (comp->su, SA_AMF_PRESENCE_INSTANTIATED); - } -} - -static void comp_readiness_state_set (struct amf_comp *comp) -{ - /* - * Set component readiness state appropriately - * if unit in service and component is enabled, it is in service - * otherwise it is out of service page 50 B.02.01 - */ - if (comp->su->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE && - comp->saAmfCompOperState == SA_AMF_OPERATIONAL_ENABLED) { - comp->saAmfCompReadinessState = SA_AMF_READINESS_IN_SERVICE; - } else if (comp->su->saAmfSUReadinessState == SA_AMF_READINESS_STOPPING && - comp->saAmfCompOperState == SA_AMF_OPERATIONAL_ENABLED) { - comp->saAmfCompReadinessState = SA_AMF_READINESS_STOPPING; - } else { - comp->saAmfCompReadinessState = SA_AMF_READINESS_OUT_OF_SERVICE; - } - TRACE1 ("Setting comp '%s' readiness state: %s\n", - comp->name.value, readiness_state_text[comp->saAmfCompReadinessState]); -} - -static void comp_operational_state_set (struct amf_comp *comp, - SaAmfOperationalStateT oper_state) -{ - struct amf_comp *comp_compare; - int all_set; - - comp->saAmfCompOperState = oper_state; - TRACE1 ("Setting comp '%s' operational state: %s\n", - comp->name.value, oper_state_text[comp->saAmfCompOperState]); - - /* - * If all operational states are ENABLED, then SU should be ENABLED - */ - if (oper_state == SA_AMF_OPERATIONAL_ENABLED) { - all_set = 1; - for (comp_compare = comp->su->comp_head; comp_compare != NULL; comp_compare = comp->next) { - if (comp_compare->saAmfCompOperState != SA_AMF_OPERATIONAL_ENABLED) { - all_set = 0; - break; - } - } - if (all_set) { - su_operational_state_set (comp->su, SA_AMF_OPERATIONAL_ENABLED); - } else { - su_operational_state_set (comp->su, SA_AMF_OPERATIONAL_DISABLED); - } - } -} - -static void comp_csi_set_callback ( - struct amf_comp *comp, - struct amf_csi_assignment *csi_assignment) -{ - struct res_lib_amf_csisetcallback* res_lib_amf_csisetcallback; - void* p; - struct amf_csi_attribute *attribute; - size_t char_length_of_csi_attrs=0; - size_t num_of_csi_attrs=0; - int i; - struct amf_csi *csi = csi_assignment->csi; - int ha_state = csi_assignment->saAmfCSICompHASate; - - if (!comp->su->is_local) - return; - - dprintf("\t Assigning CSI '%s' state %s to comp '%s'\n", - getSaNameT (&csi->name), ha_state_text[ha_state], comp->name.value); - - for (attribute = csi->attributes_head; - attribute != NULL; - attribute = attribute->next) { - for (i = 0; attribute->value[i] != NULL; i++) { - num_of_csi_attrs++; - char_length_of_csi_attrs += strlen(attribute->name); - char_length_of_csi_attrs += strlen(attribute->value[i]); - char_length_of_csi_attrs += 2; - } - } - p = malloc(sizeof(struct res_lib_amf_csisetcallback)+ - char_length_of_csi_attrs); - if (p == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - - res_lib_amf_csisetcallback = (struct res_lib_amf_csisetcallback*)p; - - /* Address of the buffer containing the Csi name value pair */ - char* csi_attribute_buf = res_lib_amf_csisetcallback->csi_attr_buf; - - /* Byteoffset start at the zero byte */ - unsigned int byte_offset = 0; - - for (attribute = csi->attributes_head; - attribute != NULL; - attribute = attribute->next) { - - for (i = 0; attribute->value[i] != NULL; i++) { - strcpy(&csi_attribute_buf[byte_offset], (char*)attribute->name); - byte_offset += strlen(attribute->name) + 1; - strcpy(&csi_attribute_buf[byte_offset], (char*)attribute->value[i]); - byte_offset += strlen(attribute->value[i]) + 1; - } - } - - res_lib_amf_csisetcallback->number = num_of_csi_attrs; - res_lib_amf_csisetcallback->csiFlags = SA_AMF_CSI_ADD_ONE; - - switch (ha_state) { - case SA_AMF_HA_ACTIVE: { - res_lib_amf_csisetcallback->csiStateDescriptor.activeDescriptor.activeCompName.length = 0; - res_lib_amf_csisetcallback->csiStateDescriptor.activeDescriptor.transitionDescriptor = - SA_AMF_CSI_NEW_ASSIGN; - break; - } - case SA_AMF_HA_STANDBY: { - res_lib_amf_csisetcallback->csiStateDescriptor.standbyDescriptor.activeCompName.length = 0; - res_lib_amf_csisetcallback->csiStateDescriptor.standbyDescriptor.standbyRank = 1; - break; - } - case SA_AMF_HA_QUIESCED: { - /*TODO*/ - break; - } - case SA_AMF_HA_QUIESCING: { - /*TODO*/ - break; - } - default: { - assert(SA_AMF_HA_ACTIVE||SA_AMF_HA_STANDBY||SA_AMF_HA_QUIESCING||SA_AMF_HA_QUIESCED); - break; - } - } - - res_lib_amf_csisetcallback->header.id = MESSAGE_RES_AMF_CSISETCALLBACK; - res_lib_amf_csisetcallback->header.size = - sizeof (struct res_lib_amf_csisetcallback)+ - char_length_of_csi_attrs; - res_lib_amf_csisetcallback->header.error = SA_AIS_OK; - - comp_dn_make (comp, &res_lib_amf_csisetcallback->compName); - csi_dn_make (csi, &res_lib_amf_csisetcallback->csiName); - - res_lib_amf_csisetcallback->haState = ha_state; - res_lib_amf_csisetcallback->invocation = - invocation_create (AMF_RESPONSE_CSISETCALLBACK, csi_assignment); - - openais_conn_send_response (openais_conn_partner_get (comp->conn), - res_lib_amf_csisetcallback, - res_lib_amf_csisetcallback->header.size); - - free(p); -} -#if 0 -static void pg_create (struct amf_si *si, struct amf_pg **pg_out) -{ - struct amf_pg *pg; -// struct amf_pg_comp *pg_comp; - - pg = malloc (sizeof (struct amf_pg)); - assert (pg); - list_init (&pg->pg_comp_head); - list_init (&pg->pg_list); - list_add (&pg->pg_list, &si->pg_head); - *pg_out = pg; -} -#endif - -#if 0 -static void csi_comp_remove_callback (struct amf_comp *comp, struct amf_csi *csi) -{ - struct res_lib_amf_csiremovecallback res_lib_amf_csiremovecallback; - struct csi_remove_callback_data *csi_remove_callback_data; - - dprintf ("\t%s\n", - getSaNameT (&comp->name)); - - res_lib_amf_csiremovecallback.header.id = MESSAGE_RES_AMF_CSIREMOVECALLBACK; - res_lib_amf_csiremovecallback.header.size = sizeof (struct res_lib_amf_csiremovecallback); - res_lib_amf_csiremovecallback.header.error = SA_AIS_OK; - - csi_remove_callback_data = malloc (sizeof (struct csi_remove_callback_data)); - assert (csi_remove_callback_data); // TODO failure here of malloc - csi_remove_callback_data->csi = csi; - - res_lib_amf_csiremovecallback.invocation = - invocation_create ( - AMF_RESPONSE_CSIREMOVECALLBACK, - csi_remove_callback_data); - - memcpy (&res_lib_amf_csiremovecallback.compName, - &comp->name, sizeof (SaNameT)); - - memcpy (&res_lib_amf_csiremovecallback.csiName, - &csi->name, sizeof (SaNameT)); - - res_lib_amf_csiremovecallback.csiFlags = 0; - - openais_conn_send_response ( - openais_conn_partner_get (comp->conn), - &res_lib_amf_csiremovecallback, - sizeof (struct res_lib_amf_csiremovecallback)); - -} -#endif - -static void cluster_assign_workload (void *data) -{ - struct amf_application *app; - struct amf_sg *sg; - - dprintf("2nd Cluster start timer expired, assigning SIs\n"); - - for (app = amf_cluster.application_head; app != NULL; app = app->next) { - for (sg = app->sg_head; sg != NULL; sg = sg->next) { - sg_assign_si (sg); - } - } -} - -static void cluster_start_applications (void *data) -{ - struct amf_application *app; - struct amf_sg *sg; - struct amf_su *su; - - dprintf("1st Cluster start timer expired, instantiating SUs"); - - for (app = amf_cluster.application_head; app != NULL; app = app->next) { - for (sg = app->sg_head; sg != NULL; sg = sg->next) { - for (su = sg->su_head; su != NULL; su = su->next) { - /* Only start SUs configured to this node */ - if (name_match (&this_amf_node->name, - &su->saAmfSUHostedByNode )) { - su->is_local = 1; - clc_su_instantiate (su); - } - } - } - } - - /* wait a while before assigning SIs as the AMF spec. says. */ - openais_timer_add( - amf_cluster.saAmfClusterStartupTimeout, - NULL, - cluster_assign_workload, - &amf_cluster.timeout_handle); -} - -#if 0 -static void comp_terminate (struct amf_comp *comp) -{ - clc_terminate (comp); -} - -static void unit_terminate (struct amf_su *unit) -{ - struct amf_comp *comp; - - for (comp = unit->comp_head; comp != NULL; comp = comp->next) { - clc_terminate (comp); - } -} -#endif - -static void comp_cleanup (struct amf_comp *comp) -{ - clc_cleanup (comp); -} - -static void su_cleanup (struct amf_su *unit) -{ - struct amf_comp *comp; - - for (comp = unit->comp_head; comp != NULL; comp = comp->next) { - clc_cleanup (comp); - } -} - -static void comp_restart (struct amf_comp *comp) -{ - comp_presence_state_set (comp, SA_AMF_PRESENCE_RESTARTING); -} - -static void comp_reassign_csis (struct amf_comp *comp) -{ - struct amf_csi_assignment *csi_assignment = comp->assigned_csis; - - ENTER ("'%s'", comp->name.value); - - for (; csi_assignment; csi_assignment = csi_assignment->comp_next) { - comp_csi_set_callback (comp, csi_assignment); - } -} - -#if 0 -static void unit_restart (struct amf_su *unit) -{ - struct amf_comp *comp; - - for (comp = unit->comp_head; comp != NULL; comp = comp->next) { - comp_presence_state_set (comp, SA_AMF_PRESENCE_RESTARTING); - } -} -#endif - -static void clc_su_instantiate (struct amf_su *unit) -{ - struct amf_comp *comp; - - for (comp = unit->comp_head; comp != NULL; comp = comp->next) { - clc_instantiate (comp); - } -} - -static void comp_assign_csi (struct amf_comp *comp, struct amf_csi *csi, - SaAmfHAStateT ha_state) -{ - struct amf_csi_assignment *csi_assignment; - - dprintf (" Assigning CSI '%s' to comp '%s' with hastate %s\n", - getSaNameT (&csi->name), getSaNameT (&comp->name), - ha_state_text[ha_state]); - - csi_assignment = malloc (sizeof (struct amf_csi_assignment)); - if (csi_assignment == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - - csi_assignment->comp_next = comp->assigned_csis; - comp->assigned_csis = csi_assignment; - setSaNameT (&csi_assignment->name, (char*)comp->name.value); - csi_assignment->saAmfCSICompHASate = ha_state; - csi_assignment->csi = csi; - csi_assignment->comp = comp; - csi_assignment->saAmfCSICompHASate = ha_state; - - if (ha_state == SA_AMF_HA_ACTIVE) - comp->saAmfCompNumCurrActiveCsi++; - else if (ha_state == SA_AMF_HA_STANDBY) - comp->saAmfCompNumCurrStandbyCsi++; - else - assert (0); - - comp_csi_set_callback (comp, csi_assignment); -} - -static void su_assign_si (struct amf_su *su, struct amf_si *si, - SaAmfHAStateT ha_state) -{ - struct amf_si_assignment *si_assignment; - - dprintf ("Assigning SI '%s' to SU '%s' with hastate %s\n", - getSaNameT (&si->name), getSaNameT (&su->name), - ha_state_text[ha_state]); - - si_assignment = malloc (sizeof (struct amf_si_assignment)); - if (si_assignment == NULL) { - openais_exit_error (AIS_DONE_OUT_OF_MEMORY); - } - setSaNameT (&si_assignment->name, (char*)su->name.value); - si_assignment->saAmfSISUHAState = ha_state; - si_assignment->next = su->assigned_sis; - su->assigned_sis = si_assignment; - si_assignment->si = si; - - if (ha_state == SA_AMF_HA_ACTIVE) { - si->saAmfSINumCurrActiveAssignments++; - su->saAmfSUNumCurrActiveSIs++; - } else if (ha_state == SA_AMF_HA_STANDBY) { - su->saAmfSUNumCurrStandbySIs++; - si->saAmfSINumCurrStandbyAssignments++; - } else - assert(0); - - if ((si->saAmfSINumCurrActiveAssignments == si->saAmfSIPrefActiveAssignments) && - (si->saAmfSINumCurrStandbyAssignments == si->saAmfSIPrefStandbyAssignments)) { - si->saAmfSIAssignmentState = SA_AMF_ASSIGNMENT_FULLY_ASSIGNED; - } else if ((si->saAmfSINumCurrActiveAssignments < si->saAmfSIPrefActiveAssignments) || - (si->saAmfSINumCurrStandbyAssignments < si->saAmfSIPrefStandbyAssignments)) { - si->saAmfSIAssignmentState = SA_AMF_ASSIGNMENT_PARTIALLY_ASSIGNED; - } - - { - struct amf_csi *csi; - struct amf_comp *comp; - SaNameT *cs_type; - int i; - - /* - ** for each component in SU, find a CSI in the SI with the same type - */ - for (comp = su->comp_head; comp != NULL; comp = comp->next) { - int no_of_cs_types = 0; - for (i = 0; comp->saAmfCompCsTypes[i]; i++) { - cs_type = comp->saAmfCompCsTypes[i]; - no_of_cs_types++; - int no_of_assignments = 0; - - for (csi = si->csi_head; csi != NULL; csi = csi->next) { - if (!memcmp(csi->saAmfCSTypeName.value, cs_type->value, cs_type->length)) { - comp_assign_csi (comp, csi, ha_state); - no_of_assignments++; - } - } - if (no_of_assignments == 0) { - log_printf (LOG_WARNING, "\t No CSIs of type %s configured?!!\n", - getSaNameT (cs_type)); - } - } - if (no_of_cs_types == 0) { - log_printf (LOG_LEVEL_ERROR, "\t No CS types configured for comp %s ?!!\n", - getSaNameT (&comp->name)); - } - } - } -} - -static int su_inservice_count_get (struct amf_sg *sg) -{ - struct amf_su *unit; - int answer = 0; - - for (unit = sg->su_head; unit != NULL; unit = unit->next) { - if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE) { - answer += 1; - } - } - return (answer); -} #if 0 static int comp_inservice_count (struct amf_su *unit) { @@ -1935,440 +464,6 @@ static int comp_inservice_count (struct amf_su *unit) } #endif -static int application_si_count_get (struct amf_application *app) -{ - struct amf_si *si; - int answer = 0; - - for (si = app->si_head; si != NULL; si = si->next) { - answer += 1; - } - return (answer); -} - - -static inline int div_round (int a, int b) -{ - int res; - - res = a / b; - if ((a % b) != 0) - res++; - return res; -} - - -static void sg_assign_nm_active (struct amf_sg *sg, int su_units_assign) -{ - struct amf_su *unit; - struct amf_si *si; - int assigned = 0; - int assign_per_su = 0; - int total_assigned = 0; - - assign_per_su = application_si_count_get (sg->application); - assign_per_su = div_round (assign_per_su, su_units_assign); - if (assign_per_su > sg->saAmfSGMaxActiveSIsperSUs) { - assign_per_su = sg->saAmfSGMaxActiveSIsperSUs; - } - - si = sg->application->si_head; - unit = sg->su_head; - while (unit != NULL) { - if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE || - unit->saAmfSUNumCurrActiveSIs == sg->saAmfSGMaxActiveSIsperSUs || - unit->saAmfSUNumCurrStandbySIs > 0) { - - unit = unit->next; - continue; /* Not in service */ - } - - assigned = 0; - while (si != NULL && - assigned < assign_per_su && - total_assigned < application_si_count_get (sg->application)) { - - assigned += 1; - total_assigned += 1; - su_assign_si (unit, si, SA_AMF_HA_ACTIVE); - si = si->next; - } - unit = unit->next; - } - - if (total_assigned == 0) { - dprintf ("Error: No SIs assigned!"); - } -} - -static void sg_assign_nm_standby (struct amf_sg *sg, int units_assign_standby) -{ - struct amf_su *unit; - struct amf_si *si; - int assigned = 0; - int assign_per_su = 0; - int total_assigned = 0; - - if (units_assign_standby == 0) { - return; - } - assign_per_su = application_si_count_get (sg->application); - assign_per_su = div_round (assign_per_su, units_assign_standby); - if (assign_per_su > sg->saAmfSGMaxStandbySIsperSUs) { - assign_per_su = sg->saAmfSGMaxStandbySIsperSUs; - } - - si = sg->application->si_head; - unit = sg->su_head; - while (unit != NULL) { - if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE || - unit->saAmfSUNumCurrActiveSIs > 0 || - unit->saAmfSUNumCurrStandbySIs == sg->saAmfSGMaxStandbySIsperSUs) { - - unit = unit->next; - continue; /* Not available for assignment */ - } - - assigned = 0; - while (si != NULL && assigned < assign_per_su) { - assigned += 1; - total_assigned += 1; - su_assign_si (unit, si, SA_AMF_HA_STANDBY); - si = si->next; - } - unit = unit->next; - } - if (total_assigned == 0) { - dprintf ("Error: No SIs assigned!"); - } -} -#if 0 -static void assign_nm_spare (struct amf_sg *sg) -{ - struct amf_su *unit; - - for (unit = sg->su_head; unit != NULL; unit = unit->next) { - if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE && - (unit->requested_ha_state != SA_AMF_HA_ACTIVE && - unit->requested_ha_state != SA_AMF_HA_STANDBY)) { - - dprintf ("Assigning to SU %s with SPARE\n", - getSaNameT (&unit->name)); - } - } -} -#endif - -static void sg_assign_si (struct amf_sg *sg) -{ - int active_sus_needed; - int standby_sus_needed; - int inservice_count; - int units_for_standby; - int units_for_active; - int ii_spare; - int su_active_assign; - int su_standby_assign; - int su_spare_assign; - - ENTER ("'%s'", sg->name.value); - /* - * Number of SUs to assign to active or standby state - */ - inservice_count = (float)su_inservice_count_get (sg); - - active_sus_needed = div_round (application_si_count_get (sg->application), - sg->saAmfSGMaxActiveSIsperSUs); - - standby_sus_needed = div_round (application_si_count_get (sg->application), - sg->saAmfSGMaxStandbySIsperSUs); - - units_for_active = inservice_count - sg->saAmfSGNumPrefStandbySUs; - if (units_for_active < 0) { - units_for_active = 0; - } - - units_for_standby = inservice_count - sg->saAmfSGNumPrefActiveSUs; - if (units_for_standby < 0) { - units_for_standby = 0; - } - - ii_spare = inservice_count - sg->saAmfSGNumPrefActiveSUs - sg->saAmfSGNumPrefStandbySUs; - if (ii_spare < 0) { - ii_spare = 0; - } - - /* - * Determine number of active and standby service units - * to assign based upon reduction procedure - */ - if ((inservice_count - active_sus_needed) < 0) { - dprintf ("assignment VI - partial assignment with SIs drop outs\n"); - - su_active_assign = active_sus_needed; - su_standby_assign = 0; - su_spare_assign = 0; - } else - if ((inservice_count - active_sus_needed - standby_sus_needed) < 0) { - dprintf ("assignment V - partial assignment with reduction of standby units\n"); - - su_active_assign = active_sus_needed; - if (standby_sus_needed > units_for_standby) { - su_standby_assign = units_for_standby; - } else { - su_standby_assign = standby_sus_needed; - } - su_spare_assign = 0; - } else - if ((sg->saAmfSGMaxStandbySIsperSUs * units_for_standby) <= application_si_count_get (sg->application)) { - dprintf ("IV: full assignment with reduction of active service units\n"); - su_active_assign = inservice_count - standby_sus_needed; - su_standby_assign = standby_sus_needed; - su_spare_assign = 0; - } else - if ((sg->saAmfSGMaxActiveSIsperSUs * units_for_active) <= application_si_count_get (sg->application)) { - - dprintf ("III: full assignment with reduction of standby service units\n"); - su_active_assign = sg->saAmfSGNumPrefActiveSUs; - su_standby_assign = units_for_standby; - su_spare_assign = 0; - } else - if (ii_spare == 0) { - dprintf ("II: full assignment with spare reduction\n"); - - su_active_assign = sg->saAmfSGNumPrefActiveSUs; - su_standby_assign = sg->saAmfSGNumPrefStandbySUs; - su_spare_assign = 0; - } else { - dprintf ("I: full assignment with spares\n"); - - su_active_assign = sg->saAmfSGNumPrefActiveSUs; - su_standby_assign = sg->saAmfSGNumPrefStandbySUs; - su_spare_assign = ii_spare; - } - - dprintf ("(inservice=%d) (assigning active=%d) (assigning standby=%d) (assigning spares=%d)\n", - inservice_count, su_active_assign, su_standby_assign, su_spare_assign); - sg_assign_nm_active (sg, su_active_assign); - sg_assign_nm_standby (sg, su_standby_assign); - LEAVE ("'%s'", sg->name.value); -} - -static int sg_all_su_in_service(struct amf_sg *sg) -{ - struct amf_su *su; - struct amf_comp *comp; - int ready = 1; - - for (su = sg->su_head; su != NULL; su = su->next) { - for (comp = su->comp_head; comp != NULL; comp = comp->next) { - if (su->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE) { - ready = 0; - } - } - } - - return ready; -} - -static void su_readiness_state_set (struct amf_su *su, - SaAmfReadinessStateT readiness_state) -{ - su->saAmfSUReadinessState = readiness_state; - TRACE1 ("Setting SU '%s' readiness state: %s\n", - &su->name.value, readiness_state_text[readiness_state]); -} - -static void su_presence_state_set (struct amf_su *su, - SaAmfPresenceStateT presence_state) -{ - su->saAmfSUPresenceState = presence_state; - TRACE1 ("Setting SU '%s' presence state: %s\n", - su->name.value, presence_state_text[presence_state]); -} - - -static void escalation_policy_restart (struct amf_comp *comp) -{ - dprintf ("escalation_policy_restart %d\n", comp->su->escalation_level); - dprintf ("escalation policy restart uninsint %p\n", comp); -// comp_presence_state_set (comp, SA_AMF_PRESENCE_UNINSTANTIATED); -// comp_operational_state_set (comp, SA_AMF_OPERATIONAL_DISABLED); - switch (comp->su->escalation_level) { - - case ESCALATION_LEVEL_NO_ESCALATION: - comp_restart (comp); - break; - - case ESCALATION_LEVEL_ONE: - comp_restart (comp); - break; - - case ESCALATION_LEVEL_TWO: - break; - - case ESCALATION_LEVEL_THREE: - break; - - } -} - -static void escalation_policy_cleanup (struct amf_comp *comp) -{ - -// escalation_timer_start (comp); - - switch (comp->su->escalation_level) { - case ESCALATION_LEVEL_NO_ESCALATION: - comp->saAmfCompRestartCount += 1; - if (comp->saAmfCompRestartCount >= comp->su->sg->saAmfSGCompRestartMax) { - comp->su->escalation_level = ESCALATION_LEVEL_ONE; - escalation_policy_cleanup (comp); - comp->saAmfCompRestartCount = 0; - return; - } - dprintf ("Escalation level 0 - restart component\n"); - dprintf ("Cleaning up and restarting component.\n"); - comp_cleanup (comp); - break; - - case ESCALATION_LEVEL_ONE: - comp->su->saAmfSURestartCount += 1; - if (comp->su->saAmfSURestartCount >= comp->su->sg->saAmfSGSuRestartMax) { - comp->su->escalation_level = ESCALATION_LEVEL_TWO; - escalation_policy_cleanup (comp); - comp->saAmfCompRestartCount = 0; - comp->su->saAmfSURestartCount = 0; - return; - } - dprintf ("Escalation level 1 - restart unit\n"); - dprintf ("Cleaning up and restarting unit.\n"); - su_cleanup (comp->su); - break; - - case ESCALATION_LEVEL_TWO: - dprintf ("Escalation level TWO\n"); - su_cleanup (comp->su); -// unit_terminate_failover (comp); - break; - - case ESCALATION_LEVEL_THREE: -//TODO - break; - } -} - -static void timer_function_healthcheck_timeout ( - void *data) -{ - struct req_exec_amf_healthcheck_tmo req_exec; - struct iovec iovec; - struct amf_healthcheck *healthcheck = (struct amf_healthcheck *)data; - - TRACE2 ("timeout occured on healthcheck for component %s.\n", - getSaNameT (&healthcheck->comp->name)); - req_exec.header.size = sizeof (struct req_exec_amf_healthcheck_tmo); - req_exec.header.id = SERVICE_ID_MAKE (AMF_SERVICE, - MESSAGE_REQ_EXEC_AMF_HEALTHCHECK_TMO); - - comp_dn_make (healthcheck->comp, &req_exec.compName); - iovec.iov_base = (char *)&req_exec; - iovec.iov_len = sizeof (req_exec); - - assert (totempg_groups_mcast_joined (openais_group_handle, - &iovec, 1, TOTEMPG_AGREED) == 0); -} - -static void healthcheck_activate (struct amf_healthcheck *healthcheck_active) -{ - struct res_lib_amf_healthcheckcallback res_lib_amf_healthcheckcallback; - - healthcheck_active->active = 1; - -// TODO memset (&res_lib_amf_healthcheckcallback, 0, sizeof(res_lib_amf_healthcheckcallback)); - res_lib_amf_healthcheckcallback.header.id = MESSAGE_RES_AMF_HEALTHCHECKCALLBACK; - res_lib_amf_healthcheckcallback.header.size = sizeof (struct res_lib_amf_healthcheckcallback); - res_lib_amf_healthcheckcallback.header.error = SA_AIS_OK; - - res_lib_amf_healthcheckcallback.invocation = - invocation_create ( - AMF_RESPONSE_HEALTHCHECKCALLBACK, - (void *)healthcheck_active); - - comp_dn_make (healthcheck_active->comp, &res_lib_amf_healthcheckcallback.compName); - memcpy (&res_lib_amf_healthcheckcallback.key, - &healthcheck_active->safHealthcheckKey, - sizeof (SaAmfHealthcheckKeyT)); - - TRACE8 ("sending healthcheck to component %s", - res_lib_amf_healthcheckcallback.compName.value); - openais_conn_send_response ( - openais_conn_partner_get (healthcheck_active->comp->conn), - &res_lib_amf_healthcheckcallback, - sizeof (struct res_lib_amf_healthcheckcallback)); - - openais_timer_delete (healthcheck_active->timer_handle_duration); - - openais_timer_add ( - healthcheck_active->saAmfHealthcheckMaxDuration, - (void *)healthcheck_active, - timer_function_healthcheck_timeout, - &healthcheck_active->timer_handle_duration); -} - -static void healthcheck_deactivate (struct amf_healthcheck *healthcheck_active) -{ - dprintf ("deactivating healthcheck for component %s\n", - getSaNameT (&healthcheck_active->comp->name)); - - openais_timer_delete (healthcheck_active->timer_handle_period); - - openais_timer_delete (healthcheck_active->timer_handle_duration); - - invocation_destroy_by_data ((void *)healthcheck_active); - healthcheck_active->active = 0; -} - - -static void timer_function_healthcheck_next_fn (void *data) -{ - healthcheck_activate (data); -} - -static void su_operational_state_set ( - struct amf_su *unit, - SaAmfOperationalStateT oper_state) -{ - struct amf_comp* comp; - - if (oper_state == unit->saAmfSUOperState) { - log_printf (LOG_INFO, - "Not assigning service unit new operational state - same state\n"); - return; - } - - unit->saAmfSUOperState = oper_state; - TRACE1 ("Setting SU '%s' operational state: %s\n", - unit->name.value, oper_state_text[oper_state]); - - if (oper_state == SA_AMF_OPERATIONAL_ENABLED) { - su_readiness_state_set (unit, SA_AMF_READINESS_IN_SERVICE); - for (comp = unit->comp_head; comp; comp = comp->next) { - comp_readiness_state_set (comp); - } - - if (sg_all_su_in_service(unit->sg)) { - TRACE1 ("All SUs in SG '%s' in service, assigning SIs\n", unit->sg->name.value); - sg_assign_si (unit->sg); - if (amf_cluster.timeout_handle) { - openais_timer_delete (amf_cluster.timeout_handle); - } - } - } else if (oper_state == SA_AMF_OPERATIONAL_DISABLED) { - su_readiness_state_set (unit, SA_AMF_READINESS_OUT_OF_SERVICE); - } -} - /* * Executive Message Implementation */ @@ -2378,60 +473,31 @@ static void message_handler_req_exec_amf_comp_register ( struct res_lib_amf_componentregister res_lib; struct req_exec_amf_comp_register *req_exec = message; struct amf_comp *comp; + SaAisErrorT error; - comp = amf_find_comp (&amf_cluster, &req_exec->compName); - if (comp == NULL) { - log_printf (LOG_ERR, "Component '%s' not found", &req_exec->compName.value); - return; - } + comp = amf_comp_find (&amf_cluster, &req_exec->compName); + assert (comp != NULL); + ENTER ("'%s'", comp->name.value); + error = amf_comp_register (comp); - TRACE2("Exec comp register '%s'", &req_exec->compName.value); - - if (comp->saAmfCompPresenceState == SA_AMF_PRESENCE_RESTARTING) { - comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATED); - comp_readiness_state_set (comp); - if (comp->saAmfCompReadinessState == SA_AMF_READINESS_IN_SERVICE) { - comp_reassign_csis (comp); - } - } else if ((comp->saAmfCompPresenceState == SA_AMF_PRESENCE_INSTANTIATING) || - (comp->saAmfCompPresenceState == SA_AMF_PRESENCE_UNINSTANTIATED)){ - comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATED); - comp_operational_state_set (comp, SA_AMF_OPERATIONAL_ENABLED); - } - else { - assert (0); - } - - if (comp->su->is_local) { + if (amf_su_is_local (comp->su)) { res_lib.header.id = MESSAGE_RES_AMF_COMPONENTREGISTER; res_lib.header.size = sizeof (struct res_lib_amf_componentregister); - res_lib.header.error = SA_AIS_OK; - openais_conn_send_response (comp->conn, &res_lib, sizeof (res_lib)); + res_lib.header.error = error; + openais_conn_send_response ( + comp->conn, &res_lib, sizeof (struct res_lib_amf_componentregister)); } } static void message_handler_req_exec_amf_comp_error_report ( void *message, unsigned int nodeid) { - struct res_lib_amf_componenterrorreport res_lib; struct req_exec_amf_comp_error_report *req_exec = message; struct amf_comp *comp; - comp = amf_find_comp (&amf_cluster, &req_exec->erroneousComponent); - if (comp == NULL) { - log_printf (LOG_ERR, "Component '%s' not found", &req_exec->erroneousComponent); - return; - } - - TRACE2("Exec comp error report '%s'", &req_exec->reportingComponent.value); - - if (comp->su->is_local) { - res_lib.header.size = sizeof (struct res_lib_amf_componenterrorreport); - res_lib.header.id = MESSAGE_RES_AMF_COMPONENTERRORREPORT; - res_lib.header.error = SA_AIS_OK; - openais_conn_send_response (comp->conn, &res_lib, sizeof (res_lib)); - } - escalation_policy_cleanup (comp); + comp = amf_comp_find (&amf_cluster, &req_exec->erroneousComponent); + assert (comp != NULL); + amf_comp_error_report (comp, req_exec->recommendedRecovery); } static void message_handler_req_exec_amf_clc_cleanup_completed ( @@ -2440,14 +506,13 @@ static void message_handler_req_exec_amf_clc_cleanup_completed ( struct req_exec_amf_clc_cleanup_completed *req_exec = message; struct amf_comp *comp; - comp = amf_find_comp (&amf_cluster, &req_exec->compName); + comp = amf_comp_find (&amf_cluster, &req_exec->compName); if (comp == NULL) { log_printf (LOG_ERR, "'%s' not found", &req_exec->compName.value); return; } - TRACE2("Exec CLC cleanup completed for '%s'", &req_exec->compName.value); - clc_instantiate (comp); + amf_comp_cleanup_completed (comp); } static void message_handler_req_exec_amf_healthcheck_tmo ( @@ -2455,15 +520,17 @@ static void message_handler_req_exec_amf_healthcheck_tmo ( { struct req_exec_amf_healthcheck_tmo *req_exec = message; struct amf_comp *comp; + struct amf_healthcheck *healthcheck; - comp = amf_find_comp (&amf_cluster, &req_exec->compName); + comp = amf_comp_find (&amf_cluster, &req_exec->compName); if (comp == NULL) { log_printf (LOG_ERR, "'%s' not found", &req_exec->compName.value); return; } - TRACE2("Exec healthcheck tmo for '%s'", &comp->name.value); - escalation_policy_cleanup (comp); + healthcheck = amf_comp_find_healthcheck (comp, &req_exec->safHealthcheckKey); + + amf_comp_healthcheck_tmo (comp, healthcheck); } static void message_handler_req_exec_amf_response ( @@ -2471,29 +538,17 @@ static void message_handler_req_exec_amf_response ( { struct req_exec_amf_response *req_exec = message; struct amf_comp *comp; + struct res_lib_amf_response res_lib; + SaAisErrorT retval; - comp = amf_find_comp (&amf_cluster, &req_exec->compName); + comp = amf_comp_response_2 (req_exec->invocation, req_exec->error, &retval); assert (comp != NULL); - switch (req_exec->interface) { - case AMF_RESPONSE_CSISETCALLBACK: - dprintf ("Exec csi set callback response from '%s', error: %d", - &req_exec->compName.value, req_exec->error); - break; - - case AMF_RESPONSE_CSIREMOVECALLBACK: - dprintf ("Exec csi remove callback response from '%s', error: %d", - &req_exec->compName.value, req_exec->error); - break; - - case AMF_RESPONSE_COMPONENTTERMINATECALLBACK: - dprintf ("Exec component terminate callback response from '%s', error: %s", - &req_exec->compName.value, req_exec->error); - break; - - default: - assert (0); - break; + if (amf_su_is_local (comp->su)) { + res_lib.header.id = MESSAGE_RES_AMF_RESPONSE; + res_lib.header.size = sizeof (struct res_lib_amf_response); + res_lib.header.error = retval; + openais_conn_send_response (comp->conn, &res_lib, sizeof (res_lib)); } } @@ -2507,7 +562,7 @@ static void message_handler_req_lib_amf_componentregister ( struct req_lib_amf_componentregister *req_lib = msg; struct amf_comp *comp; - comp = amf_find_comp (&amf_cluster, &req_lib->compName); + comp = amf_comp_find (&amf_cluster, &req_lib->compName); if (comp) { struct req_exec_amf_comp_register req_exec; struct iovec iovec; @@ -2559,7 +614,7 @@ static void message_handler_req_lib_amf_componentunregister ( req_lib_amf_componentunregister, sizeof (struct req_lib_amf_componentunregister)); - component = amf_find_comp (&amf_cluster, &req_lib_amf_componentunregister->compName); + component = amf_comp_find (&amf_cluster, &req_lib_amf_componentunregister->compName); if (component && component->registered && component->local) { // component->probableCause = SA_AMF_NOT_RESPONDING; } @@ -2576,6 +631,7 @@ static void message_handler_req_lib_amf_pmstart ( void *msg) { } + static void message_handler_req_lib_amf_pmstop ( void *conn, void *msg) @@ -2587,129 +643,101 @@ static void message_handler_req_lib_amf_healthcheckstart ( { struct req_lib_amf_healthcheckstart *req_lib = msg; struct res_lib_amf_healthcheckstart res_lib; - struct amf_healthcheck *healthcheck; struct amf_comp *comp; SaAisErrorT error = SA_AIS_OK; - comp = amf_find_comp (&amf_cluster, &req_lib->compName); - if (comp == 0) { - log_printf (LOG_ERR, "Healthcheckstart: Component '%s' not found", - req_lib->compName.value); - error = SA_AIS_ERR_NOT_EXIST; - goto error_exit; - } + comp = amf_comp_find (&amf_cluster, &req_lib->compName); - healthcheck = amf_find_healthcheck (comp, &req_lib->healthcheckKey); - if (healthcheck == 0) { - log_printf (LOG_ERR, "Healthcheckstart: Healthcheck '%s' not found", - req_lib->healthcheckKey.key); - error = SA_AIS_ERR_NOT_EXIST; - goto error_exit; - } - - dprintf ("Healthcheckstart: '%s', key '%s'", - req_lib->compName.value, req_lib->healthcheckKey.key); - - /* - * Determine if this healthcheck is already active - */ - if (healthcheck->active) { - error = SA_AIS_ERR_EXIST; - goto error_exit; - } - - /* - * Initialise - */ - healthcheck->invocationType = req_lib->invocationType; - healthcheck->timer_handle_duration = 0; - healthcheck->timer_handle_period = 0; - healthcheck->active = 0; - - if (comp->conn == NULL) { + if (comp != NULL) { comp->conn = conn; + error = amf_comp_healthcheck_start ( + comp, &req_lib->healthcheckKey, req_lib->invocationType, + req_lib->recommendedRecovery); + } else { + log_printf (LOG_ERR, "Healthcheckstart: Component '%s' not found", + req_lib->compName.value); + error = SA_AIS_ERR_NOT_EXIST; } - healthcheck_activate (healthcheck); - -error_exit: res_lib.header.id = MESSAGE_RES_AMF_HEALTHCHECKSTART; res_lib.header.size = sizeof (res_lib); res_lib.header.error = error; - openais_conn_send_response (conn, &res_lib, sizeof (struct res_lib_amf_healthcheckstart)); } static void message_handler_req_lib_amf_healthcheckconfirm ( - void *conn, - void *msg) + void *conn, void *msg) { -} - -static void message_handler_req_lib_amf_healthcheckstop ( - void *conn, - void *msg) -{ - struct req_lib_amf_healthcheckstop *req_lib = msg; - struct res_lib_amf_healthcheckstop res_lib; - struct amf_healthcheck *healthcheck; + struct req_lib_amf_healthcheckconfirm *req_lib = msg; + struct res_lib_amf_healthcheckconfirm res_lib; struct amf_comp *comp; SaAisErrorT error = SA_AIS_OK; - dprintf ("healthcheck stop\n"); + comp = amf_comp_find (&amf_cluster, &req_lib->compName); + if (comp != NULL) { + error = amf_comp_healthcheck_confirm ( + comp, &req_lib->healthcheckKey, req_lib->healthcheckResult); + } else { + log_printf (LOG_ERR, "Healthcheck confirm: Component '%s' not found", + req_lib->compName.value); + error = SA_AIS_ERR_NOT_EXIST; + } - comp = amf_find_comp (&amf_cluster, &req_lib->compName); - if (comp == 0) { + res_lib.header.id = MESSAGE_RES_AMF_HEALTHCHECKCONFIRM; + res_lib.header.size = sizeof (res_lib); + res_lib.header.error = error; + openais_conn_send_response (conn, &res_lib, sizeof (res_lib)); +} + +static void message_handler_req_lib_amf_healthcheckstop ( + void *conn, void *msg) +{ + struct req_lib_amf_healthcheckstop *req_lib = msg; + struct res_lib_amf_healthcheckstop res_lib; + struct amf_comp *comp; + SaAisErrorT error = SA_AIS_OK; + + comp = amf_comp_find (&amf_cluster, &req_lib->compName); + if (comp != NULL) { + error = amf_comp_healthcheck_stop (comp, &req_lib->healthcheckKey); + } else { log_printf (LOG_ERR, "Healthcheckstop: Component '%s' not found", - req_lib->compName.value); + req_lib->compName.value); error = SA_AIS_ERR_NOT_EXIST; - goto error_exit; } - healthcheck = amf_find_healthcheck (comp, &req_lib->healthcheckKey); - if (healthcheck == 0) { - log_printf (LOG_ERR, "Healthcheckstop: Healthcheck '%s' not found", - req_lib->healthcheckKey.key); - error = SA_AIS_ERR_NOT_EXIST; - goto error_exit; - } - - healthcheck_deactivate (healthcheck); - -error_exit: res_lib.header.id = MESSAGE_RES_AMF_HEALTHCHECKSTOP; res_lib.header.size = sizeof (res_lib); res_lib.header.error = error; openais_conn_send_response (conn, &res_lib, sizeof (res_lib)); } -static void message_handler_req_lib_amf_hastateget ( - void *conn, - void *msg) +static void message_handler_req_lib_amf_hastateget (void *conn, void *msg) { -#ifdef COMPILE_OUT - struct req_lib_amf_hastateget *req_lib_amf_hastateget = (struct req_lib_amf_hastateget *)msg; - struct res_lib_amf_hastateget res_lib_amf_hastateget; - struct amf_comp *component; + struct req_lib_amf_hastateget *req_lib = msg; + struct res_lib_amf_hastateget res_lib; + struct amf_comp *comp; + SaAmfHAStateT ha_state; + SaAisErrorT error; - log_printf (LOG_LEVEL_FROM_LIB, "Handle : message_handler_req_lib_amf_hastateget()\n"); - - res_lib_amf_hastateget.header.id = MESSAGE_RES_AMF_HASTATEGET; - res_lib_amf_hastateget.header.size = sizeof (struct res_lib_amf_hastateget); - res_lib_amf_hastateget.header.error = SA_ERR_NOT_EXIST; - -#ifdef COMPILE_OUT - component = component_in_protectiongroup_find (&req_lib_amf_hastateget->csiName, &req_lib_amf_hastateget->compName); -#endif - - if (component) { - memcpy (&res_lib_amf_hastateget.haState, - &component->currentHAState, sizeof (SaAmfHAStateT)); - res_lib_amf_hastateget.header.error = SA_AIS_OK; + comp = amf_comp_find (&amf_cluster, &req_lib->compName); + if (comp != NULL) { + error = amf_comp_hastate_get (comp, &req_lib->csiName, &ha_state); + res_lib.haState = ha_state; + res_lib.header.error = error; + } else { + log_printf (LOG_ERR, "HA state get: Component '%s' not found", + req_lib->compName.value); + error = SA_AIS_ERR_NOT_EXIST; } - openais_conn_send_response (conn, &res_lib_amf_hastateget, sizeof (struct res_lib_amf_hastateget)); -#endif + + res_lib.header.id = MESSAGE_RES_AMF_HASTATEGET; + res_lib.header.size = sizeof (struct res_lib_amf_hastateget); + res_lib.header.error = error; + + openais_conn_send_response (conn, &res_lib, + sizeof (struct res_lib_amf_hastateget)); } static void message_handler_req_lib_amf_protectiongrouptrack ( @@ -2837,7 +865,7 @@ static void message_handler_req_lib_amf_componenterrorreport ( struct req_lib_amf_componenterrorreport *req_lib = msg; struct amf_comp *comp; - comp = amf_find_comp (&amf_cluster, &req_lib->erroneousComponent); + comp = amf_comp_find (&amf_cluster, &req_lib->erroneousComponent); if (comp != NULL) { struct req_exec_amf_comp_error_report req_exec; struct iovec iovec; @@ -2849,26 +877,26 @@ static void message_handler_req_lib_amf_componenterrorreport ( MESSAGE_REQ_EXEC_AMF_COMPONENT_ERROR_REPORT); memcpy (&req_exec.reportingComponent, &req_lib->reportingComponent, - sizeof (SaNameT)); + sizeof (SaNameT)); memcpy (&req_exec.erroneousComponent, &req_lib->erroneousComponent, - sizeof (SaNameT)); + sizeof (SaNameT)); memcpy (&req_exec.errorDetectionTime, &req_lib->errorDetectionTime, - sizeof (SaTimeT)); + sizeof (SaTimeT)); memcpy (&req_exec.recommendedRecovery, &req_lib->recommendedRecovery, - sizeof (SaAmfRecommendedRecoveryT)); + sizeof (SaAmfRecommendedRecoveryT)); memcpy (&req_exec.ntfIdentifier, &req_lib->ntfIdentifier, - sizeof (SaNtfIdentifierT)); + sizeof (SaNtfIdentifierT)); iovec.iov_base = (char *)&req_exec; iovec.iov_len = sizeof (req_exec); - assert (totempg_groups_mcast_joined (openais_group_handle, - &iovec, 1, TOTEMPG_AGREED) == 0); + assert (totempg_groups_mcast_joined ( + openais_group_handle, &iovec, 1, TOTEMPG_AGREED) == 0); } else { struct res_lib_amf_componenterrorreport res_lib; log_printf (LOG_ERR, "Component %s not found", - &req_lib->erroneousComponent.value); + &req_lib->erroneousComponent.value); res_lib.header.size = sizeof (struct res_lib_amf_componenterrorreport); res_lib.header.id = MESSAGE_RES_AMF_COMPONENTERRORREPORT; res_lib.header.error = SA_AIS_ERR_NOT_EXIST; @@ -2908,109 +936,42 @@ static void message_handler_req_lib_amf_componenterrorclear ( } -#if 0 -static void pg_comp_create ( - struct amf_pg *pg, - struct amf_csi *csi, - struct amf_comp *comp) -{ - struct amf_pg_comp *pg_comp; - - dprintf ("creating component for pg\n"); - pg_comp = malloc (sizeof (struct amf_pg_comp)); - assert (pg_comp); - pg_comp->comp = comp; - pg_comp->csi = csi; - list_init (&pg_comp->list); - list_add_tail (&pg_comp->list, &pg->pg_comp_head); -} -#endif - static void message_handler_req_lib_amf_response (void *conn, void *msg) { - struct res_lib_amf_response res_lib; struct req_lib_amf_response *req_lib = msg; - struct req_exec_amf_response req_exec; - struct iovec iovec; - struct amf_pd *pd = openais_conn_private_data_get (conn); - int res; - int interface; - void *data; - int error = SA_AIS_OK; + int multicast; + SaAisErrorT retval; - res = invocation_get_and_destroy (req_lib->invocation, &interface, &data); + /* + * This is an optimisation to avoid multicast of healthchecks while keeping + * a nice design. We multicast and make lib responses from this file. + */ + multicast = amf_comp_response_1 ( + req_lib->invocation, req_lib->error, &retval); - if (res == -1) { - log_printf (LOG_ERR, "Lib response: invocation not found\n"); - error = SA_AIS_ERR_INVALID_PARAM; - goto end; - } + if (multicast) { + struct req_exec_amf_response req_exec; + struct iovec iovec; - switch (interface) { - case AMF_RESPONSE_HEALTHCHECKCALLBACK: { - struct amf_healthcheck *healthcheck = data; - SaNameT name; - TRACE3 ("Lib healthcheck response from '%s'", - comp_dn_make (healthcheck->comp, &name)); - - openais_timer_delete (healthcheck->timer_handle_duration); - healthcheck->timer_handle_duration = 0; - - openais_timer_add ( - healthcheck->saAmfHealthcheckPeriod, - (void *)healthcheck, - timer_function_healthcheck_next_fn, - &healthcheck->timer_handle_period); - break; - } - case AMF_RESPONSE_CSISETCALLBACK: { - struct amf_csi_assignment *csi_assignment = data; - dprintf ("Lib csi '%s' set callback response from '%s', error: %d", - csi_assignment->csi->name.value, csi_assignment->comp->name.value, req_lib->error); - memcpy (&req_exec.csiName, &csi_assignment->name, sizeof (SaNameT)); - break; - } - case AMF_RESPONSE_CSIREMOVECALLBACK: { - struct amf_csi_assignment *csi_assignment = data; - dprintf ("Lib csi '%s' remove callback response from '%s', error: %d", - csi_assignment->csi->name.value, csi_assignment->comp->name.value, req_lib->error); - memcpy (&req_exec.csiName, &csi_assignment->name, sizeof (SaNameT)); - break; - } - case AMF_RESPONSE_COMPONENTTERMINATECALLBACK: { - struct component_terminate_callback_data *component_terminate_callback_data; - component_terminate_callback_data = data; - - dprintf ("Lib component terminate callback response, error: %d", req_lib->error); - comp_healthcheck_deactivate (component_terminate_callback_data->comp); - - escalation_policy_restart (component_terminate_callback_data->comp); - break; - } - default: - assert (0); - break; - } - - /* Keep healthcheck responses node local */ - if (interface != AMF_RESPONSE_HEALTHCHECKCALLBACK) { - assert (pd && pd->comp); req_exec.header.size = sizeof (struct req_exec_amf_response); req_exec.header.id = SERVICE_ID_MAKE (AMF_SERVICE, - MESSAGE_REQ_EXEC_AMF_RESPONSE); - comp_dn_make (pd->comp, &req_exec.compName); - req_exec.interface = interface; + MESSAGE_REQ_EXEC_AMF_RESPONSE); + req_exec.invocation = req_lib->invocation; req_exec.error = req_lib->error; iovec.iov_base = (char *)&req_exec; iovec.iov_len = sizeof (req_exec); - assert (totempg_groups_mcast_joined (openais_group_handle, - &iovec, 1, TOTEMPG_AGREED) == 0); + assert (totempg_groups_mcast_joined ( + openais_group_handle, &iovec, 1, TOTEMPG_AGREED) == 0); + } else { + struct res_lib_amf_response res_lib; + res_lib.header.id = MESSAGE_RES_AMF_RESPONSE; + res_lib.header.size = sizeof (struct res_lib_amf_response); + res_lib.header.error = retval; + openais_conn_send_response (conn, &res_lib, sizeof (res_lib)); } - -end: - res_lib.header.id = MESSAGE_RES_AMF_RESPONSE; - res_lib.header.size = sizeof (struct res_lib_amf_response); - res_lib.header.error = error; - openais_conn_send_response (conn, &res_lib, sizeof (res_lib)); } +static void amf_dump_fn (void) +{ + amf_runtime_attributes_print (&amf_cluster); +} diff --git a/exec/amf.h b/exec/amf.h new file mode 100644 index 00000000..4a2fc3e5 --- /dev/null +++ b/exec/amf.h @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2002-2005 MontaVista Software, Inc. + * Author: Steven Dake (sdake@mvista.com) + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * Description: - Reworked to match AMF B.02 information model + * - New state machine design + * + * All rights reserved. + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AMF_H_DEFINED +#define AMF_H_DEFINED + +#include +#include "../include/saAis.h" +#include "../include/saAmf.h" +#include "../include/list.h" +#include "../include/ipc_gen.h" +#include "aispoll.h" +#include "objdb.h" + +enum escalation_levels { + ESCALATION_LEVEL_NO_ESCALATION = 1, /* execute component restart */ + ESCALATION_LEVEL_ONE = 2, /* escalate to service unit restart */ + ESCALATION_LEVEL_TWO = 3, /* escalate to service unit failover */ + ESCALATION_LEVEL_THREE = 4 /* escalate to node failover */ +}; + +enum clc_component_types { + clc_component_sa_aware = 0, /* sa aware */ + clc_component_proxied_pre = 1, /* proxied, pre-instantiable */ + clc_component_proxied_non_pre = 2, /* proxied, non pre-instantiable */ + clc_component_non_proxied_non_sa_aware = 3 /* non-proxied, non sa aware */ +}; + +struct amf_si_assignment; +struct amf_csi_assignment; +struct amf_healthcheck; + +struct amf_cluster { + /* Configuration Attributes */ + SaNameT name; + int saAmfClusterStartupTimeout; + SaNameT saAmfClusterClmCluster; + + /* Runtime Attributes */ + SaAmfAdminStateT saAmfClusterAdminState; + + /* Relations */ + struct amf_node *node_head; + struct amf_application *application_head; + + /* Implementation */ + poll_timer_handle timeout_handle; +}; + +struct amf_node { + /* Configuration Attributes */ + SaNameT name; + SaNameT saAmfNodeClmNode; + int saAmfNodeSuFailOverProb; + SaUint32T saAmfNodeSuFailoverMax; + SaBoolT saAmfNodeAutoRepair; + SaBoolT saAmfNodeRebootOnInstantiationFailure; + SaBoolT saAmfNodeRebootOnTerminationFailure; + + /* Runtime Attributes */ + SaAmfAdminStateT saAmfNodeAdminState; + SaAmfOperationalStateT saAmfNodeOperState; + + /* Relations */ + struct amf_cluster *cluster; + + /* Implementation */ + struct amf_node *next; +}; + +struct amf_application { + /* Configuration Attributes */ + SaNameT name; + + /* Runtime Attributes */ + SaAmfAdminStateT saAmfApplicationAdminState; + SaUint32T saAmfApplicationCurrNumSG; + + /* Relations */ + struct amf_cluster *cluster; + struct amf_sg *sg_head; + struct amf_si *si_head; + + /* Implementation */ + char clccli_path[PATH_MAX]; + char binary_path[PATH_MAX]; + struct amf_application *next; +}; + +struct amf_sg { + /* Configuration Attributes */ + SaNameT name; + saAmfRedundancyModelT saAmfSGRedundancyModel; + SaBoolT saAmfSGAutoAdjust; + SaUint32T saAmfSGNumPrefActiveSUs; + SaUint32T saAmfSGNumPrefStandbySUs; + SaUint32T saAmfSGNumPrefInserviceSUs; + SaUint32T saAmfSGNumPrefAssignedSUs; + SaUint32T saAmfSGMaxActiveSIsperSUs; + SaUint32T saAmfSGMaxStandbySIsperSUs; + SaTimeT saAmfSGCompRestartProb; + SaUint32T saAmfSGCompRestartMax; + SaTimeT saAmfSGSuRestartProb; + SaUint32T saAmfSGSuRestartMax; + SaTimeT saAmfSGAutoAdjustProb; + SaBoolT saAmfSGAutoRepair; + + /* Runtime Attributes */ + SaAmfAdminStateT saAmfSGAdminState; + SaUint32T saAmfSGNumCurrAssignedSUs; + SaUint32T saAmfSGNumCurrNonInstantiatedSpareSUs; + SaUint32T saAmfSGNumCurrInstantiatedSpareSUs; + + /* Relations */ + struct amf_application *application; + struct amf_su *su_head; + + /* Implementation */ + char clccli_path[PATH_MAX]; + char binary_path[PATH_MAX]; + struct amf_sg *next; +}; + +struct amf_su { + /* Configuration Attributes */ + SaNameT name; + SaUint32T saAmfSURank; + SaUint32T saAmfSUNumComponents; + SaBoolT saAmfSUIsExternal; + SaBoolT saAmfSUFailover; + + /* Runtime Attributes */ + SaBoolT saAmfSUPreInstantiable; + SaAmfOperationalStateT saAmfSUOperState; + SaAmfAdminStateT saAmfSUAdminState; + SaAmfReadinessStateT saAmfSUReadinessState; + SaAmfPresenceStateT saAmfSUPresenceState; + SaNameT saAmfSUAssignedSIs; + SaNameT saAmfSUHostedByNode; + SaUint32T saAmfSUNumCurrActiveSIs; + SaUint32T saAmfSUNumCurrStandbySIs; + SaUint32T saAmfSURestartCount; + + /* Relations */ + struct amf_sg *sg; + struct amf_comp *comp_head; + struct amf_si_assignment *assigned_sis; + + /* Implementation */ + char clccli_path[PATH_MAX]; + char binary_path[PATH_MAX]; + SaUint32T su_failover_cnt; /* missing in SAF specs? */ + enum escalation_levels escalation_level; + struct amf_su *next; +}; + +struct amf_comp { + /* Configuration Attributes */ + SaNameT name; + SaNameT **saAmfCompCsTypes; + saAmfCompCategoryT saAmfCompCategory; + saAmfCompCapabilityModelT saAmfCompCapability; + SaUint32T saAmfCompNumMaxActiveCsi; + SaUint32T saAmfCompNumMaxStandbyCsi; + SaStringT *saAmfCompCmdEnv; + int saAmfCompDefaultClcCliTimeout; + int saAmfCompDefaultCallbackTimeOut; + SaStringT saAmfCompInstantiateCmd; + SaStringT saAmfCompInstantiateCmdArgv; + int saAmfCompInstantiateTimeout; + SaUint32T saAmfCompInstantiationLevel; + SaUint32T saAmfCompNumMaxInstantiateWithoutDelay; + SaUint32T saAmfCompNumMaxInstantiateWithDelay; + int saAmfCompDelayBetweenInstantiateAttempts; + SaStringT saAmfCompTerminateCmd; + int saAmfCompTerminateTimeout; + SaStringT saAmfCompTerminateCmdArgv; + SaStringT saAmfCompCleanupCmd; + int saAmfCompCleanupTimeout; + SaStringT saAmfCompCleanupCmdArgv; + SaStringT saAmfCompAmStartCmd; + int saAmfCompAmStartTimeout; + SaStringT saAmfCompAmStartCmdArgv; + SaUint32T saAmfCompNumMaxAmStartAttempt; + SaStringT saAmfCompAmStopCmd; + int saAmfCompAmStopTimeout; + SaStringT saAmfCompAmStopCmdArgv; + SaUint32T saAmfCompNumMaxAmStopAttempt; + int saAmfCompTerminateCallbackTimeout; + int saAmfCompCSISetCallbackTimeout; + int saAmfCompQuiescingCompleteTimeout; + int saAmfCompCSIRmvCallbackTimeout; + SaAmfRecommendedRecoveryT saAmfCompRecoveryOnError; + SaBoolT saAmfCompDisableRestart; + SaNameT saAmfCompProxyCsi; + + /* Runtime Attributes */ + SaAmfOperationalStateT saAmfCompOperState; + SaAmfReadinessStateT saAmfCompReadinessState; + SaAmfPresenceStateT saAmfCompPresenceState; + SaUint32T saAmfCompRestartCount; + SaUint32T saAmfCompNumCurrActiveCsi; + SaUint32T saAmfCompNumCurrStandbyCsi; + SaNameT saAmfCompAssignedCsi; + SaNameT saAmfCompCurrProxyName; + SaNameT saAmfCompCurrProxiedNames; + + /* Relations */ + struct amf_comp *proxy_comp; + struct amf_su *su; + struct amf_csi_assignment *assigned_csis; + + /* Implementation */ + char clccli_path[PATH_MAX]; + char binary_path[PATH_MAX]; + struct amf_comp *next; + void *conn; + enum clc_component_types comptype; + struct amf_healthcheck *healthcheck_head; +}; + +struct amf_healthcheck { + /* Configuration Attributes */ + SaAmfHealthcheckKeyT safHealthcheckKey; + int saAmfHealthcheckMaxDuration; + int saAmfHealthcheckPeriod; + + /* Relations */ + struct amf_comp *comp; + + /* Implementation */ + struct amf_healthcheck *next; + int active; + SaAmfHealthcheckInvocationT invocationType; + SaAmfRecommendedRecoveryT recommendedRecovery; + poll_timer_handle timer_handle_duration; + poll_timer_handle timer_handle_period; +}; + +struct amf_si { + /* Configuration Attributes */ + SaNameT name; + SaNameT saAmfSIProtectedbySG; + SaUint32T saAmfSIRank; + SaUint32T saAmfSINumCSIs; + SaUint32T saAmfSIPrefActiveAssignments; + SaUint32T saAmfSIPrefStandbyAssignments; + + /* Runtime Attributes */ + SaAmfAdminStateT saAmfSIAdminState; + SaAmfAssignmentStateT saAmfSIAssignmentState; + SaUint32T saAmfSINumCurrActiveAssignments; + SaUint32T saAmfSINumCurrStandbyAssignments; + + /* Relations */ + struct amf_application *application; + struct amf_csi *csi_head; + struct amf_si_assignment *si_assignments; + struct amf_si_dependency *depends_on; + struct amf_si_ranked_su *ranked_sus; + + /* Implementation */ + struct amf_si *next; +}; + +struct amf_si_ranked_su { + /* Configuration Attributes */ + SaNameT name; + SaUint32T saAmfRank; + + /* Relations */ + struct amf_si *si; + struct amf_su *su; + + /* Implementation */ + struct amf_si_ranked_su *su_next; + struct amf_si_ranked_su *si_next; +}; + +struct amf_si_dependency { + /* Configuration Attributes */ + SaNameT name; + int saAmfToleranceTime; + + /* Relations */ + + /* Implementation */ + struct amf_si_dependency *next; +}; + +struct amf_si_assignment { + /* Runtime Attributes */ + SaNameT name; + SaAmfHAStateT saAmfSISUHAState; + + /* Relations */ + struct amf_si *si; + + /* Implementation */ + struct amf_si_assignment *next; +}; + +struct amf_csi { + /* Configuration Attributes */ + SaNameT name; + SaNameT saAmfCSTypeName; + SaNameT **saAmfCSIDependencies; + + /* Relations */ + struct amf_si *si; + struct amf_csi_assignment *csi_assignments; + struct amf_csi_attribute *attributes_head; + + /* Implementation */ + struct amf_csi *next; + int pg_set; +}; + +struct amf_csi_attribute { + /* Configuration Attributes */ + SaStringT name; + SaStringT *value; + + /* Implementation */ + struct amf_csi_attribute *next; +}; + +struct amf_csi_assignment { + /* Runtime Attributes */ + SaNameT name; + SaAmfHAStateT saAmfCSICompHAState; /* confirmed HA state */ + + /* Relations */ + struct amf_csi *csi; + struct amf_comp *comp; + + /* Implementation */ + SaAmfHAStateT requested_ha_state; + struct amf_csi_assignment *comp_next; + struct amf_csi_assignment *csi_next; +}; + +enum amf_response_interfaces { + AMF_RESPONSE_HEALTHCHECKCALLBACK = 1, + AMF_RESPONSE_CSISETCALLBACK = 2, + AMF_RESPONSE_CSIREMOVECALLBACK = 3, + AMF_RESPONSE_COMPONENTTERMINATECALLBACK = 4 +}; + +enum amf_message_req_types { + MESSAGE_REQ_EXEC_AMF_COMPONENT_REGISTER = 0, + MESSAGE_REQ_EXEC_AMF_COMPONENT_ERROR_REPORT = 1, + MESSAGE_REQ_EXEC_AMF_CLC_CLEANUP_COMPLETED = 2, + MESSAGE_REQ_EXEC_AMF_HEALTHCHECK_TMO = 3, + MESSAGE_REQ_EXEC_AMF_RESPONSE = 4 +}; + +struct req_exec_amf_clc_cleanup_completed { + struct req_header header; + SaNameT compName; +}; + +struct req_exec_amf_healthcheck_tmo { + struct req_header header; + SaNameT compName; + SaAmfHealthcheckKeyT safHealthcheckKey; +}; + +/*===========================================================================*/ +/* amfutil.c */ + +extern int amf_config_read (struct amf_cluster *cluster, char **error_string); +extern char *amf_serialize (struct amf_cluster *cluster); +extern int amf_deserialize (char *buf, struct amf_cluster *cluster); +extern void amf_state_print (struct amf_cluster *cluster); +extern void amf_runtime_attributes_print (struct amf_cluster *cluster); +extern int amf_enabled (struct objdb_iface_ver0 *objdb); +extern int amf_invocation_create (int interface, void *data); +extern int amf_invocation_get_and_destroy ( + int invocation, int *interface, void **data); +extern void amf_invocation_destroy_by_data (void *data); + +extern const char *amf_admin_state (int state); +extern const char *amf_op_state (int state); +extern const char *amf_presence_state (int state); +extern const char *amf_ha_state (int state); +extern const char *amf_readiness_state (int state); + +/*===========================================================================*/ +/* amfnode.c */ + +/* General methods */ +extern struct amf_node *amf_node_create (void); +extern int amf_node_serialize ( + struct amf_node *node, char **buf, int *offset); +extern struct amf_node *amf_node_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); + +/* Event methods */ +extern void amf_node_sync_ready (struct amf_node *node); +extern void amf_node_leave (struct amf_node *node); +extern void amf_node_failover (struct amf_node *node); +extern void amf_node_switchover (struct amf_node *node); +extern void amf_node_failfast (struct amf_node *node); +extern void amf_node_comp_restart_req ( + struct amf_node *node, struct amf_comp *comp); +extern void amf_node_comp_failover_req ( + struct amf_node *node, struct amf_comp *comp); + +enum amf_reboot_reason { + TERMINATION_FAILED = 1, + INSTANTIATION_FAILED = 2 +}; + +extern int amf_node_reboot ( + struct amf_node *node, enum amf_reboot_reason reason); + +/* Response event methods */ +extern void amf_node_application_started ( + struct amf_node *node, struct amf_application *app); +extern void amf_node_application_workload_assigned ( + struct amf_node *node, struct amf_application *app); + +/* Timer event methods */ +extern void timer_function_node_probation_period_expired (void *node); + +/*===========================================================================*/ +/* amfcluster.c */ + +/* General methods */ +extern void amf_cluster_init (void); +extern int amf_cluster_serialize ( + struct amf_cluster *cluster, char **buf, int *offset); +extern struct amf_cluster *amf_cluster_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); + +/* Event methods */ +extern void amf_cluster_start (struct amf_cluster *cluster); + +/* Response event methods */ +extern void amf_cluster_application_started ( + struct amf_cluster *cluster, struct amf_application *app); +extern void amf_cluster_application_workload_assigned ( + struct amf_cluster *cluster, struct amf_application *app); + +/*===========================================================================*/ +/* amfapp.c */ + +/* General methods */ +extern void amf_application_init (void); +extern struct amf_application *amf_application_create (void); +extern int amf_application_calc_and_set_si_dependency_level ( + struct amf_application *app); +extern int amf_application_serialize ( + struct amf_application *application, char **buf, int *offset); +extern struct amf_application *amf_application_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); +extern int amf_application_si_count_get (struct amf_application *app); + +/* Event methods */ +extern void amf_application_start ( + struct amf_application *app, struct amf_node *node); +extern void amf_application_assign_workload ( + struct amf_application *app, struct amf_node *node); + +/* Response event methods */ +extern void amf_application_sg_started ( + struct amf_application *app, struct amf_sg *sg, struct amf_node *node); +extern void amf_application_sg_assigned ( + struct amf_application *app, struct amf_sg *sg); + +/*===========================================================================*/ +/* amfsg.c */ + +/* General methods */ +extern void amf_sg_init (void); +extern struct amf_sg *amf_sg_create (void); +extern int amf_sg_serialize ( + struct amf_sg *sg, char **buf, int *offset); +extern struct amf_sg *amf_sg_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); + +/* Event methods */ +extern void amf_sg_start (struct amf_sg *sg, struct amf_node *node); +extern void amf_sg_assign_si (struct amf_sg *sg, int dependency_level); + +extern void amf_sg_failover_node_req ( + struct amf_sg *sg, struct amf_node *node); +extern void amf_sg_failover_su_req ( + struct amf_sg *sg, struct amf_node *node); +extern void amf_sg_failover_comp_req ( + struct amf_sg *sg, struct amf_node *node); +extern void amf_sg_switchover_node_req ( + struct amf_sg *sg, struct amf_node *node); + +/* Response event methods */ +extern void amf_sg_su_state_changed ( + struct amf_sg *sg, struct amf_su *su, SaAmfStateT type, int state); +extern void amf_sg_si_ha_state_changed ( + struct amf_sg *sg, struct amf_si *si, int state); +extern void amf_sg_su_assignment_removed ( + struct amf_sg *sg, struct amf_su *su); + +/* Timer event methods */ +//static void timer_function_auto_adjust_tmo (void *sg); + +/*===========================================================================*/ +/* amfsu.c */ + +/* General methods */ +extern void amf_su_init (void); +extern struct amf_su *amf_su_create (void); +extern int amf_su_serialize ( + struct amf_su *su, char **buf, int *offset); +extern struct amf_su *amf_su_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); +extern int amf_su_is_local (struct amf_su *su); + +/* Event methods */ +extern void amf_su_instantiate (struct amf_su *su); +extern void amf_su_assign_si ( + struct amf_su *su, struct amf_si *si, SaAmfHAStateT ha_state); +extern void amf_su_restart_req (struct amf_su *su); +extern void amf_su_terminate (struct amf_su *su); +extern struct amf_node *amf_su_get_node (struct amf_su *su); +extern void amf_su_escalation_level_reset (struct amf_su *su); +extern void amf_su_remove_assignment (struct amf_su *su); + +/* Response event methods */ +extern void amf_su_comp_state_changed ( + struct amf_su *su, struct amf_comp *comp, SaAmfStateT type, int state); +extern void amf_su_comp_hastate_changed ( + struct amf_su *su, struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment); +extern void amf_su_comp_error_suspected ( + struct amf_su *su, + struct amf_comp *comp, + SaAmfRecommendedRecoveryT recommended_recovery); + +/* Timer event methods */ +//static void timer_function_su_probation_period_expired(void *data); + +/*===========================================================================*/ +/* amfcomp.c */ + +/* General methods */ +extern void amf_comp_init (void); +extern struct amf_comp *amf_comp_create (struct amf_su *su); +extern char *amf_comp_dn_make (struct amf_comp *comp, SaNameT *name); +extern struct amf_comp *amf_comp_find ( + struct amf_cluster *cluster, SaNameT *name); +extern int amf_comp_serialize ( + struct amf_comp *comp, char **buf, int *offset); +extern struct amf_comp *amf_comp_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); + +/* Event methods */ +extern void amf_comp_instantiate (struct amf_comp *comp); +extern void amf_comp_terminate (struct amf_comp *comp); +extern void amf_comp_hastate_set ( + struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment, + SaAmfHAStateT requested_ha_state); +extern void amf_comp_restart (struct amf_comp *comp); +extern void amf_comp_operational_state_set ( + struct amf_comp *comp, SaAmfOperationalStateT opstate); +extern void amf_comp_readiness_state_set ( + struct amf_comp *comp, SaAmfReadinessStateT state); +extern struct amf_healthcheck *amf_comp_find_healthcheck ( + struct amf_comp *comp, SaAmfHealthcheckKeyT *key); +extern void amf_comp_healthcheck_tmo ( + struct amf_comp *comp, struct amf_healthcheck *healthcheck); +extern void amf_comp_cleanup_completed (struct amf_comp *comp); + +/* + * Originates from library + */ +extern SaAisErrorT amf_comp_healthcheck_start ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey, + SaAmfHealthcheckInvocationT invocationType, + SaAmfRecommendedRecoveryT recommendedRecovery); +extern SaAisErrorT amf_comp_healthcheck_stop ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey); +extern SaAisErrorT amf_comp_register (struct amf_comp *comp); +extern void amf_comp_unregister (struct amf_comp *comp); +extern void amf_comp_error_report ( + struct amf_comp *comp, SaAmfRecommendedRecoveryT recommendedRecovery); +extern int amf_comp_response_1 ( + SaInvocationT invocation, SaAisErrorT error, SaAisErrorT *retval); +extern struct amf_comp *amf_comp_response_2 ( + SaInvocationT invocation, SaAisErrorT error, SaAisErrorT *retval); +extern SaAisErrorT amf_comp_hastate_get ( + struct amf_comp *comp, SaNameT *csi_name, SaAmfHAStateT *ha_state); +extern SaAisErrorT amf_comp_healthcheck_confirm ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey, + SaAisErrorT healthcheckResult); + +/*===========================================================================*/ +/* amfsi.c */ + +/* General methods */ +extern void amf_si_init (void); +extern struct amf_si *amf_si_create (void); +extern int amf_si_calc_and_set_csi_dependency_level (struct amf_si *si); +extern int amf_si_serialize ( + struct amf_si *si, char **buf, int *offset); +extern struct amf_si *amf_si_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); + +/* Event methods */ +extern void amf_si_activate ( + struct amf_si *si, + void (*activated_callback_fn)(struct amf_si *si, int result)); +extern void amf_si_deactivate ( + struct amf_si *si, + struct amf_csi *csi, + void (*deactivated_callback_fn)(struct amf_si *si, int result)); +extern void amf_si_set_ha_state ( + struct amf_si *si, + SaAmfHAStateT ha_state, + void (*set_ha_state_callback_fn)(struct amf_si *si, int result)); + +/* Response event methods */ +extern void amf_si_comp_set_ha_state_done ( + struct amf_si *si, struct amf_csi_assignment *csi_assignment); +extern void amf_si_comp_set_ha_state_failed ( + struct amf_si *si, struct amf_csi_assignment *csi_assignment); + + +/* General methods */ +extern struct amf_csi *amf_csi_create (void); +extern int amf_csi_serialize ( + struct amf_csi *csi, char **buf, int *offset); +extern struct amf_csi *amf_csi_deserialize ( + char **buf, int *size, struct amf_cluster *cluster); +extern char *amf_csi_dn_make (struct amf_csi *csi, SaNameT *name); + +/*===========================================================================*/ +extern struct amf_node *this_amf_node; +extern struct amf_cluster amf_cluster; + +#endif /* AMF_H_DEFINED */ diff --git a/exec/amfapp.c b/exec/amfapp.c new file mode 100644 index 00000000..305e7417 --- /dev/null +++ b/exec/amfapp.c @@ -0,0 +1,113 @@ +/** @file amfapp.c + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Application Class implementation + * + * This file contains functions for handling the AMF applications. It can + * be viewed as the implementation of the AMF Application class + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * - on request start the service groups it contains + * - on request order the service groups to assign workload to all + * service units contained in the service group, level by level + * - to handle administrative operation support for the application (FUTURE) + * + * The cluster class contains the following state machines: + * - administrative state machine (ADSM) + * - availability control state machine (ACSM) + * + * The administrative state machine will be implemented in the future. + * + * ACSM handles initial start of an application. In the future it will also + * handle administrative commands on the application as described in paragraph + * 7.4 of the spec. ACSM includes two stable states (UNINSTANTIATED and + * STARTED) and a number of states to control the transition between the + * stable states. + * + * The application is in state UNINSTANTIATED when the application starts. + * (In the future this state will also be assumed after the LOCK_INSTANTIATION + * administrative command.) + * + * State STARTED is assumed when the application has been initially started and + * will in the future be re-assumed after the administrative command RESTART + * have been executed. + * + */ + +#include "amf.h" +#include "print.h" + +int amf_application_si_count_get (struct amf_application *app) +{ + struct amf_si *si; + int answer = 0; + + for (si = app->si_head; si != NULL; si = si->next) { + answer += 1; + } + return (answer); +} + +void amf_application_start ( + struct amf_application *app, struct amf_node *node) +{ + struct amf_sg *sg; + + ENTER ("'%s'", app->name.value); + + for (sg = app->sg_head; sg != NULL; sg = sg->next) { + amf_sg_start (sg, node); + } +} + +void amf_application_assign_workload ( + struct amf_application *app, struct amf_node *node) +{ + struct amf_sg *sg; + + for (sg = app->sg_head; sg != NULL; sg = sg->next) { + amf_sg_assign_si (sg, 0); + } +} + +void amf_application_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfcluster.c b/exec/amfcluster.c new file mode 100644 index 00000000..ab0735e9 --- /dev/null +++ b/exec/amfcluster.c @@ -0,0 +1,123 @@ +/** @file amfcluster.c + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Cluster Class Implementation + * + * This file contains functions for handling the AMF cluster. It can be + * viewed as the implementation of the AMF Cluster class + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * - to start the cluster initially + * - to handle the administrative operation support for the cluster (FUTURE) + * + * The cluster class contains the following state machines: + * - administrative state machine (ADSM) + * - availability control state machine (ACSM) + * + * The administrative state machine will be implemented in the future. + * + * ACSM handles initial start of the cluster. In the future it will also handle + * administrative commands on the cluster as described in paragraph 7.4 of the + * spec. ACSM includes two stable states (UNINSTANTIATED and STARTED) and a + * number of states to control the transition between the stable states. + * + * The cluster is in state UNINSTANTIATED when the cluster starts. (In the + * future this state will also be assumed after the LOCK_INSTANTIATION + * administrative command.) + * + * State STARTED is assumed when the cluster has been initially started and + * will in the future be re-assumed after the administrative command RESTART + * have been executed. + */ + +#include +#include + +#include "print.h" +#include "amf.h" +#include "aispoll.h" +#include "util.h" +#include "main.h" + +static void timer_function_cluster_assign_workload_tmo (void *_cluster) +{ + struct amf_application *app; + struct amf_cluster *cluster = _cluster; + + dprintf("2nd Cluster start timer expired, assigning workload to application\n"); + + for (app = cluster->application_head; app != NULL; app = app->next) { + amf_application_assign_workload (app, this_amf_node); + } +} + +static void timer_function_cluster_startup_tmo (void *_cluster) +{ + struct amf_cluster *cluster = _cluster; + struct amf_application *app; + + dprintf("1st Cluster start timer expired, starting applications"); + + for (app = cluster->application_head; app != NULL; app = app->next) { + amf_application_start (app, this_amf_node); + } + + /* wait a while before assigning workload */ + poll_timer_add (aisexec_poll_handle, + cluster->saAmfClusterStartupTimeout, + cluster, + timer_function_cluster_assign_workload_tmo, + &cluster->timeout_handle); +} + +void amf_cluster_start (struct amf_cluster *cluster) +{ + /* wait a while before starting applications */ + poll_timer_add (aisexec_poll_handle, + cluster->saAmfClusterStartupTimeout, + cluster, + timer_function_cluster_startup_tmo, + &cluster->timeout_handle); +} + +void amf_cluster_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfcomp.c b/exec/amfcomp.c new file mode 100644 index 00000000..14fd4384 --- /dev/null +++ b/exec/amfcomp.c @@ -0,0 +1,1521 @@ +/** @file amfcomp.c + * + * Copyright (c) 2002-2006 MontaVista Software, Inc. + * Author: Steven Dake (sdake@mvista.com) + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Introduced AMF B.02 information model + * - Use DN in API and multicast messages + * - (Re-)Introduction of event based multicast messages + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Component Class Implementation + * + * This file contains functions for handling AMF-components. It can be + * viewed as the implementation of the AMF Component class (called comp) + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for handling the following + * types of components: + * - sa-aware components + * (proxy or non-proxy) + * - non-sa-aware components + * (non-proxied non-pre-instantiable and + * proxied pre-instantiable or not pre-instantiable) + * + * The functions of this file are also responsible for: + * - handling all communication with the AMF API library supported by the + * AMF main function, see below + * - instantiating and terminating components upon request + * - updating the ha-state of the CSI-assignment related to the component + * - initiating an error report to the parent SU + * - handling all run time attributes of the AMF Component; all cached + * attributes are stored as variables and sent to the IMM service + * upon the changes described in the specification. + * + * Incoming events from the AMF library is primarily handled by the AMF + * main function which: + * <1> transforms the incoming event to an event that is multicast + * to all AMF service instances in the cluster + * <2> the event received from multicast is tranformed to a function + * call of the external interface of comp + * + * Outgoing events to the AMF library is handled by static functions called + * lib__request which creates an invocation handle + * unique to this call and stores any variables comp want to associate to the + * call back so it is possible to pick them up when the component responses + * through the API. Finally, a timer is started to supervise that a response + * really is received. + * + * Comp initiates error reports to its parent SU in the cases described in + * paragraph 3.3.2.2 in the spec. Comp delegates all actions to SU except + * - it stores the received or pre-configured recommended recovery + * action + * - sets the operational state to DISABLED unless the + * recommended recovery action was SA_AMF_COMP_RESTART. (In this case + * SU or node may set operational state of the component later on + * when it has been fully investigated that no escallation to a + * more powerful recovery action shall be made.) + * + * Comp contains the following state machines: + * - presence state machine (PRSM) + * - operational state machine (OPSM) + * - readiness state machine (RESM) + * - ha state per component service instance (CSI) + * + * The behaviour of comp is mainly controlled by the presence state machine, + * while the operational and readiness state machines are used only to report + * information to its parent (service unit SU) and management (IMM). Comp does + * not control the logic to assign a CSI to itself and neither to decide the + * value of the ha-state but only to faciltate the communication of the CSI + * set (or remove) order and to evaluate the response from the library. + * + * The presence state machine implements all the states described in the + * specification. + * The '-ING' states of PRSM are designed as composite states (UML terminology). + * Being a composite state means that the state contains substates. + * PRSM composite states are: + * - TERMINATING (TERMINATE and CLEANUP) + * - INSTANTIATING (INSTANTIATE, INSTANTIATEDELAY and CLEANUP) + * - RESTARTING (TERMINATE, INSTANTIATE, INSTANTIATEDELAY and CLEANUP) + * + * The reason for introducing these composite states is to make it easier to + * understand the implementation of the behaviour described in paragraphs + * 4.1 - 4.6 in the spec. The comp PRSM implements all the logic described + * except for node reboot, which is handled by the AMF Node class. + * Also PRSM reports all changes of state to its parent SU. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/saAis.h" +#include "../include/saAmf.h" +#include "../include/ipc_gen.h" +#include "../include/ipc_amf.h" +#include "totempg.h" +#include "aispoll.h" +#include "main.h" +#include "service.h" +#include "util.h" +#include "amf.h" +#include "print.h" + +enum clc_command_run_operation_type { + CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE = 1, + CLC_COMMAND_RUN_OPERATION_TYPE_TERMINATE = 2, + CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP = 3 +}; + +struct clc_command_run_data { + struct amf_comp *comp; + enum clc_command_run_operation_type type; + void (*completion_callback) (void *context); +}; + +struct clc_interface { + int (*instantiate) (struct amf_comp *comp); + int (*terminate) (struct amf_comp *comp); + int (*cleanup) (struct amf_comp *comp); +}; + +struct csi_remove_callback_data { + struct amf_csi *csi; +}; + +struct component_terminate_callback_data { + struct amf_comp *comp; +}; + +static void comp_presence_state_set ( + struct amf_comp *comp, + SaAmfPresenceStateT presence_state); +static void comp_operational_state_set ( + struct amf_comp *comp, + SaAmfOperationalStateT operational_state); +static int clc_cli_instantiate (struct amf_comp *comp); +static int clc_instantiate_callback (struct amf_comp *comp); +static int clc_csi_set_callback (struct amf_comp *comp); +static int clc_cli_terminate (struct amf_comp *comp); +static int lib_comp_terminate_request (struct amf_comp *comp); +static int clc_csi_remove_callback (struct amf_comp *comp); +static int clc_cli_cleanup (struct amf_comp *comp); +static int clc_cli_cleanup_local (struct amf_comp *comp); +static void healthcheck_deactivate (struct amf_healthcheck *healthcheck_active); +static void lib_healthcheck_request (struct amf_healthcheck *healthcheck); +static void timer_function_healthcheck_tmo (void *_healthcheck); + +/* + * Life cycle functions + */ +static struct clc_interface clc_interface_sa_aware = { + clc_cli_instantiate, + lib_comp_terminate_request, + clc_cli_cleanup +}; + +static struct clc_interface clc_interface_proxied_pre = { + clc_instantiate_callback, + lib_comp_terminate_request, + clc_cli_cleanup +}; + +static struct clc_interface clc_interface_proxied_non_pre = { + clc_csi_set_callback, + clc_csi_remove_callback, + clc_cli_cleanup_local +}; + +static struct clc_interface clc_interface_non_proxied_non_saware = { + clc_cli_instantiate, + clc_cli_terminate, + clc_cli_cleanup_local +}; + +static struct clc_interface *clc_interfaces[4] = { + &clc_interface_sa_aware, + &clc_interface_proxied_pre, + &clc_interface_proxied_non_pre, + &clc_interface_non_proxied_non_saware +}; + +struct invocation { + void *data; + int interface; + int active; +}; + +static struct invocation *invocation_entries = 0; +static int invocation_entries_size = 0; + +static int invocation_create ( + int interface, + void *data) +{ + struct invocation *invocation_addr = 0; + struct invocation *invocation_temp; + int i; + int loc = 0; + + for (i = 0; i < invocation_entries_size; i++) { + if (invocation_entries[i].active == 0) { + invocation_addr = &invocation_entries[i]; + loc = i; + break; + } + } + if (invocation_addr == 0) { + invocation_temp = (struct invocation *)realloc (invocation_entries, + (invocation_entries_size + 1) * sizeof (struct invocation)); + if (invocation_temp == 0) { + return (-1); + } + invocation_entries = invocation_temp; + invocation_addr = &invocation_entries[invocation_entries_size]; + loc = invocation_entries_size; + invocation_entries_size += 1; + } + invocation_addr->interface = interface; + invocation_addr->data = data; + invocation_addr->active = 1; + + return (loc); +} + +static int invocation_get_and_destroy (SaUint64T invocation, int *interface, + void **data) +{ + if (invocation > invocation_entries_size) { + return (-1); + } + if (invocation_entries[invocation].active == 0) { + return (-1); + } + + *interface = invocation_entries[invocation].interface; + *data = invocation_entries[invocation].data; + memset (&invocation_entries[invocation], 0, sizeof (struct invocation)); + + return (0); +} + +static int invocation_get (SaUint64T invocation, int *interface, + void **data) +{ + if (invocation > invocation_entries_size) { + return (-1); + } + if (invocation_entries[invocation].active == 0) { + return (-1); + } + + *interface = invocation_entries[invocation].interface; + *data = invocation_entries[invocation].data; + + return (0); +} + +static void invocation_destroy_by_data (void *data) +{ + int i; + + for (i = 0; i < invocation_entries_size; i++) { + if (invocation_entries[i].data == data) { + memset (&invocation_entries[i], 0, + sizeof (struct invocation)); + break; + } + } +} + +char *amf_comp_dn_make (struct amf_comp *comp, SaNameT *name) +{ + int i = snprintf((char*) name->value, SA_MAX_NAME_LENGTH, + "safComp=%s,safSu=%s,safSg=%s,safApp=%s", + comp->name.value, comp->su->name.value, + comp->su->sg->name.value, comp->su->sg->application->name.value); + assert (i <= SA_MAX_NAME_LENGTH); + name->length = i; + return (char *)name->value; +} + +static void *clc_command_run (void *context) +{ + struct clc_command_run_data *clc_command_run_data = + (struct clc_command_run_data *)context; + pid_t pid; + int res; + char *argv[10]; + char *envp[10]; + int status; + char path[PATH_MAX]; + char *cmd = 0; + char *comp_argv = 0; + char comp_name[SA_MAX_NAME_LENGTH]; + int i; + + ENTER_VOID(); + + pid = fork(); + + if (pid == -1) { + dprintf ("Couldn't fork process %s\n", strerror (errno)); + return (0); + } + + if (pid) { + dprintf ("waiting for pid %d to finish\n", pid); + waitpid (pid, &status, 0); + dprintf ("process (%d) finished with %d\n", pid, status); + if (clc_command_run_data->completion_callback) { + clc_command_run_data->completion_callback (context); + } + pthread_exit(0); + } + + switch (clc_command_run_data->type) { + case CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE: + cmd = clc_command_run_data->comp->saAmfCompInstantiateCmd; + comp_argv = clc_command_run_data->comp->saAmfCompInstantiateCmdArgv; + break; + + case CLC_COMMAND_RUN_OPERATION_TYPE_TERMINATE: + cmd = clc_command_run_data->comp->saAmfCompTerminateCmd; + comp_argv = clc_command_run_data->comp->saAmfCompTerminateCmdArgv; + break; + + case CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP: + cmd = clc_command_run_data->comp->saAmfCompCleanupCmd; + comp_argv = clc_command_run_data->comp->saAmfCompCleanupCmdArgv; + break; + default: + assert (0 != 1); + break; + } + + /* If command is not an absolute path, search for paths in parent objects */ + if (cmd[0] != '/') { + if (strlen (clc_command_run_data->comp->clccli_path)) { + sprintf (path, "%s/%s", + clc_command_run_data->comp->clccli_path, cmd); + } else if (strlen (clc_command_run_data->comp->su->clccli_path)) { + sprintf (path, "%s/%s", + clc_command_run_data->comp->su->clccli_path, cmd); + } else if (strlen (clc_command_run_data->comp->su->sg->clccli_path)) { + sprintf (path, "%s/%s", + clc_command_run_data->comp->su->sg->clccli_path, cmd); + } else if (strlen (clc_command_run_data->comp->su->sg->application->clccli_path)) { + sprintf (path, "%s/%s", + clc_command_run_data->comp->su->sg->application->clccli_path, cmd); + } + cmd = path; + } + + argv[0] = cmd; + { + /* make a proper argv array */ + i = 1; + char *ptrptr; + char *arg = strtok_r(comp_argv, " ", &ptrptr); + while (arg) { + argv[i] = arg; + arg = strtok_r(NULL, " ", & ptrptr); + i++; + } + } + argv[i] = NULL; + assert (i < 10); + + envp[0] = comp_name; + i = snprintf(comp_name, SA_MAX_NAME_LENGTH, + "SA_AMF_COMPONENT_NAME=safComp=%s,safSu=%s,safSg=%s,safApp=%s", + clc_command_run_data->comp->name.value, + clc_command_run_data->comp->su->name.value, + clc_command_run_data->comp->su->sg->name.value, + clc_command_run_data->comp->su->sg->application->name.value); + assert (i <= SA_MAX_NAME_LENGTH); + + for (i = 1; clc_command_run_data->comp->saAmfCompCmdEnv && + clc_command_run_data->comp->saAmfCompCmdEnv[i - 1]; i++) { + envp[i] = clc_command_run_data->comp->saAmfCompCmdEnv[i - 1]; + } + envp[i] = NULL; + assert (i < 10); + + dprintf ("running command '%s' with environment:\n", cmd); + for (i = 0; envp[i] != NULL; i++) { + dprintf (" %s\n", envp[i]); + } + dprintf (" and argv:\n", cmd); + for (i = 0; argv[i] != NULL; i++) { + dprintf (" %s\n", argv[i]); + } + + res = execve (cmd, argv, envp); + if (res == -1) { + log_printf (LOG_LEVEL_ERROR, "Couldn't exec program %s (%s)\n", + cmd, strerror (errno)); + } + assert (res != -1); + return (0); +} + +/* + * Instantiate possible operations + */ +static int clc_cli_instantiate (struct amf_comp *comp) +{ + int res; + pthread_t thread; + pthread_attr_t thread_attr; /* thread attribute */ + + struct clc_command_run_data *clc_command_run_data; + + ENTER("comp '%s'\n", getSaNameT (&comp->name)); + + clc_command_run_data = malloc (sizeof (struct clc_command_run_data)); + if (clc_command_run_data == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + clc_command_run_data->comp = comp; + clc_command_run_data->type = CLC_COMMAND_RUN_OPERATION_TYPE_INSTANTIATE; + clc_command_run_data->completion_callback = NULL; + pthread_attr_init (&thread_attr); + pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED); + res = pthread_create (&thread, &thread_attr, clc_command_run, (void *)clc_command_run_data); + if (res != 0) { + log_printf (LOG_LEVEL_ERROR, "pthread_create failed: %d", res); + } +// TODO error code from pthread_create + return (res); +} + +static int clc_instantiate_callback (struct amf_comp *comp) +{ + ENTER("comp %s\n", getSaNameT (&comp->name)); + return (0); +} + +static int clc_csi_set_callback (struct amf_comp *comp) +{ + ENTER("comp %s\n", getSaNameT (&comp->name)); + return (0); +} + +/* + * Terminate possible operations + */ +static int clc_cli_terminate (struct amf_comp *comp) +{ + ENTER("comp %s\n", getSaNameT (&comp->name)); + return (0); +} + +static int lib_comp_terminate_request (struct amf_comp *comp) +{ + struct res_lib_amf_componentterminatecallback res_lib_amf_componentterminatecallback; + struct component_terminate_callback_data *component_terminate_callback_data; + + ENTER("comp %s\n", getSaNameT (&comp->name)); + + if (comp->saAmfCompPresenceState != SA_AMF_PRESENCE_INSTANTIATED) { + dprintf ("component terminated but not instantiated %s - %d\n", + getSaNameT (&comp->name), comp->saAmfCompPresenceState); + assert (0); + return (0); + } + + dprintf ("component name terminating %s\n", getSaNameT (&comp->name)); + dprintf ("component presence state %d\n", comp->saAmfCompPresenceState); + + res_lib_amf_componentterminatecallback.header.id = MESSAGE_RES_AMF_COMPONENTTERMINATECALLBACK; + res_lib_amf_componentterminatecallback.header.size = sizeof (struct res_lib_amf_componentterminatecallback); + res_lib_amf_componentterminatecallback.header.error = SA_AIS_OK; + + + memcpy (&res_lib_amf_componentterminatecallback.compName, + &comp->name, sizeof (SaNameT)); + + component_terminate_callback_data = + malloc (sizeof (struct component_terminate_callback_data)); + if (component_terminate_callback_data == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + component_terminate_callback_data->comp = comp; + + res_lib_amf_componentterminatecallback.invocation = + invocation_create ( + AMF_RESPONSE_COMPONENTTERMINATECALLBACK, + component_terminate_callback_data); + dprintf ("Creating invocation %llu", + (unsigned long long)res_lib_amf_componentterminatecallback.invocation); + + openais_conn_send_response ( + openais_conn_partner_get (comp->conn), + &res_lib_amf_componentterminatecallback, + sizeof (struct res_lib_amf_componentterminatecallback)); + + return (0); +} + +static int clc_csi_remove_callback (struct amf_comp *comp) +{ + dprintf ("clc_tcsi_remove_callback\n"); + return (0); +} + +/* + * Clean up completed + */ +static void mcast_cleanup_completion_event (void *context) +{ + struct clc_command_run_data *clc_command_run_data = + (struct clc_command_run_data *)context; + struct req_exec_amf_clc_cleanup_completed req; + struct iovec iovec; + + TRACE2("CLC cleanup done for '%s'", + clc_command_run_data->comp->name.value); + + req.header.size = sizeof (struct req_exec_amf_clc_cleanup_completed); + req.header.id = SERVICE_ID_MAKE (AMF_SERVICE, + MESSAGE_REQ_EXEC_AMF_CLC_CLEANUP_COMPLETED); + + amf_comp_dn_make (clc_command_run_data->comp, &req.compName); + iovec.iov_base = (char *)&req; + iovec.iov_len = sizeof (req); + + assert (totempg_groups_mcast_joined (openais_group_handle, + &iovec, 1, TOTEMPG_AGREED) == 0); +} + +/* + * Cleanup possible operations + */ +static int clc_cli_cleanup (struct amf_comp *comp) +{ + int res; + pthread_t thread; + pthread_attr_t thread_attr; /* thread attribute */ + + struct clc_command_run_data *clc_command_run_data; + + dprintf ("clc_cli_cleanup\n"); + clc_command_run_data = malloc (sizeof (struct clc_command_run_data)); + if (clc_command_run_data == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + clc_command_run_data->comp = comp; + clc_command_run_data->type = CLC_COMMAND_RUN_OPERATION_TYPE_CLEANUP; + clc_command_run_data->completion_callback = mcast_cleanup_completion_event; + + pthread_attr_init (&thread_attr); + pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED); + res = pthread_create (&thread, &thread_attr, clc_command_run, (void *)clc_command_run_data); + if (res != 0) { + log_printf (LOG_LEVEL_ERROR, "pthread_create failed: %d", res); + } +// TODO error code from pthread_create + return (res); +} + +static int clc_cli_cleanup_local (struct amf_comp *comp) +{ + dprintf ("clc_cli_cleanup_local\n"); + return (0); +} + +#if 0 +static int clc_terminate (struct amf_comp *comp) +{ + int res; + + dprintf ("clc terminate for comp %s\n", getSaNameT (&comp->name)); + assert (0); + operational_state_comp_set (comp, SA_AMF_OPERATIONAL_DISABLED); + comp_presence_state_set (comp, SA_AMF_PRESENCE_TERMINATING); + + res = clc_interfaces[comp->comptype]->terminate (comp); + return (0); +} +#endif + +struct amf_healthcheck *amf_comp_find_healthcheck ( + struct amf_comp *comp, SaAmfHealthcheckKeyT *key) +{ + struct amf_healthcheck *healthcheck; + struct amf_healthcheck *ret_healthcheck = 0; + + if (key == NULL) { + return NULL; + } + + for (healthcheck = comp->healthcheck_head; + healthcheck != NULL; + healthcheck = healthcheck->next) { + + if (memcmp (key, &healthcheck->safHealthcheckKey, + sizeof (SaAmfHealthcheckKeyT)) == 0) { + ret_healthcheck = healthcheck; + break; + } + } + + return (ret_healthcheck); +} + +struct amf_comp *amf_comp_create(struct amf_su *su) +{ + struct amf_comp *comp = calloc (1, sizeof (struct amf_comp)); + + if (comp == NULL) { + openais_exit_error(AIS_DONE_OUT_OF_MEMORY); + } + comp->next = su->comp_head; + su->comp_head = comp; + comp->su = su; + comp->saAmfCompOperState = SA_AMF_OPERATIONAL_DISABLED; + comp->saAmfCompPresenceState = SA_AMF_PRESENCE_UNINSTANTIATED; + comp->saAmfCompNumMaxInstantiateWithoutDelay = 2; + comp->saAmfCompNumMaxAmStartAttempt = 2; + comp->saAmfCompNumMaxAmStopAttempt = 2; + + return comp; +} + +struct amf_comp *amf_comp_find (struct amf_cluster *cluster, SaNameT *name) +{ + struct amf_application *app; + struct amf_sg *sg; + struct amf_su *su; + struct amf_comp *comp = NULL; + char *app_name; + char *sg_name; + char *su_name; + char *comp_name; + char *ptrptr; + char *buf; + + /* malloc new buffer since strtok_r writes to its first argument */ + buf = malloc (name->length); + memcpy (buf, name->value,name ->length); + + comp_name = strtok_r(buf, ",", &ptrptr); + su_name = strtok_r(NULL, ",", &ptrptr); + sg_name = strtok_r(NULL, ",", &ptrptr); + app_name = strtok_r(NULL, ",", &ptrptr); + + if (comp_name == NULL || su_name == NULL || + sg_name == NULL || app_name == NULL) { + goto end; + } + + comp_name += 8; + su_name += 6; + sg_name += 6; + app_name += 7; + + for (app = cluster->application_head; app != NULL; app = app->next) { + if (strncmp (app_name, + (char*)app->name.value, app->name.length) == 0) { + for (sg = app->sg_head; sg != NULL; sg = sg->next) { + if (strncmp (sg_name, (char*)sg->name.value, + sg->name.length) == 0) { + for (su = sg->su_head; su != NULL; su = su->next) { + if (strncmp (su_name, (char*)su->name.value, + su->name.length) == 0) { + for (comp = su->comp_head; + comp != NULL; + comp = comp->next) { + if (strncmp (comp_name, + (char*)comp->name.value, + comp->name.length) == 0) { + goto end; + } + } + } + } + } + } + } + } + +end: + free (buf); + return comp; +} + +void amf_comp_healthcheck_deactivate (struct amf_comp *comp) +{ + struct amf_healthcheck *healthcheck; + + if (!amf_su_is_local (comp->su)) + return; + + ENTER ("'%s'\n", getSaNameT (&comp->name)); + + for (healthcheck = comp->healthcheck_head; + healthcheck != NULL; + healthcheck = healthcheck->next) { + + if (healthcheck->active) { + healthcheck_deactivate (healthcheck); + } + } +} + +static void comp_ha_state_set ( struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment, + SaAmfHAStateT ha_state) +{ + csi_assignment->saAmfCSICompHAState = ha_state; + TRACE1 ("Setting comp '%s' HA state: %s\n", + comp->name.value, amf_ha_state (csi_assignment->saAmfCSICompHAState)); + amf_su_comp_hastate_changed (comp->su, comp, csi_assignment); +} + +static void comp_presence_state_set (struct amf_comp *comp, + SaAmfPresenceStateT presence_state) +{ + comp->saAmfCompPresenceState = presence_state; + TRACE1 ("Setting comp '%s' presence state: %s\n", + comp->name.value, amf_presence_state (comp->saAmfCompPresenceState)); + + amf_su_comp_state_changed ( + comp->su, comp, SA_AMF_PRESENCE_STATE, presence_state); +} + +static void comp_operational_state_set (struct amf_comp *comp, + SaAmfOperationalStateT oper_state) +{ + comp->saAmfCompOperState = oper_state; + TRACE1 ("Setting comp '%s' operational state: %s\n", + comp->name.value, amf_op_state (comp->saAmfCompOperState)); + amf_su_comp_state_changed ( + comp->su, comp, SA_AMF_OP_STATE, oper_state); +} + +#if 0 +static void lib_csi_remove_request (struct amf_comp *comp, + struct amf_csi *csi) +{ + struct res_lib_amf_csiremovecallback res_lib_amf_csiremovecallback; + struct csi_remove_callback_data *csi_remove_callback_data; + + dprintf ("\t%s\n", getSaNameT (&comp->name)); + + res_lib_amf_csiremovecallback.header.id = MESSAGE_RES_AMF_CSIREMOVECALLBACK; + res_lib_amf_csiremovecallback.header.size = sizeof (struct res_lib_amf_csiremovecallback); + res_lib_amf_csiremovecallback.header.error = SA_AIS_OK; + + csi_remove_callback_data = malloc (sizeof (struct csi_remove_callback_data)); + assert (csi_remove_callback_data); // TODO failure here of malloc + csi_remove_callback_data->csi = csi; + + res_lib_amf_csiremovecallback.invocation = + invocation_create ( + AMF_RESPONSE_CSIREMOVECALLBACK, + csi_remove_callback_data); + + memcpy (&res_lib_amf_csiremovecallback.compName, + &comp->name, sizeof (SaNameT)); + + memcpy (&res_lib_amf_csiremovecallback.csiName, + &csi->name, sizeof (SaNameT)); + + res_lib_amf_csiremovecallback.csiFlags = 0; + + openais_conn_send_response ( + openais_conn_partner_get (comp->conn), + &res_lib_amf_csiremovecallback, + sizeof (struct res_lib_amf_csiremovecallback)); +} +#endif + +static void comp_reassign_csis (struct amf_comp *comp) +{ + struct amf_csi_assignment *csi_assignment = comp->assigned_csis; + + ENTER ("'%s'", comp->name.value); + + for (; csi_assignment; csi_assignment = csi_assignment->comp_next) { + amf_comp_hastate_set (comp, csi_assignment, + csi_assignment->saAmfCSICompHAState); + } +} + +static void healthcheck_deactivate ( + struct amf_healthcheck *healthcheck_active) +{ + dprintf ("deactivating healthcheck for component %s\n", + getSaNameT (&healthcheck_active->comp->name)); + + poll_timer_delete (aisexec_poll_handle, + healthcheck_active->timer_handle_period); + + poll_timer_delete (aisexec_poll_handle, + healthcheck_active->timer_handle_duration); + + invocation_destroy_by_data ((void *)healthcheck_active); + healthcheck_active->active = 0; +} + +/** + * This function is called by the timer subsystem when AMF should request + * a new healthcheck from a component. + * @param data + */ +static void timer_function_healthcheck_next_fn (void *_healthcheck) +{ + struct amf_healthcheck *healthcheck = _healthcheck; + + /* send healthcheck request to component */ + lib_healthcheck_request (healthcheck); + + /* start duration timer for response */ + poll_timer_add (aisexec_poll_handle, + healthcheck->saAmfHealthcheckMaxDuration, + (void *)healthcheck, + timer_function_healthcheck_tmo, + &healthcheck->timer_handle_duration); +} + +/** + * Multicast a healthcheck timeout event. + * @param healthcheck + */ +static void mcast_healthcheck_tmo_event ( + struct amf_healthcheck *healthcheck) +{ + struct req_exec_amf_healthcheck_tmo req_exec; + struct iovec iovec; + req_exec.header.size = sizeof (struct req_exec_amf_healthcheck_tmo); + req_exec.header.id = SERVICE_ID_MAKE (AMF_SERVICE, + MESSAGE_REQ_EXEC_AMF_HEALTHCHECK_TMO); + + amf_comp_dn_make (healthcheck->comp, &req_exec.compName); + memcpy (&req_exec.safHealthcheckKey, + &healthcheck->safHealthcheckKey, sizeof (SaAmfHealthcheckKeyT)); + iovec.iov_base = (char *)&req_exec; + iovec.iov_len = sizeof (req_exec); + + assert (totempg_groups_mcast_joined (openais_group_handle, + &iovec, 1, TOTEMPG_AGREED) == 0); +} + +/** + * This function is called by the timer subsystem when a component has not + * performed a healthcheck on time. + * The event is multicasted to the cluster. + * @param data + */ +static void timer_function_healthcheck_tmo ( + void *_healthcheck) +{ + struct amf_healthcheck *healthcheck = (struct amf_healthcheck *)_healthcheck; + + TRACE2 ("timeout occured on healthcheck for component %s.\n", + getSaNameT (&healthcheck->comp->name)); + + mcast_healthcheck_tmo_event (healthcheck); +} + +static void lib_healthcheck_request (struct amf_healthcheck *healthcheck) +{ + struct res_lib_amf_healthcheckcallback res_lib_amf_healthcheckcallback; + + res_lib_amf_healthcheckcallback.header.id = + MESSAGE_RES_AMF_HEALTHCHECKCALLBACK; + res_lib_amf_healthcheckcallback.header.size = + sizeof (struct res_lib_amf_healthcheckcallback); + res_lib_amf_healthcheckcallback.header.error = SA_AIS_OK; + + res_lib_amf_healthcheckcallback.invocation = + invocation_create (AMF_RESPONSE_HEALTHCHECKCALLBACK, healthcheck); + + amf_comp_dn_make (healthcheck->comp, + &res_lib_amf_healthcheckcallback.compName); + memcpy (&res_lib_amf_healthcheckcallback.key, + &healthcheck->safHealthcheckKey, + sizeof (SaAmfHealthcheckKeyT)); + + TRACE8 ("sending healthcheck request to component %s", + res_lib_amf_healthcheckcallback.compName.value); + openais_conn_send_response ( + openais_conn_partner_get (healthcheck->comp->conn), + &res_lib_amf_healthcheckcallback, + sizeof (struct res_lib_amf_healthcheckcallback)); +} + +static void lib_csi_set_request ( + struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment, + SaAmfHAStateT requested_ha_state) +{ + struct res_lib_amf_csisetcallback* res_lib_amf_csisetcallback; + void* p; + struct amf_csi_attribute *attribute; + size_t char_length_of_csi_attrs=0; + size_t num_of_csi_attrs=0; + int i; + struct amf_csi *csi; + char* csi_attribute_buf; + unsigned int byte_offset; + + csi_assignment->requested_ha_state = requested_ha_state; + csi = csi_assignment->csi; + + dprintf("\t Assigning CSI '%s' state %s to comp '%s'\n", + getSaNameT (&csi->name), amf_ha_state (requested_ha_state), + comp->name.value); + + for (attribute = csi->attributes_head; + attribute != NULL; + attribute = attribute->next) { + for (i = 0; attribute->value[i] != NULL; i++) { + num_of_csi_attrs++; + char_length_of_csi_attrs += strlen(attribute->name); + char_length_of_csi_attrs += strlen(attribute->value[i]); + char_length_of_csi_attrs += 2; + } + } + p = malloc(sizeof(struct res_lib_amf_csisetcallback)+ + char_length_of_csi_attrs); + if (p == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + + res_lib_amf_csisetcallback = (struct res_lib_amf_csisetcallback*)p; + + /* Address of the buffer containing the Csi name value pair */ + csi_attribute_buf = res_lib_amf_csisetcallback->csi_attr_buf; + + /* Byteoffset start at the zero byte */ + byte_offset = 0; + + for (attribute = csi->attributes_head; + attribute != NULL; + attribute = attribute->next) { + + for (i = 0; attribute->value[i] != NULL; i++) { + strcpy(&csi_attribute_buf[byte_offset], (char*)attribute->name); + byte_offset += strlen(attribute->name) + 1; + strcpy(&csi_attribute_buf[byte_offset], (char*)attribute->value[i]); + byte_offset += strlen(attribute->value[i]) + 1; + } + } + + res_lib_amf_csisetcallback->number = num_of_csi_attrs; + res_lib_amf_csisetcallback->csiFlags = SA_AMF_CSI_ADD_ONE; + + switch (requested_ha_state) { + case SA_AMF_HA_ACTIVE: { + res_lib_amf_csisetcallback->csiStateDescriptor.activeDescriptor.activeCompName.length = 0; + res_lib_amf_csisetcallback->csiStateDescriptor.activeDescriptor.transitionDescriptor = + SA_AMF_CSI_NEW_ASSIGN; + break; + } + case SA_AMF_HA_STANDBY: { + res_lib_amf_csisetcallback->csiStateDescriptor.standbyDescriptor.activeCompName.length = 0; + res_lib_amf_csisetcallback->csiStateDescriptor.standbyDescriptor.standbyRank = 1; + break; + } + case SA_AMF_HA_QUIESCED: { + /*TODO*/ + break; + } + case SA_AMF_HA_QUIESCING: { + /*TODO*/ + break; + } + default: { + assert(SA_AMF_HA_ACTIVE||SA_AMF_HA_STANDBY||SA_AMF_HA_QUIESCING||SA_AMF_HA_QUIESCED); + break; + } + } + + res_lib_amf_csisetcallback->header.id = MESSAGE_RES_AMF_CSISETCALLBACK; + res_lib_amf_csisetcallback->header.size = + sizeof (struct res_lib_amf_csisetcallback) + + char_length_of_csi_attrs; + res_lib_amf_csisetcallback->header.error = SA_AIS_OK; + + amf_comp_dn_make (comp, &res_lib_amf_csisetcallback->compName); + amf_csi_dn_make (csi, &res_lib_amf_csisetcallback->csiName); + + res_lib_amf_csisetcallback->haState = requested_ha_state; + res_lib_amf_csisetcallback->invocation = + invocation_create (AMF_RESPONSE_CSISETCALLBACK, csi_assignment); + + openais_conn_send_response (openais_conn_partner_get (comp->conn), + res_lib_amf_csisetcallback, + res_lib_amf_csisetcallback->header.size); + + free(p); +} + +SaAisErrorT amf_comp_register (struct amf_comp *comp) +{ + TRACE2("Exec comp register '%s'", &comp->name.value); + + if (comp->saAmfCompPresenceState == SA_AMF_PRESENCE_RESTARTING) { + comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATED); + if (comp->saAmfCompReadinessState == SA_AMF_READINESS_IN_SERVICE) { + comp_reassign_csis (comp); + } + } else if (comp->saAmfCompPresenceState == SA_AMF_PRESENCE_INSTANTIATING) { + comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATED); + comp_operational_state_set (comp, SA_AMF_OPERATIONAL_ENABLED); + } + else { + assert (0); + } + + return SA_AIS_OK; +} + +void amf_comp_error_report ( + struct amf_comp *comp, SaAmfRecommendedRecoveryT recommendedRecovery) +{ + struct res_lib_amf_componenterrorreport res_lib; + + TRACE2("Exec comp error report '%s'", &comp->name.value); + + if (amf_su_is_local (comp->su)) { + res_lib.header.size = sizeof (struct res_lib_amf_componenterrorreport); + res_lib.header.id = MESSAGE_RES_AMF_COMPONENTERRORREPORT; + res_lib.header.error = SA_AIS_OK; + openais_conn_send_response (comp->conn, &res_lib, sizeof (res_lib)); + } + + /* report to SU and let it handle the problem */ + amf_su_comp_error_suspected (comp->su, comp, recommendedRecovery); +} + +/** + * Healthcheck timeout event handler + * @param comp + * @param healthcheck + */ +void amf_comp_healthcheck_tmo ( + struct amf_comp *comp, struct amf_healthcheck *healthcheck) +{ + TRACE2("Exec healthcheck tmo for '%s'", &comp->name.value); + + /* report to SU and let it handle the problem */ + amf_su_comp_error_suspected ( + comp->su, comp, healthcheck->recommendedRecovery); +} + +/** + * Event method to be called when a cleanup completed event is received + * @param comp + */ +void amf_comp_cleanup_completed (struct amf_comp *comp) +{ + TRACE2("Exec CLC cleanup completed for '%s'", &comp->name.value); + amf_comp_instantiate (comp); +} + +/** + * Handle the request from a component to start a healthcheck + * + * @param comp + * @param healthcheckKey + * @param invocationType + * @param recommendedRecovery + * + * @return SaAisErrorT - return value to component + */ +SaAisErrorT amf_comp_healthcheck_start ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey, + SaAmfHealthcheckInvocationT invocationType, + SaAmfRecommendedRecoveryT recommendedRecovery) +{ + struct amf_healthcheck *healthcheck; + SaAisErrorT error = SA_AIS_OK; + + healthcheck = amf_comp_find_healthcheck (comp, healthcheckKey); + if (healthcheck == 0) { + log_printf (LOG_ERR, "Healthcheckstart: Healthcheck '%s' not found", + healthcheckKey->key); + error = SA_AIS_ERR_NOT_EXIST; + goto error_exit; + } + + dprintf ("Healthcheckstart: '%s', key '%s'", + comp->name.value, healthcheckKey->key); + + /* + * Determine if this healthcheck is already active + */ + if (healthcheck->active) { + error = SA_AIS_ERR_EXIST; + goto error_exit; + } + + /* + * Initialise + */ + healthcheck->invocationType = invocationType; + healthcheck->recommendedRecovery = recommendedRecovery; + healthcheck->timer_handle_duration = 0; + healthcheck->timer_handle_period = 0; + healthcheck->active = 1; + + if (invocationType == SA_AMF_HEALTHCHECK_AMF_INVOKED) { + /* start timer to execute first healthcheck request */ + poll_timer_add (aisexec_poll_handle, + healthcheck->saAmfHealthcheckPeriod, + (void *)healthcheck, + timer_function_healthcheck_next_fn, + &healthcheck->timer_handle_period); + } else if (invocationType == SA_AMF_HEALTHCHECK_COMPONENT_INVOKED) { + /* start supervision timer */ + poll_timer_add (aisexec_poll_handle, + healthcheck->saAmfHealthcheckPeriod, + (void *)healthcheck, + timer_function_healthcheck_tmo, + &healthcheck->timer_handle_period); + } else { + error = SA_AIS_ERR_INVALID_PARAM; + } + +error_exit: + return error; +} + +/** + * Stop all or a specifed healthcheck + * @param comp + * @param healthcheckKey - NULL if all + * + * @return SaAisErrorT + */ +SaAisErrorT amf_comp_healthcheck_stop ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey) +{ + struct amf_healthcheck *healthcheck; + SaAisErrorT error = SA_AIS_OK; + + dprintf ("Healthcheckstop: '%s', key '%s'", + comp->name.value, healthcheckKey->key); + + if (healthcheckKey == NULL) { + for (healthcheck = comp->healthcheck_head; + healthcheck != NULL; + healthcheck = healthcheck->next) { + healthcheck_deactivate (healthcheck); + } + } else { + healthcheck = amf_comp_find_healthcheck (comp, healthcheckKey); + if (healthcheck == NULL) { + log_printf (LOG_ERR, "Healthcheckstop: Healthcheck '%s' not found", + healthcheckKey->key); + error = SA_AIS_ERR_NOT_EXIST; + } else { + healthcheck_deactivate (healthcheck); + } + } + + return error; +} + +/** + * Instantiate a component + * @param comp + */ +void amf_comp_instantiate (struct amf_comp *comp) +{ + int res = 0; + + ENTER ("'%s'", getSaNameT (&comp->name)); + + if (comp->saAmfCompPresenceState != SA_AMF_PRESENCE_RESTARTING) { + comp_presence_state_set (comp, SA_AMF_PRESENCE_INSTANTIATING); + } + + if (amf_su_is_local (comp->su)) { + res = clc_interfaces[comp->comptype]->instantiate (comp); + } +} + +void amf_comp_readiness_state_set (struct amf_comp *comp, + SaAmfReadinessStateT state) +{ +#if 0 + /* + * Set component readiness state appropriately + * if unit in service and component is enabled, it is in service + * otherwise it is out of service page 50 B.02.01 + */ + if (comp->su->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE && + comp->saAmfCompOperState == SA_AMF_OPERATIONAL_ENABLED) { + comp->saAmfCompReadinessState = SA_AMF_READINESS_IN_SERVICE; + } else if (comp->su->saAmfSUReadinessState == SA_AMF_READINESS_STOPPING && + comp->saAmfCompOperState == SA_AMF_OPERATIONAL_ENABLED) { + comp->saAmfCompReadinessState = SA_AMF_READINESS_STOPPING; + } else { + comp->saAmfCompReadinessState = SA_AMF_READINESS_OUT_OF_SERVICE; + } +#endif + + comp->saAmfCompReadinessState = state; + TRACE1 ("Setting comp '%s' readiness state: %s\n", + comp->name.value, amf_readiness_state (comp->saAmfCompReadinessState)); +} + +/** + * Handle a component response (received from the lib) of an earlier AMF request. + * This function should be invoked when the lib request is received. + * @param invocation [in] associates the response with the request (callback) + * @param error [in] response from the component of the associated callback + * @param retval [out] contains return value to component when needed + * + * @return ==0 respond to component, do not multicast + * @return >0 do not respond to component, multicast response + */ +int amf_comp_response_1 ( + SaInvocationT invocation, SaAisErrorT error, SaAisErrorT *retval) +{ + int res; + int interface; + void *data; + + res = invocation_get (invocation, &interface, &data); + + if (res == -1) { + log_printf (LOG_ERR, "Lib response: invocation not found\n"); + *retval = SA_AIS_ERR_INVALID_PARAM; + return 0; + } + + switch (interface) { + case AMF_RESPONSE_HEALTHCHECKCALLBACK: { + struct amf_healthcheck *healthcheck = data; + SaNameT name; + TRACE3 ("Healthcheck response from '%s': %d", + amf_comp_dn_make (healthcheck->comp, &name), error); + + if (healthcheck->invocationType == SA_AMF_HEALTHCHECK_AMF_INVOKED) { + /* the response was on time, delete supervision timer */ + poll_timer_delete (aisexec_poll_handle, + healthcheck->timer_handle_duration); + healthcheck->timer_handle_duration = 0; + + /* start timer to execute next healthcheck request */ + poll_timer_add (aisexec_poll_handle, + healthcheck->saAmfHealthcheckPeriod, + (void *)healthcheck, + timer_function_healthcheck_next_fn, + &healthcheck->timer_handle_period); + *retval = SA_AIS_OK; + } else { + *retval = SA_AIS_ERR_INVALID_PARAM; + } + + return 0; /* do not multicast event */ + break; + } + case AMF_RESPONSE_CSISETCALLBACK: /* fall-through */ + case AMF_RESPONSE_CSIREMOVECALLBACK: + return 1; /* multicast event */ + break; +#if 0 + case AMF_RESPONSE_COMPONENTTERMINATECALLBACK: { + struct component_terminate_callback_data *component_terminate_callback_data; + component_terminate_callback_data = data; + + dprintf ("Lib component terminate callback response, error: %d", error); + amf_comp_healthcheck_deactivate (component_terminate_callback_data->comp); + escalation_policy_restart (component_terminate_callback_data->comp); + return 1; + break; + } +#endif + default: + assert (0); + break; + } +} + +/** + * Handle a component response (received from EVS) of an earlier AMF request. + * This function should be invoked when the multicast request is received. + * @param invocation [in] associates the response with the request (callback) + * @param error [in] response from the component of the associated callback + * @param retval [out] contains return value to component when needed + * + * @return component to which the response should be sent + */ +struct amf_comp *amf_comp_response_2 ( + SaInvocationT invocation, SaAisErrorT error, SaAisErrorT *retval) +{ + int res; + int interface; + void *data; + struct amf_comp *comp = NULL; + + assert (retval != NULL); + + *retval = SA_AIS_OK; + + res = invocation_get_and_destroy (invocation, &interface, &data); + if (res == -1) { + log_printf (LOG_ERR, "Comp response: invocation not found\n"); + *retval = SA_AIS_ERR_INVALID_PARAM; + return NULL; + } + + switch (interface) { + case AMF_RESPONSE_CSISETCALLBACK: { + struct amf_csi_assignment *csi_assignment = data; + dprintf ("CSI '%s' set callback response from '%s', error: %d", + csi_assignment->csi->name.value, csi_assignment->comp->name.value, error); + comp = csi_assignment->comp; + if (error == SA_AIS_OK) { + comp_ha_state_set (comp, csi_assignment, + csi_assignment->requested_ha_state); + } else if (error == SA_AIS_ERR_FAILED_OPERATION) { + amf_su_comp_error_suspected (comp->su, comp, + comp->saAmfCompRecoveryOnError); + } else { + *retval = SA_AIS_ERR_INVALID_PARAM; + } + break; + } + case AMF_RESPONSE_CSIREMOVECALLBACK: { + struct amf_csi_assignment *csi_assignment = data; + dprintf ("Lib csi '%s' remove callback response from '%s', error: %d", + csi_assignment->csi->name.value, csi_assignment->comp->name.value, error); + comp = csi_assignment->comp; + amf_su_comp_hastate_changed (comp->su, comp, csi_assignment); + break; + } +#if 0 + case AMF_RESPONSE_COMPONENTTERMINATECALLBACK: + break; +#endif + default: + assert (0); + break; + } + + return comp; +} + +/** + * Request a component to assume a particular HA state + * @param comp + * @param csi_assignment + * @param requested_ha_state + */ +void amf_comp_hastate_set ( + struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment, + SaAmfHAStateT requested_ha_state) +{ + assert (comp != NULL && csi_assignment != NULL); + + if (!amf_su_is_local (comp->su)) + return; + + lib_csi_set_request(comp, csi_assignment, requested_ha_state); +} + +/** + * Request termination of a component + * @param comp + */ +void amf_comp_terminate (struct amf_comp *comp) +{ + dprintf ("comp terminate '%s'\n", getSaNameT (&comp->name)); + amf_comp_healthcheck_stop (comp, NULL); + comp_presence_state_set (comp, SA_AMF_PRESENCE_TERMINATING); + + if (amf_su_is_local (comp->su)) { + clc_interfaces[comp->comptype]->terminate (comp); + } +} + +/** + * Request restart of a component + * @param comp + */ +void amf_comp_restart (struct amf_comp *comp) +{ + dprintf ("comp restart '%s'\n", getSaNameT (&comp->name)); + amf_comp_healthcheck_stop (comp, NULL); + comp_presence_state_set (comp, SA_AMF_PRESENCE_RESTARTING); + + if (amf_su_is_local (comp->su)) { + clc_interfaces[comp->comptype]->cleanup (comp); + } +} + +/** + * Request to return the HA state for a components CSI + * @param comp + * @param csi_name + * @param ha_state + * + * @return SaAisErrorT + */ +SaAisErrorT amf_comp_hastate_get ( + struct amf_comp *comp, SaNameT *csi_name, SaAmfHAStateT *ha_state) +{ + struct amf_csi_assignment *assignment; + SaNameT name; + + assert (comp != NULL && csi_name != NULL && ha_state != NULL); + + dprintf ("comp ha state get from comp '%s' CSI '%s'\n", + getSaNameT (&comp->name), csi_name->value); + + for (assignment = comp->assigned_csis; + assignment != NULL; assignment = assignment->comp_next) { + amf_csi_dn_make (assignment->csi, &name); + if (name_match (csi_name, &name)) { + *ha_state = assignment->saAmfCSICompHAState; + return SA_AIS_OK; + } + } + + return SA_AIS_ERR_INVALID_PARAM; +} + +/** + * Response from a component informs AMF that it has performed a healthcheck + * @param comp + * @param healthcheckKey + * @param healthcheckResult + * + * @return SaAisErrorT + */ +SaAisErrorT amf_comp_healthcheck_confirm ( + struct amf_comp *comp, + SaAmfHealthcheckKeyT *healthcheckKey, + SaAisErrorT healthcheckResult) +{ + struct amf_healthcheck *healthcheck; + SaAisErrorT error = SA_AIS_OK; + + dprintf ("Healthcheckconfirm: '%s', key '%s'", + comp->name.value, healthcheckKey->key); + + healthcheck = amf_comp_find_healthcheck (comp, healthcheckKey); + if (healthcheck == NULL) { + log_printf (LOG_ERR, "Healthcheckstop: Healthcheck '%s' not found", + healthcheckKey->key); + error = SA_AIS_ERR_NOT_EXIST; + } else if (healthcheck->active) { + if (healthcheckResult == SA_AIS_OK) { + /* the response was on time, restart the supervision timer */ + poll_timer_delete (aisexec_poll_handle, + healthcheck->timer_handle_period); + poll_timer_add (aisexec_poll_handle, + healthcheck->saAmfHealthcheckPeriod, + (void *)healthcheck, + timer_function_healthcheck_tmo, + &healthcheck->timer_handle_period); + } else if (healthcheckResult == SA_AIS_ERR_FAILED_OPERATION) { + /* send to cluster */ + mcast_healthcheck_tmo_event (healthcheck); + } else { + error = SA_AIS_ERR_INVALID_PARAM; + } + } else { + error = SA_AIS_ERR_INVALID_PARAM; + } + + return error; +} + +void amf_comp_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfconfig.h b/exec/amfconfig.h deleted file mode 100644 index 5d9fe507..00000000 --- a/exec/amfconfig.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2002-2005 MontaVista Software, Inc. - * Author: Steven Dake (sdake@mvista.com) - * - * Copyright (c) 2006 Ericsson AB. - * Author: Hans Feldt - * Description: Reworked to match AMF B.02 information model - * - * All rights reserved. - * This software licensed under BSD license, the text of which follows: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of the MontaVista Software, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "../include/saAis.h" -#include "../include/saAmf.h" -#include "../include/list.h" -#include "aispoll.h" - -#ifndef AMFCONFIG_H_DEFINED -#define AMFCONFIG_H_DEFINED - - -enum escalation_levels { - ESCALATION_LEVEL_NO_ESCALATION = 1, /* execute component restart */ - ESCALATION_LEVEL_ONE = 2, /* escalate to service unit restart */ - ESCALATION_LEVEL_TWO = 3, /* escalate to service unit failover */ - ESCALATION_LEVEL_THREE = 4 /* escalate to node failover */ -}; - -enum clc_component_types { - clc_component_sa_aware = 0, /* sa aware */ - clc_component_proxied_pre = 1, /* proxied, pre-instantiable */ - clc_component_proxied_non_pre = 2, /* proxied, non pre-instantiable */ - clc_component_non_proxied_non_sa_aware = 3 /* non-proxied, non sa aware */ -}; - -struct amf_si_assignment; -struct amf_csi_assignment; -struct amf_healthcheck; - -struct amf_cluster { - /* Configuration Attributes */ - SaNameT name; - int saAmfClusterStartupTimeout; - SaNameT saAmfClusterClmCluster; - - /* Runtime Attributes */ - SaAmfAdminStateT saAmfClusterAdminState; - - /* Relations */ - struct amf_node *node_head; - struct amf_application *application_head; - - /* Implementation */ - poll_timer_handle timeout_handle; -}; - -struct amf_node { - /* Configuration Attributes */ - SaNameT name; - SaNameT saAmfNodeClmNode; - int saAmfNodeSuFailOverProb; - SaUint32T saAmfNodeSuFailoverMax; - SaBoolT saAmfNodeAutoRepair; - SaBoolT saAmfNodeRebootOnInstantiationFailure; - SaBoolT saAmfNodeRebootOnTerminationFailure; - - /* Runtime Attributes */ - SaAmfAdminStateT saAmfNodeAdminState; - SaAmfOperationalStateT saAmfNodeOperState; - - /* Relations */ - struct amf_cluster *cluster; - - /* Implementation */ - struct amf_node *next; -}; - -struct amf_application { - /* Configuration Attributes */ - SaNameT name; - - /* Runtime Attributes */ - SaAmfAdminStateT saAmfApplicationAdminState; - SaUint32T saAmfApplicationCurrNumSG; - - /* Relations */ - struct amf_cluster *cluster; - struct amf_sg *sg_head; - struct amf_si *si_head; - - /* Implementation */ - char clccli_path[PATH_MAX]; - char binary_path[PATH_MAX]; - struct amf_application *next; -}; - -struct amf_sg { - /* Configuration Attributes */ - SaNameT name; - saAmfRedundancyModelT saAmfSGRedundancyModel; - SaBoolT saAmfSGAutoAdjust; - SaUint32T saAmfSGNumPrefActiveSUs; - SaUint32T saAmfSGNumPrefStandbySUs; - SaUint32T saAmfSGNumPrefInserviceSUs; - SaUint32T saAmfSGNumPrefAssignedSUs; - SaUint32T saAmfSGMaxActiveSIsperSUs; - SaUint32T saAmfSGMaxStandbySIsperSUs; - SaTimeT saAmfSGCompRestartProb; - SaUint32T saAmfSGCompRestartMax; - SaTimeT saAmfSGSuRestartProb; - SaUint32T saAmfSGSuRestartMax; - SaTimeT saAmfSGAutoAdjustProb; - SaBoolT saAmfSGAutoRepair; - - /* Runtime Attributes */ - SaAmfAdminStateT saAmfSGAdminState; - SaUint32T saAmfSGNumCurrAssignedSUs; - SaUint32T saAmfSGNumCurrNonInstantiatedSpareSUs; - SaUint32T saAmfSGNumCurrInstantiatedSpareSUs; - - /* Relations */ - struct amf_application *application; - struct amf_su *su_head; - - /* Implementation */ - char clccli_path[PATH_MAX]; - char binary_path[PATH_MAX]; - struct amf_sg *next; -}; - -struct amf_su { - /* Configuration Attributes */ - SaNameT name; - SaUint32T saAmfSURank; - SaUint32T saAmfSUNumComponents; - SaBoolT saAmfSUIsExternal; - SaBoolT saAmfSUFailover; - - /* Runtime Attributes */ - SaBoolT saAmfSUPreInstantiable; - SaAmfOperationalStateT saAmfSUOperState; - SaAmfAdminStateT saAmfSUAdminState; - SaAmfReadinessStateT saAmfSUReadinessState; - SaAmfPresenceStateT saAmfSUPresenceState; - SaNameT saAmfSUAssignedSIs; - SaNameT saAmfSUHostedByNode; - SaUint32T saAmfSUNumCurrActiveSIs; - SaUint32T saAmfSUNumCurrStandbySIs; - SaUint32T saAmfSURestartCount; - - /* Relations */ - struct amf_sg *sg; - struct amf_comp *comp_head; - struct amf_si_assignment *assigned_sis; - - /* Implementation */ - int is_local; - char clccli_path[PATH_MAX]; - char binary_path[PATH_MAX]; - SaUint32T su_failover_cnt; /* missing in SAF specs? */ - enum escalation_levels escalation_level; - struct amf_su *next; -}; - -struct amf_comp { - /* Configuration Attributes */ - SaNameT name; - SaNameT **saAmfCompCsTypes; - saAmfCompCategoryT saAmfCompCategory; - saAmfCompCapabilityModelT saAmfCompCapability; - SaUint32T saAmfCompNumMaxActiveCsi; - SaUint32T saAmfCompNumMaxStandbyCsi; - SaStringT *saAmfCompCmdEnv; - int saAmfCompDefaultClcCliTimeout; - int saAmfCompDefaultCallbackTimeOut; - SaStringT saAmfCompInstantiateCmd; - SaStringT saAmfCompInstantiateCmdArgv; - int saAmfCompInstantiateTimeout; - SaUint32T saAmfCompInstantiationLevel; - SaUint32T saAmfCompNumMaxInstantiateWithoutDelay; - SaUint32T saAmfCompNumMaxInstantiateWithDelay; - int saAmfCompDelayBetweenInstantiateAttempts; - SaStringT saAmfCompTerminateCmd; - int saAmfCompTerminateTimeout; - SaStringT saAmfCompTerminateCmdArgv; - SaStringT saAmfCompCleanupCmd; - int saAmfCompCleanupTimeout; - SaStringT saAmfCompCleanupCmdArgv; - SaStringT saAmfCompAmStartCmd; - int saAmfCompAmStartTimeout; - SaStringT saAmfCompAmStartCmdArgv; - SaUint32T saAmfCompNumMaxAmStartAttempt; - SaStringT saAmfCompAmStopCmd; - int saAmfCompAmStopTimeout; - SaStringT saAmfCompAmStopCmdArgv; - SaUint32T saAmfCompNumMaxAmStopAttempt; - int saAmfCompTerminateCallbackTimeout; - int saAmfCompCSISetCallbackTimeout; - int saAmfCompQuiescingCompleteTimeout; - int saAmfCompCSIRmvCallbackTimeout; - SaAmfRecommendedRecoveryT saAmfCompRecoveryOnError; - SaBoolT saAmfCompDisableRestart; - SaNameT saAmfCompProxyCsi; - - /* Runtime Attributes */ - SaAmfOperationalStateT saAmfCompOperState; - SaAmfReadinessStateT saAmfCompReadinessState; - SaAmfPresenceStateT saAmfCompPresenceState; - SaUint32T saAmfCompRestartCount; - SaUint32T saAmfCompNumCurrActiveCsi; - SaUint32T saAmfCompNumCurrStandbyCsi; - SaNameT saAmfCompAssignedCsi; - SaNameT saAmfCompCurrProxyName; - SaNameT saAmfCompCurrProxiedNames; - - /* Relations */ - struct amf_comp *proxy_comp; - struct amf_su *su; - struct amf_csi_assignment *assigned_csis; - - /* Implementation */ - char clccli_path[PATH_MAX]; - char binary_path[PATH_MAX]; - struct amf_comp *next; - void *conn; - enum clc_component_types comptype; - struct amf_healthcheck *healthcheck_head; -}; - -struct amf_healthcheck { - /* Configuration Attributes */ - SaAmfHealthcheckKeyT safHealthcheckKey; - int saAmfHealthcheckMaxDuration; - int saAmfHealthcheckPeriod; - - /* Relations */ - struct amf_comp *comp; - - /* Implementation */ - struct amf_healthcheck *next; - SaAmfHealthcheckInvocationT invocationType; - poll_timer_handle timer_handle_duration; - poll_timer_handle timer_handle_period; - int active; -}; - -struct amf_si { - /* Configuration Attributes */ - SaNameT name; - SaNameT saAmfSIProtectedbySG; - SaUint32T saAmfSIRank; - SaUint32T saAmfSINumCSIs; - SaUint32T saAmfSIPrefActiveAssignments; - SaUint32T saAmfSIPrefStandbyAssignments; - - /* Runtime Attributes */ - SaAmfAdminStateT saAmfSIAdminState; - SaAmfAssignmentStateT saAmfSIAssignmentState; - SaUint32T saAmfSINumCurrActiveAssignments; - SaUint32T saAmfSINumCurrStandbyAssignments; - - /* Relations */ - struct amf_application *application; - struct amf_csi *csi_head; - struct amf_si_assignment *si_assignments; - struct amf_si_dependency *depends_on; - struct amf_si_ranked_su *ranked_sus; - - /* Implementation */ - struct amf_si *next; -}; - -struct amf_si_ranked_su { - /* Configuration Attributes */ - SaNameT name; - SaUint32T saAmfRank; - - /* Relations */ - struct amf_si *si; - struct amf_su *su; - - /* Implementation */ - struct amf_si_ranked_su *su_next; - struct amf_si_ranked_su *si_next; -}; - -struct amf_si_dependency { - /* Configuration Attributes */ - SaNameT name; - int saAmfToleranceTime; - - /* Relations */ - - /* Implementation */ - struct amf_si_dependency *next; -}; - -struct amf_si_assignment { - /* Runtime Attributes */ - SaNameT name; - SaAmfHAStateT saAmfSISUHAState; - - /* Relations */ - struct amf_si *si; - - /* Implementation */ - struct amf_si_assignment *next; -}; - -struct amf_csi { - /* Configuration Attributes */ - SaNameT name; - SaNameT saAmfCSTypeName; - SaNameT **saAmfCSIDependencies; - - /* Relations */ - struct amf_si *si; - struct amf_csi_assignment *csi_assignments; - struct amf_csi_attribute *attributes_head; - - /* Implementation */ - struct amf_csi *next; - int pg_set; -}; - -struct amf_csi_attribute { - /* Configuration Attributes */ - SaStringT name; - SaStringT *value; - - /* Implementation */ - struct amf_csi_attribute *next; -}; - -struct amf_csi_assignment { - /* Runtime Attributes */ - SaNameT name; - SaAmfHAStateT saAmfCSICompHASate; - - /* Relations */ - struct amf_csi *csi; - struct amf_comp *comp; - - /* Implementation */ - struct amf_csi_assignment *comp_next; - struct amf_csi_assignment *csi_next; -}; - -extern struct amf_comp *amf_find_comp (struct amf_cluster *cluster, SaNameT *name); -extern struct amf_healthcheck *amf_find_healthcheck (struct amf_comp *comp, SaAmfHealthcheckKeyT *key); -extern int amf_config_read (struct amf_cluster *cluster, char **error_string); - -#endif /* AMFCONFIG_H_DEFINED */ diff --git a/exec/amfnode.c b/exec/amfnode.c new file mode 100644 index 00000000..4cd94202 --- /dev/null +++ b/exec/amfnode.c @@ -0,0 +1,107 @@ +/** @file amfnode.c + * + * Copyright (c) 2006 Ericsson AB. + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Node Class Implementation + * + * This file contains functions for handling AMF nodes. It can be + * viewed as the implementation of the AMF Node class (called NODE) + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * - controlling the instantiation of the SUs hosted on current node and + * controlling the assigning of workload to them when a node joins the + * cluster (cluster start is controlled by the Cluster Class) + * - controlling node level recovery and repair functions + * - implementing error escallation level 2 and 3 (paragraph 3.12.2.2 and + * 3.12.2.3 in the spec) + * - handling run time attributes of the AMF NODE; cached + * attributes are stored as variables and sent to the IMM service (future) + * upon the changes described in the specification + * + * The node class contains the following state machines: + * - administrative state machine (ADSM) + * - operational state machine (OPSM) + * - availability control state machine (ACSM) + * + * The administrative state machine will be implemented in the future. + * + * The operational state machine is primarily used to report status of the + * node. + * + * The availability control state machine is used for control purposes. + * ACSM contains three states of which two are composite. + * Being a composite state means that the state contains substates. + * ACSM states are: + * - REPAIR_NEEDED + * - ESCALLATION_LEVEL (LEVEL_0, LEVEL_2 and LEVEL_3) + * - MANAGING_HOSTED_SERVICE_UNITS ( + * . FAILING_FAST (REBOOTING_NODE and ACTIVATING_STANDBY_NODE) + * . FAILING_GRACEFULLY (SWITCHING_OVER, FAILING_OVER and REBOOTING_NODE) + * . LEAVING_SPONTANEOUSLY (DEACTIVATE_DEPENDENT and + * WAITING_FOR_NODE_TO_JOIN) + * . JOINING (STARTING_SERVICE_UNITS, ASSIGNING_ACTIVE_WORKLOAD and + * ASSIGNING_STANDBY_WORKLOAD) + * + * REPAIR_NEEDED indicates the node needs a manual repair and this state will + * maintained until the administrative command REPAIRED is entered + * (implemented in the future) + * + * ESCALLATION_LEVEL is a kind of idle state where no actions are performed + * and used only to remember the escallation level. Substate LEVEL_0 indicates + * no escallation. LEVEL_2 indicates that so many component restarts have been + * executed recently that a new component restart request will escalate + * to service unit restart action. Node will request a service unit restart + * from SU. + * LEVEL_3 will be entered if either there are too many service unit restarts + * been made or a component failover recovery action is requested. On level 3 + * the recovery action performed is service unit failover (paragraph 3.12.1.3). + * + * FAILING_FAST state executes a node re-boot and waits for the node to join + * the cluster again. + * + * FAILING_GRACEFULLY state requests all SGs which have SUs hosted on current + * node to switch or failover according to the procedures described in + * paragraphs 3.12.1.3 before re-boot is executed. Then the confirmation is + * awaited from all concerned SGs and finally a node re-boot is executed as + * the repair action (see paragraph 2.12.1.4). + * + * LEAVING_SPONTANEOUSLY state handles the spontaneous leave of a node. + * + * JOINING state handles the start of a node in all cases except cluster start, + * which is handled by the CLUSTER class. + * + */ + diff --git a/exec/amfsg.c b/exec/amfsg.c new file mode 100644 index 00000000..58b1dcff --- /dev/null +++ b/exec/amfsg.c @@ -0,0 +1,422 @@ +/** @file amfsg.c + * + * Copyright (c) 2002-2006 MontaVista Software, Inc. + * Author: Steven Dake (sdake@mvista.com) + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Introduced AMF B.02 information model + * - Use DN in API and multicast messages + * - (Re-)Introduction of event based multicast messages + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Service Group Class Implementation + * + * This file contains functions for handling AMF-service groups(SGs). It can be + * viewed as the implementation of the AMF Service Group class (called SG) + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * -on request start the service group by instantiating the contained SUs + * -on request assign the service instances it protects to the in-service + * service units it contains respecting as many as possible of the configured + * requirements for the group + * -create and delete an SI-assignment object for each relation between + * an SI and an SU + * -order each contained SU to create and delete CSI-assignments + * -request the Service Instance class (SI) to execute the transfer of the + * HA-state set/remove requests to each component involved + * -fully control the execution of component failover and SU failover + * -on request control the execution of the initial steps of node switchover + * and node failover + * -fully handle the auto adjust procedure + * + * Currently only the 'n+m' redundancy model is implemented. It is the + * ambition to identify n+m specific variables and functions and add the suffix + * '_nplusm' to them so that they can be easily recognized. + * + * When SG is requested to assign workload to all SUs or all SUs hosted on + * a specific node, a procedure containing several steps is executed: + * <1> An algorithm is executed which assigns SIs to SUs respecting the rules + * that has been configured for SG. The algorithm also has to consider + * if assignments between som SIs and SUs already exist. The scope of this + * algorithm is to create SI-assignments and set up requested HA-state for + * each assignment but not to transfer those HA-states to the components. + * <2> All SI-assignments with a requested HA state == ACTIVE are transferred + * to the components concerned before any STANDBY assignments are + * transferred. All components have to acknowledge the setting of the + * ACTIVE HA state before the transfer of any STANDBY assignment is + * initiated. + * <3> All active assignments can not be transferred at the same time to the + * different components because the rules for dependencies between SI and + * SI application wide and CSI and CSI within one SI, has to be respected. + * + * SG is fully responsible for step <1> but not fully responsible for handling + * step <2> and <3>. However, SG uses an attribute called 'dependency level' + * when requsted to assign workload. This parameter refers to an integer that + * has been calculated initially for each SI. The 'dependency level' indicates + * to which extent an SI depends on other SIs such that an SI that depends on + * no other SI is on dependecy_level == 1, an SI that depends only on an SI on + * dependency_level == 1 is on dependency-level == 2. + * An SI that depends on several SIs gets a + * dependency_level that is one unit higher than the SI with the highest + * dependency_level it depends on. When SG is requested to assign the workload + * on a certain dependency level, it requests all SI objects on that level to + * activate (all) SI-assignments that during step <1> has been requested to + * assume the active HA state. + * + * SG contains the following state machines: + * - administrative state machine (ADSM) (NOT IN THIS RELEASE) + * - availability control state machine (ACSM) + * + * The availability control state machine contains two states and one of them + * is composite. Being a composite state means that it contains substates. + * The states are: + * - IDLE (non composite state) + * - MANAGING_SG (composite state) + * MANAGING_SG is entered at several different events which has in common + * the need to set up or change the assignment of SIs to SUs. Only one such + * event can be handled at the time. If new events occur while one event is + * being handled then the new event is saved and will be handled after the + * handling of the first event is ready (return to IDLE state has been done). + * MANAGING_SG handles the following events: + * - start (requests SG to order SU to instantiate all SUs in SG and waits + * for SU to indicate presence state change reports from the SUs and + * finally responds 'started' to the requester) + * - assign (requests SG to assign SIs to SUs according to pre-configured + * rules (if not already done) and transfer the HA state of + * the SIs on the requested SI dependency level. Then SG waits for + * confirmation that the HA state has been succesfully set and + * finally responds 'assigned' to the reqeuster) + * - auto_adjust (this event indicates that the auto-adjust probation timer has + * expired and that SG should evaluate current assignments of + * SIs to SUs and if needed remove current assignments and + * create new according to what is specified in paragraph + * 3.7.1.2) + * - failover_comp (requests SG to failover a specific component according to + * the procedure described in paragraph 3.12.1.3) + * - failover_su (requests SG to failover a specific SU according to the + * procedure described in paragraph 3.12.1.3 and 3.12.1.4) + * - switchover_node (requests SG to execute the recovery actions described + * in 3.12.1.3 and respond to the requester when recovery + * is completed) + * - failover_node (requests SG to execute the recovery actions described + * in 3.12.1.3 and respond to the requester when recovery is + * completed) + * + */ + +#include +#include + +#include "amf.h" +#include "print.h" +#include "main.h" + +static inline int div_round (int a, int b) +{ + int res; + + res = a / b; + if ((a % b) != 0) + res++; + return res; +} + +static int sg_all_su_in_service(struct amf_sg *sg) +{ + struct amf_su *su; + struct amf_comp *comp; + int ready = 1; + + for (su = sg->su_head; su != NULL; su = su->next) { + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + if (su->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE) { + ready = 0; + } + } + } + + return ready; +} + +static int application_si_count_get (struct amf_application *app) +{ + struct amf_si *si; + int answer = 0; + + for (si = app->si_head; si != NULL; si = si->next) { + answer += 1; + } + return (answer); +} + +static void sg_assign_nm_active (struct amf_sg *sg, int su_units_assign) +{ + struct amf_su *unit; + struct amf_si *si; + int assigned = 0; + int assign_per_su = 0; + int total_assigned = 0; + + assign_per_su = application_si_count_get (sg->application); + assign_per_su = div_round (assign_per_su, su_units_assign); + if (assign_per_su > sg->saAmfSGMaxActiveSIsperSUs) { + assign_per_su = sg->saAmfSGMaxActiveSIsperSUs; + } + + si = sg->application->si_head; + unit = sg->su_head; + while (unit != NULL) { + if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE || + unit->saAmfSUNumCurrActiveSIs == sg->saAmfSGMaxActiveSIsperSUs || + unit->saAmfSUNumCurrStandbySIs > 0) { + + unit = unit->next; + continue; /* Not in service */ + } + + assigned = 0; + while (si != NULL && + assigned < assign_per_su && + total_assigned < application_si_count_get (sg->application)) { + + assigned += 1; + total_assigned += 1; + amf_su_assign_si (unit, si, SA_AMF_HA_ACTIVE); + si = si->next; + } + unit = unit->next; + } + + if (total_assigned == 0) { + dprintf ("Error: No SIs assigned!"); + } +} + +static void sg_assign_nm_standby (struct amf_sg *sg, int units_assign_standby) +{ + struct amf_su *unit; + struct amf_si *si; + int assigned = 0; + int assign_per_su = 0; + int total_assigned = 0; + + if (units_assign_standby == 0) { + return; + } + assign_per_su = application_si_count_get (sg->application); + assign_per_su = div_round (assign_per_su, units_assign_standby); + if (assign_per_su > sg->saAmfSGMaxStandbySIsperSUs) { + assign_per_su = sg->saAmfSGMaxStandbySIsperSUs; + } + + si = sg->application->si_head; + unit = sg->su_head; + while (unit != NULL) { + if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE || + unit->saAmfSUNumCurrActiveSIs > 0 || + unit->saAmfSUNumCurrStandbySIs == sg->saAmfSGMaxStandbySIsperSUs) { + + unit = unit->next; + continue; /* Not available for assignment */ + } + + assigned = 0; + while (si != NULL && assigned < assign_per_su) { + assigned += 1; + total_assigned += 1; + amf_su_assign_si (unit, si, SA_AMF_HA_STANDBY); + si = si->next; + } + unit = unit->next; + } + if (total_assigned == 0) { + dprintf ("Error: No SIs assigned!"); + } +} +#if 0 +static void assign_nm_spare (struct amf_sg *sg) +{ + struct amf_su *unit; + + for (unit = sg->su_head; unit != NULL; unit = unit->next) { + if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE && + (unit->requested_ha_state != SA_AMF_HA_ACTIVE && + unit->requested_ha_state != SA_AMF_HA_STANDBY)) { + + dprintf ("Assigning to SU %s with SPARE\n", + getSaNameT (&unit->name)); + } + } +} +#endif + +static int su_inservice_count_get (struct amf_sg *sg) +{ + struct amf_su *unit; + int answer = 0; + + for (unit = sg->su_head; unit != NULL; unit = unit->next) { + if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE) { + answer += 1; + } + } + return (answer); +} + +void amf_sg_assign_si (struct amf_sg *sg, int dependency_level) +{ + int active_sus_needed; + int standby_sus_needed; + int inservice_count; + int units_for_standby; + int units_for_active; + int ii_spare; + int su_active_assign; + int su_standby_assign; + int su_spare_assign; + + ENTER ("'%s'", sg->name.value); + /* + * Number of SUs to assign to active or standby state + */ + inservice_count = (float)su_inservice_count_get (sg); + + active_sus_needed = div_round (application_si_count_get (sg->application), + sg->saAmfSGMaxActiveSIsperSUs); + + standby_sus_needed = div_round (application_si_count_get (sg->application), + sg->saAmfSGMaxStandbySIsperSUs); + + units_for_active = inservice_count - sg->saAmfSGNumPrefStandbySUs; + if (units_for_active < 0) { + units_for_active = 0; + } + + units_for_standby = inservice_count - sg->saAmfSGNumPrefActiveSUs; + if (units_for_standby < 0) { + units_for_standby = 0; + } + + ii_spare = inservice_count - sg->saAmfSGNumPrefActiveSUs - sg->saAmfSGNumPrefStandbySUs; + if (ii_spare < 0) { + ii_spare = 0; + } + + /* + * Determine number of active and standby service units + * to assign based upon reduction procedure + */ + if ((inservice_count - active_sus_needed) < 0) { + dprintf ("assignment VI - partial assignment with SIs drop outs\n"); + + su_active_assign = active_sus_needed; + su_standby_assign = 0; + su_spare_assign = 0; + } else + if ((inservice_count - active_sus_needed - standby_sus_needed) < 0) { + dprintf ("assignment V - partial assignment with reduction of standby units\n"); + + su_active_assign = active_sus_needed; + if (standby_sus_needed > units_for_standby) { + su_standby_assign = units_for_standby; + } else { + su_standby_assign = standby_sus_needed; + } + su_spare_assign = 0; + } else + if ((sg->saAmfSGMaxStandbySIsperSUs * units_for_standby) <= application_si_count_get (sg->application)) { + dprintf ("IV: full assignment with reduction of active service units\n"); + su_active_assign = inservice_count - standby_sus_needed; + su_standby_assign = standby_sus_needed; + su_spare_assign = 0; + } else + if ((sg->saAmfSGMaxActiveSIsperSUs * units_for_active) <= application_si_count_get (sg->application)) { + + dprintf ("III: full assignment with reduction of standby service units\n"); + su_active_assign = sg->saAmfSGNumPrefActiveSUs; + su_standby_assign = units_for_standby; + su_spare_assign = 0; + } else + if (ii_spare == 0) { + dprintf ("II: full assignment with spare reduction\n"); + + su_active_assign = sg->saAmfSGNumPrefActiveSUs; + su_standby_assign = sg->saAmfSGNumPrefStandbySUs; + su_spare_assign = 0; + } else { + dprintf ("I: full assignment with spares\n"); + + su_active_assign = sg->saAmfSGNumPrefActiveSUs; + su_standby_assign = sg->saAmfSGNumPrefStandbySUs; + su_spare_assign = ii_spare; + } + + dprintf ("(inservice=%d) (assigning active=%d) (assigning standby=%d) (assigning spares=%d)\n", + inservice_count, su_active_assign, su_standby_assign, su_spare_assign); + sg_assign_nm_active (sg, su_active_assign); + sg_assign_nm_standby (sg, su_standby_assign); + LEAVE ("'%s'", sg->name.value); +} + +void amf_sg_start (struct amf_sg *sg, struct amf_node *node) +{ + struct amf_su *su; + + ENTER ("'%s'", sg->name.value); + + for (su = sg->su_head; su != NULL; su = su->next) { + amf_su_instantiate (su); + } +} + +extern void amf_sg_su_state_changed ( + struct amf_sg *sg, struct amf_su *su, SaAmfStateT type, int state) +{ + if (sg_all_su_in_service(su->sg)) { + TRACE1 ("All SUs in SG '%s' in service, assigning SIs\n", su->sg->name.value); + amf_sg_assign_si (su->sg, 0); + if (amf_cluster.timeout_handle) { + poll_timer_delete (aisexec_poll_handle, amf_cluster.timeout_handle); + } + } +} + +void amf_sg_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfsi.c b/exec/amfsi.c new file mode 100644 index 00000000..0c822a1b --- /dev/null +++ b/exec/amfsi.c @@ -0,0 +1,132 @@ +/** @file amfsi.c + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Workload related classes Implementation + * + * This file contains functions for handling : + * - AMF service instances(SI) + * - AMF SI Dependency + * - AMF SI Ranked SU + * - AMF SI Assignment + * - AMF component service instances (CSI) + * - AMF CSI Assignment + * - AMF CSI Type + * - AMF CSI Attribute + * The file can be viewed as the implementation of the classes listed above + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * - calculating and storing an SI_dependency_level integer per SI + * - calculating and storing a csi_dependency_level integer per CSI + * - on request change HA state of an SI or CSI in such a way that the + * requirements regarding SI -> SI dependencies (paragraphs 3.9.1.1 and + * 3.9.1.2) and CSI -> CSI dependencies (paragraph 3.9.1.3) are fully + * respected + * + * The si_dependency_level is an attribute calculated at init (in the future + * also at reconfiguration) which indicates dependencies between SIs as + * an integer. The si_dependency level indicates to which extent an SI depends + * on other SIs such that an SI that depends on no other SI is on + * si_dependecy_level == 1, an SI that depends only on an SI on + * si_dependency_level == 1 is on si_dependency-level == 2. + * An SI that depends on several SIs gets a si_dependency_level that is one + * unit higher than the SI with the highest si_dependency_level it depends on. + * + * The csi_dependency_level attribute works the same way. + * + * According to paragraph 3.9.1 of the spec, a change to or from the ACTIVE + * HA state is not always allowed without first deactivate dependent SI and CSI + * assignments. Dependencies between CSIs are absolute while an SI that depends + * on another SI may tolerate that the SI on which it depends is inactive for a + * configurable time (the tolerance time). The consequence of this is that a + * request to change the SI state may require a sequence of requests to + * components to assume a new HA state for a CSI-assignment and to guarantee + * the dependency rules, the active response from the component has to be + * awaited before next HA state can be set. + * + * This file implements an SI state machine that fully implements these rules. + * This state machine is called SI Dependency Control State Machine (dcsm) + * and has the following states: + * - DEACTIVATED (there is no SI-assignment with active HA state) + * - ACTIVATING (a request to set the ACTIVE HA state has been received and + * setting ACTIVE HA states to the appropriate components are + * in progress) + * - ACTIVATED (there is at least one SI-assignment with the ACTIVE HA-state) + * - DEACTIVATING (a request to de-activate an SI or only a specific CSI + * within an SI has been received and setting the QUISCED + * HA states to the appropriate components are in progress) + * - DEPENDENCY_DEACTIVATING (the SI-SI dependency tolerance timer has expired + * and setting the QUISCED HA states to the + * appropriate components are in progress) + * - DEPENDENCY_DEACTIVATED (as state DEACTIVATED but will automatically + * transition to state ACTIVATING when the + * dependency problem is solved, i.e. the SI on + * which it depends has re-assumed the ACTIVE HA + * state) + * - SETTING (a request to change the HA state when neither the existing + * nor the requested state is ACTIVE) + * + * This file also implements: + * - SI: Assignment state (for report purposes) + * - SI Assignment: HA state + * - CSI Assignment: HA state + * + */ + +#include +#include +#include "amf.h" +#include "print.h" + +char *amf_csi_dn_make (struct amf_csi *csi, SaNameT *name) +{ + int i = snprintf((char*) name->value, SA_MAX_NAME_LENGTH, + "safCsi=%s,safSi=%s,safApp=%s", + csi->name.value, csi->si->name.value, + csi->si->application->name.value); + assert (i <= SA_MAX_NAME_LENGTH); + name->length = i; + + return (char *)name->value; +} + +void amf_si_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfsu.c b/exec/amfsu.c new file mode 100644 index 00000000..377e5d58 --- /dev/null +++ b/exec/amfsu.c @@ -0,0 +1,456 @@ +/** @file exec/amfsu.c + * + * Copyright (c) 2002-2006 MontaVista Software, Inc. + * Author: Steven Dake (sdake@mvista.com) + * + * Copyright (c) 2006 Ericsson AB. + * Author: Hans Feldt + * - Introduced AMF B.02 information model + * - Use DN in API and multicast messages + * - (Re-)Introduction of event based multicast messages + * - Refactoring of code into several AMF files + * Author: Anders Eriksson + * + * All rights reserved. + * + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF Service Unit Class Implementation + * + * This file contains functions for handling AMF-service units(SUs). It can be + * viewed as the implementation of the AMF Service Unit class (called SU) + * as described in SAI-Overview-B.02.01. The SA Forum specification + * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour + * and is referred to as 'the spec' below. + * + * The functions in this file are responsible for: + * - instantiating and terminating service units on request + * (considering the dependencies between components described in paragraph + * 3.9.2) + * - creating and deleting CSI-assignment objects between its components and + * CSI-objects upon request + * - receiving error reports from its components and forwarding them to + * appropriate handler (SU or SG or node or cluster) + * - implementing restart of itself and its components (paragraph 3.12.1.2) + * - implementing error escallation level 1 (paragraph 3.12.2.2 in the spec) + * - handling all run time attributes of the AMF SU; all cached + * attributes are stored as variables and sent to the IMM service + * upon the changes described in the specification. + * + * SU contains the following state machines: + * - presence state machine (PRSM) + * - administrative state machine (ADSM) (NOT IN THIS RELEASE) + * - operational state machine (OPSM) + * - readiness state machine (RESM) + * - ha state per service instance (SI) + * - restart control state machine (RCSM) + * + * The presence state machine orders intantiation of its components on request. + * It fully respects the dependency rules between components at instantiation + * such that it orders instantiation simultaneously only of components on the + * same instantiation level. The presence state machine is implemented with + * the states described in the spec and the state transitions are trigged by + * reported state transitions from its contained components according to + * paragraph 3.3.1.1. + * + * The operational state machine is not responsible for any control function. + * It assumes the DISABLED state if an incoming operational state change report + * from a component indicates the component has assumed the DISABLED state. + * Operational state changes are reported to IMM. + * + * The readiness state machine is not used for any control but is updated and + * reported to IMM when it is changed. + * + * The restart control state machine (RCSM) is used to implement level 1 of + * the error escallation polycy described in chapter 3.12.2 of the spec. It + * also implements component restart and service unit restart as described in + * paragraph 3.12.1.2 and 3.12.1.3. + * RCSM contains three composite states. + * Being a composite state means that the state contains substates. + * RCSM composite states are: + * - ESCALLATION_LEVEL (LEVEL_0, LEVEL_1 and LEVEL_2) + * - RESTARTING_COMPONENT (DEACTIVATING, RESTARTING, SETTING and ACTIVATING) + * - RESTARTING_SERVICE_UNIT (DEACTIVATING, TERMINATING, INSTANTIATING, + * and ACTIVATING) + * + * ESCALLATION_LEVEL is a kind of idle state where no actions are performed + * and used only to remember the escallation level. Substate LEVEL_0 indicates + * no escallation. LEVEL_1 indicates that a component restart has been + * executed recently and the escallation timer is still running. At this level + * component restart requests will transition to RESTARTING_COMPONENT but + * if there are too many restart requests before the probation timer expires + * then a transition will be made to LEVEL_2 and the restart request will + * be forwarded to the node instance hosting this component. + * State RESTARTING_SERVICE_UNIT will only be assumed if the node explicitly + * requests the SU to execute a restart of itself (after having evaluated its + * part of the error escallation policy). + * + */ + + /* + * + */ + +#include +#include +#include +#include + +#include "amf.h" +#include "util.h" +#include "print.h" +#include "main.h" + +static int presence_state_all_comps_in_su_are_set (struct amf_su *su, + SaAmfPresenceStateT state) +{ + int all_set = 1; + struct amf_comp *comp; + + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + if (comp->saAmfCompPresenceState != state) { + all_set = 0; + } + } + + return all_set; +} + +static void su_readiness_state_set (struct amf_su *su, + SaAmfReadinessStateT readiness_state) +{ + su->saAmfSUReadinessState = readiness_state; + TRACE1 ("Setting SU '%s' readiness state: %s\n", + &su->name.value, amf_readiness_state(readiness_state)); +} + +static void su_presence_state_set (struct amf_su *su, + SaAmfPresenceStateT presence_state) +{ + su->saAmfSUPresenceState = presence_state; + TRACE1 ("Setting SU '%s' presence state: %s\n", + su->name.value, amf_presence_state (presence_state)); +} + +static void su_operational_state_set (struct amf_su *su, + SaAmfOperationalStateT oper_state) +{ + struct amf_comp* comp; + + if (oper_state == su->saAmfSUOperState) { + log_printf (LOG_INFO, + "Not assigning service unit new operational state - same state\n"); + return; + } + + su->saAmfSUOperState = oper_state; + TRACE1 ("Setting SU '%s' operational state: %s\n", + su->name.value, amf_op_state (oper_state)); + + if (oper_state == SA_AMF_OPERATIONAL_ENABLED) { + su_readiness_state_set (su, SA_AMF_READINESS_IN_SERVICE); + + for (comp = su->comp_head; comp; comp = comp->next) { + amf_comp_readiness_state_set (comp, SA_AMF_READINESS_IN_SERVICE); + } + + amf_sg_su_state_changed (su->sg, su, SA_AMF_OP_STATE, SA_AMF_OPERATIONAL_ENABLED); + } else if (oper_state == SA_AMF_OPERATIONAL_DISABLED) { + su_readiness_state_set (su, SA_AMF_READINESS_OUT_OF_SERVICE); + } +} + +static void comp_assign_csi (struct amf_comp *comp, struct amf_csi *csi, + SaAmfHAStateT ha_state) +{ + struct amf_csi_assignment *csi_assignment; + + dprintf (" Assigning CSI '%s' to comp '%s' with hastate %s\n", + getSaNameT (&csi->name), getSaNameT (&comp->name), + amf_ha_state (ha_state)); + + csi_assignment = malloc (sizeof (struct amf_csi_assignment)); + if (csi_assignment == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + + csi_assignment->comp_next = comp->assigned_csis; + comp->assigned_csis = csi_assignment; + setSaNameT (&csi_assignment->name, (char*)comp->name.value); + csi_assignment->saAmfCSICompHAState = ha_state; + csi_assignment->csi = csi; + csi_assignment->comp = comp; + csi_assignment->saAmfCSICompHAState = ha_state; + + if (ha_state == SA_AMF_HA_ACTIVE) + comp->saAmfCompNumCurrActiveCsi++; + else if (ha_state == SA_AMF_HA_STANDBY) + comp->saAmfCompNumCurrStandbyCsi++; + else + assert (0); + + amf_comp_hastate_set (comp, csi_assignment, ha_state); +} + +static void su_cleanup (struct amf_su *su) +{ + struct amf_comp *comp; + + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + amf_comp_restart (comp); + } +} + +static void escalation_policy_cleanup (struct amf_comp *comp) +{ +// escalation_timer_start (comp); + + switch (comp->su->escalation_level) { + case ESCALATION_LEVEL_NO_ESCALATION: + comp->saAmfCompRestartCount += 1; + if (comp->saAmfCompRestartCount >= comp->su->sg->saAmfSGCompRestartMax) { + comp->su->escalation_level = ESCALATION_LEVEL_ONE; + escalation_policy_cleanup (comp); + comp->saAmfCompRestartCount = 0; + return; + } + dprintf ("Escalation level 0 - restart component\n"); + dprintf ("Cleaning up and restarting component.\n"); + amf_comp_restart (comp); + break; + + case ESCALATION_LEVEL_ONE: + comp->su->saAmfSURestartCount += 1; + if (comp->su->saAmfSURestartCount >= comp->su->sg->saAmfSGSuRestartMax) { + comp->su->escalation_level = ESCALATION_LEVEL_TWO; + escalation_policy_cleanup (comp); + comp->saAmfCompRestartCount = 0; + comp->su->saAmfSURestartCount = 0; + return; + } + dprintf ("Escalation level 1 - restart unit\n"); + dprintf ("Cleaning up and restarting unit.\n"); + su_cleanup (comp->su); + break; + + case ESCALATION_LEVEL_TWO: + dprintf ("Escalation level TWO\n"); + su_cleanup (comp->su); +// unit_terminate_failover (comp); + break; + + case ESCALATION_LEVEL_THREE: +//TODO + break; + } +} + +void amf_su_instantiate (struct amf_su *su) +{ + struct amf_comp *comp; + + ENTER ("'%s'", su->name.value); + + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + amf_comp_instantiate (comp); + } +} + +void amf_su_assign_si (struct amf_su *su, struct amf_si *si, + SaAmfHAStateT ha_state) +{ + struct amf_si_assignment *si_assignment; + + dprintf ("Assigning SI '%s' to SU '%s' with hastate %s\n", + getSaNameT (&si->name), getSaNameT (&su->name), + amf_ha_state (ha_state)); + + si_assignment = malloc (sizeof (struct amf_si_assignment)); + if (si_assignment == NULL) { + openais_exit_error (AIS_DONE_OUT_OF_MEMORY); + } + setSaNameT (&si_assignment->name, (char*)su->name.value); + si_assignment->saAmfSISUHAState = ha_state; + si_assignment->next = su->assigned_sis; + su->assigned_sis = si_assignment; + si_assignment->si = si; + + if (ha_state == SA_AMF_HA_ACTIVE) { + si->saAmfSINumCurrActiveAssignments++; + su->saAmfSUNumCurrActiveSIs++; + } else if (ha_state == SA_AMF_HA_STANDBY) { + su->saAmfSUNumCurrStandbySIs++; + si->saAmfSINumCurrStandbyAssignments++; + } else + assert(0); + + if ((si->saAmfSINumCurrActiveAssignments == si->saAmfSIPrefActiveAssignments) && + (si->saAmfSINumCurrStandbyAssignments == si->saAmfSIPrefStandbyAssignments)) { + si->saAmfSIAssignmentState = SA_AMF_ASSIGNMENT_FULLY_ASSIGNED; + } else if ((si->saAmfSINumCurrActiveAssignments < si->saAmfSIPrefActiveAssignments) || + (si->saAmfSINumCurrStandbyAssignments < si->saAmfSIPrefStandbyAssignments)) { + si->saAmfSIAssignmentState = SA_AMF_ASSIGNMENT_PARTIALLY_ASSIGNED; + } + + { + struct amf_csi *csi; + struct amf_comp *comp; + SaNameT *cs_type; + int i; + + /* + ** for each component in SU, find a CSI in the SI with the same type + */ + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + int no_of_cs_types = 0; + for (i = 0; comp->saAmfCompCsTypes[i]; i++) { + cs_type = comp->saAmfCompCsTypes[i]; + no_of_cs_types++; + int no_of_assignments = 0; + + for (csi = si->csi_head; csi != NULL; csi = csi->next) { + if (!memcmp(csi->saAmfCSTypeName.value, cs_type->value, cs_type->length)) { + comp_assign_csi (comp, csi, ha_state); + no_of_assignments++; + } + } + if (no_of_assignments == 0) { + log_printf (LOG_WARNING, "\t No CSIs of type %s configured?!!\n", + getSaNameT (cs_type)); + } + } + if (no_of_cs_types == 0) { + log_printf (LOG_LEVEL_ERROR, "\t No CS types configured for comp %s ?!!\n", + getSaNameT (&comp->name)); + } + } + } +} + +/** + * Used by a component to report a state change event + * @param su + * @param comp + * @param type type of state + * @param state new state + */ +void amf_su_comp_state_changed ( + struct amf_su *su, struct amf_comp *comp, SaAmfStateT type, int state) +{ + if (type == SA_AMF_PRESENCE_STATE) { + /* + * If all comp presence states are INSTANTIATED, then SU should + * be instantated. + */ + if (state == SA_AMF_PRESENCE_INSTANTIATED) { + if (presence_state_all_comps_in_su_are_set ( + comp->su, SA_AMF_PRESENCE_INSTANTIATED)) { + + su_presence_state_set (comp->su, SA_AMF_PRESENCE_INSTANTIATED); + } else { + assert (0); + } + } else if (state == SA_AMF_PRESENCE_INSTANTIATING) { + } else if (state == SA_AMF_PRESENCE_RESTARTING) { + } else { + assert (0); + } + } else if (type == SA_AMF_OP_STATE) { + /* + * If all component op states are ENABLED, then SU op + * state should be ENABLED. + */ + if (state == SA_AMF_OPERATIONAL_ENABLED) { + struct amf_comp *comp_compare; + int all_set = 1; + for (comp_compare = comp->su->comp_head; comp_compare != NULL; comp_compare = comp->next) { + if (comp_compare->saAmfCompOperState != SA_AMF_OPERATIONAL_ENABLED) { + all_set = 0; + break; + } + } + if (all_set) { + su_operational_state_set (comp->su, SA_AMF_OPERATIONAL_ENABLED); + } else { + su_operational_state_set (comp->su, SA_AMF_OPERATIONAL_DISABLED); + } + } else { + assert (0); + } + } else { + assert (0); + } +} + +/** + * Used by a component to report a change in HA state + * @param su + * @param comp + * @param csi_assignment + */ +void amf_su_comp_hastate_changed ( + struct amf_su *su, struct amf_comp *comp, + struct amf_csi_assignment *csi_assignment) +{ + ENTER("'%s' '%s'", comp->name.value, csi_assignment->csi->name.value); +} + +/** + * Determine if the SU is hosted on the local node. + * @param su + * + * @return int + */ +int amf_su_is_local (struct amf_su *su) +{ + if (name_match (&this_amf_node->name, &su->saAmfSUHostedByNode)) { + return 1; + } else { + return 0; + } +} + +/** + * Called by a component to report a suspected error on a component + * @param su + * @param comp + * @param recommended_recovery + */ +void amf_su_comp_error_suspected ( + struct amf_su *su, + struct amf_comp *comp, + SaAmfRecommendedRecoveryT recommended_recovery) +{ + escalation_policy_cleanup (comp); +} + +void amf_su_init (void) +{ + log_init ("AMF"); +} + diff --git a/exec/amfconfig.c b/exec/amfutil.c similarity index 82% rename from exec/amfconfig.c rename to exec/amfutil.c index bea7c732..42963bc9 100644 --- a/exec/amfconfig.c +++ b/exec/amfutil.c @@ -1,10 +1,13 @@ -/* +/** @file exec/amfutil.c + * * Copyright (c) 2002-2005 MontaVista Software, Inc. * Author: Steven Dake (sdake@mvista.com) * * Copyright (c) 2006 Ericsson AB. * Author: Hans Feldt - * Description: Reworked to match AMF B.02 information model + * Description: + * - Reworked to match AMF B.02 information model Description: + * - Refactoring of code into several AMF files * * All rights reserved. * @@ -33,7 +36,14 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. + * + * AMF utility functions + * + * This file contains functions that provide different services used by other + * AMF files. For example parsing the configuration file, printing state etc. + * */ + #include #include #include @@ -44,7 +54,7 @@ #include "../include/ipc_amf.h" #include "../include/list.h" #include "util.h" -#include "amfconfig.h" +#include "amf.h" #include "totem.h" #include "print.h" @@ -68,90 +78,55 @@ typedef enum { AMF_CS_TYPE, } amf_parse_t; -typedef enum { - MAIN_HEAD, - MAIN_NETWORK, - MAIN_LOGGING, - MAIN_KEY, - MAIN_TIMEOUT, - MAIN_EVENT -} main_parse_t; - #ifndef OPENAIS_CLUSTER_STARTUP_TIMEOUT #define OPENAIS_CLUSTER_STARTUP_TIMEOUT 5000 #endif -struct amf_healthcheck *amf_find_healthcheck (struct amf_comp *comp, SaAmfHealthcheckKeyT *key) -{ - struct amf_healthcheck *healthcheck; - struct amf_healthcheck *ret_healthcheck = 0; +static const char *presence_state_text[] = { + "UNKNOWN", + "UNINSTANTIATED", + "INSTANTIATING", + "INSTANTIATED", + "TERMINATING", + "RESTARTING", + "INSTANTION_FAILED", + "TERMINIATION-FAILED" +}; - for (healthcheck = comp->healthcheck_head; - healthcheck != NULL; - healthcheck = healthcheck->next) { +static const char *oper_state_text[] = { + "UNKNOWN", + "ENABLED", + "DISABLED" +}; - if (memcmp (key, &healthcheck->safHealthcheckKey, sizeof (SaAmfHealthcheckKeyT)) == 0) { - ret_healthcheck = healthcheck; - break; - } - } +static const char *admin_state_text[] = { + "UNKNOWN", + "UNLOCKED", + "LOCKED", + "LOCKED-INSTANTIATION", + "SHUTTING-DOWN" +}; - return (ret_healthcheck); -} +static const char *readiness_state_text[] = { + "UNKNOWN", + "OUT-OF-SERVICE", + "IN-SERVICE", +}; -struct amf_comp *amf_find_comp (struct amf_cluster *cluster, SaNameT *name) -{ - struct amf_application *app; - struct amf_sg *sg; - struct amf_su *su; - struct amf_comp *comp = NULL; - char *app_name; - char *sg_name; - char *su_name; - char *comp_name; - char *ptrptr; - char *buf; +static const char *ha_state_text[] = { + "UNKNOWN", + "ACTIVE", + "STANDBY", + "QUIESCED", + "QUIESCING", +}; - /* malloc new buffer since strtok_r writes to its first argument */ - buf = malloc (name->length); - memcpy (buf, name->value,name ->length); - - comp_name = strtok_r(buf, ",", &ptrptr); - su_name = strtok_r(NULL, ",", &ptrptr); - sg_name = strtok_r(NULL, ",", &ptrptr); - app_name = strtok_r(NULL, ",", &ptrptr); - - if (comp_name == NULL || su_name == NULL || sg_name == NULL || app_name == NULL) { - goto end; - } - - comp_name += 8; - su_name += 6; - sg_name += 6; - app_name += 7; - - for (app = cluster->application_head; app != NULL; app = app->next) { - if (strncmp (app_name, (char*)app->name.value, app->name.length) == 0) { - for (sg = app->sg_head; sg != NULL; sg = sg->next) { - if (strncmp (sg_name, (char*)sg->name.value, sg->name.length) == 0) { - for (su = sg->su_head; su != NULL; su = su->next) { - if (strncmp (su_name, (char*)su->name.value, su->name.length) == 0) { - for (comp = su->comp_head; comp != NULL; comp = comp->next) { - if (strncmp (comp_name, (char*)comp->name.value, comp->name.length) == 0) { - goto end; - } - } - } - } - } - } - } - } - -end: - free (buf); - return comp; -} +static const char *assignment_state_text[] = { + "UNKNOWN", + "UNASSIGNED", + "FULLY-ASSIGNED", + "PARTIALLY-ASSIGNED" +}; static int init_category (struct amf_comp *comp, char *loc) { @@ -216,25 +191,6 @@ static int init_recovery_on_error (struct amf_comp *comp, char *loc) return 0; } -static struct amf_comp *new_comp(struct amf_su *su) -{ - struct amf_comp *comp = calloc (1, sizeof (struct amf_comp)); - - if (comp == NULL) { - openais_exit_error(AIS_DONE_OUT_OF_MEMORY); - } - comp->next = su->comp_head; - su->comp_head = comp; - comp->su = su; - comp->saAmfCompOperState = SA_AMF_OPERATIONAL_DISABLED; - comp->saAmfCompPresenceState = SA_AMF_PRESENCE_UNINSTANTIATED; - comp->saAmfCompNumMaxInstantiateWithoutDelay = 2; - comp->saAmfCompNumMaxAmStartAttempt = 2; - comp->saAmfCompNumMaxAmStopAttempt = 2; - - return comp; -} - static void post_init_comp(struct amf_comp *comp) { if (comp->saAmfCompInstantiateTimeout == 0) { @@ -589,7 +545,7 @@ int amf_config_read (struct amf_cluster *cluster, char **error_string) } else if ((loc = strstr_rs (line, "saAmfSUHostedByNode=")) != 0) { setSaNameT (&su->saAmfSUHostedByNode, loc); } else if ((loc = strstr_rs (line, "safComp=")) != 0) { - comp = new_comp (su); + comp = amf_comp_create (su); comp_env_var_cnt = 0; comp_cs_type_cnt = 0; setSaNameT (&comp->name, trim_str (loc)); @@ -775,7 +731,7 @@ int amf_config_read (struct amf_cluster *cluster, char **error_string) comp->saAmfCompCmdEnv = realloc (comp->saAmfCompCmdEnv, (comp_env_var_cnt + 1) * sizeof(SaStringT)); comp->saAmfCompCmdEnv[comp_env_var_cnt] = NULL; - env_var = comp->saAmfCompCmdEnv[comp_env_var_cnt - 1] = malloc (strlen (line + 1)); + env_var = comp->saAmfCompCmdEnv[comp_env_var_cnt - 1] = malloc (strlen (line) + 1); strcpy (env_var, line); } else { goto parse_error; @@ -933,3 +889,149 @@ parse_error: fclose (fp); return (-1); } + +void amf_runtime_attributes_print (struct amf_cluster *cluster) +{ + struct amf_node *node; + struct amf_application *app; + struct amf_sg *sg; + struct amf_su *su; + struct amf_comp *comp; + struct amf_si *si; + struct amf_csi *csi; + struct amf_si_assignment *si_assignment; + struct amf_csi_assignment *csi_assignment; + + dprintf("AMF runtime attributes:"); + dprintf("==================================================="); + dprintf("safCluster=%s", getSaNameT(&cluster->name)); + dprintf(" admin state: %s\n", admin_state_text[cluster->saAmfClusterAdminState]); + for (node = cluster->node_head; node != NULL; node = node->next) { + dprintf(" safNode=%s\n", getSaNameT (&node->name)); + dprintf(" admin state: %s\n", admin_state_text[node->saAmfNodeAdminState]); + dprintf(" oper state: %s\n", oper_state_text[node->saAmfNodeOperState]); + } + for (app = cluster->application_head; app != NULL; app = app->next) { + dprintf(" safApp=%s\n", getSaNameT(&app->name)); + dprintf(" admin state: %s\n", admin_state_text[app->saAmfApplicationAdminState]); + dprintf(" num_sg: %d\n", app->saAmfApplicationCurrNumSG); + for (sg = app->sg_head; sg != NULL; sg = sg->next) { + dprintf(" safSG=%s\n", getSaNameT(&sg->name)); + dprintf(" admin state: %s\n", admin_state_text[sg->saAmfSGAdminState]); + dprintf(" assigned SUs %d\n", sg->saAmfSGNumCurrAssignedSUs); + dprintf(" non inst. spare SUs %d\n", sg->saAmfSGNumCurrNonInstantiatedSpareSUs); + dprintf(" inst. spare SUs %d\n", sg->saAmfSGNumCurrInstantiatedSpareSUs); + for (su = sg->su_head; su != NULL; su = su->next) { + dprintf(" safSU=%s\n", getSaNameT(&su->name)); + dprintf(" oper state: %s\n", oper_state_text[su->saAmfSUOperState]); + dprintf(" admin state: %s\n", admin_state_text[su->saAmfSUAdminState]); + dprintf(" readiness state: %s\n", readiness_state_text[su->saAmfSUReadinessState]); + dprintf(" presence state: %s\n", presence_state_text[su->saAmfSUPresenceState]); + dprintf(" hosted by node %s\n", su->saAmfSUHostedByNode.value); + dprintf(" num active SIs %d\n", su->saAmfSUNumCurrActiveSIs); + dprintf(" num standby SIs %d\n", su->saAmfSUNumCurrStandbySIs); + dprintf(" restart count %d\n", su->saAmfSURestartCount); + dprintf(" escalation level %d\n", su->escalation_level); + dprintf(" SU failover cnt %d\n", su->su_failover_cnt); + dprintf(" assigned SIs:"); + for (si_assignment = su->assigned_sis; si_assignment != NULL; + si_assignment = si_assignment->next) { + dprintf(" safSi=%s\n", si_assignment->si->name.value); + dprintf(" HA state: %s\n", + ha_state_text[si_assignment->saAmfSISUHAState]); + } + for (comp = su->comp_head; comp != NULL; comp = comp->next) { + dprintf(" safComp=%s\n", getSaNameT(&comp->name)); + dprintf(" oper state: %s\n", + oper_state_text[comp->saAmfCompOperState]); + dprintf(" readiness state: %s\n", + readiness_state_text[comp->saAmfCompReadinessState]); + dprintf(" presence state: %s\n", + presence_state_text[comp->saAmfCompPresenceState]); + dprintf(" num active CSIs %d\n", + comp->saAmfCompNumCurrActiveCsi); + dprintf(" num standby CSIs %d\n", + comp->saAmfCompNumCurrStandbyCsi); + dprintf(" restart count %d\n", comp->saAmfCompRestartCount); + dprintf(" assigned CSIs:"); + for (csi_assignment = comp->assigned_csis; csi_assignment != NULL; + csi_assignment = csi_assignment->comp_next) { + dprintf(" safCSI=%s\n", csi_assignment->csi->name.value); + dprintf(" HA state: %s\n", + ha_state_text[csi_assignment->saAmfCSICompHAState]); + } + } + } + } + for (si = app->si_head; si != NULL; si = si->next) { + dprintf(" safSi=%s\n", getSaNameT(&si->name)); + dprintf(" admin state: %s\n", admin_state_text[si->saAmfSIAdminState]); + dprintf(" assignm. state: %s\n", assignment_state_text[si->saAmfSIAssignmentState]); + dprintf(" active assignments: %d\n", si->saAmfSINumCurrActiveAssignments); + dprintf(" standby assignments: %d\n", si->saAmfSINumCurrStandbyAssignments); + for (csi = si->csi_head; csi != NULL; csi = csi->next) { + dprintf(" safCsi=%s\n", getSaNameT(&csi->name)); + } + } + } + dprintf("==================================================="); +} + +/* to be removed... */ +int amf_enabled (struct objdb_iface_ver0 *objdb) +{ + unsigned int object_service_handle; + char *value; + int enabled = 0; + + objdb->object_find_reset (OBJECT_PARENT_HANDLE); + if (objdb->object_find ( + OBJECT_PARENT_HANDLE, + "amf", + strlen ("amf"), + &object_service_handle) == 0) { + + value = NULL; + if ( !objdb->object_key_get (object_service_handle, + "mode", + strlen ("mode"), + (void *)&value, + NULL) && value) { + + if (strcmp (value, "enabled") == 0) { + enabled = 1; + } else + if (strcmp (value, "disabled") == 0) { + enabled = 0; + } + } + } + + return enabled; +} + +const char *amf_admin_state (int state) +{ + return admin_state_text[state]; +} + +const char *amf_op_state (int state) +{ + return oper_state_text[state]; +} + +const char *amf_presence_state (int state) +{ + return presence_state_text[state]; +} + +const char *amf_ha_state (int state) +{ + return ha_state_text[state]; +} + +const char *amf_readiness_state (int state) +{ + return readiness_state_text[state]; +} + diff --git a/include/saAmf.h b/include/saAmf.h index ccc69597..ad576804 100644 --- a/include/saAmf.h +++ b/include/saAmf.h @@ -53,7 +53,7 @@ typedef enum { typedef enum { SA_AMF_HEALTHCHECK_AMF_INVOKED = 1, - SA_AMF_HELATHCHECK_COMPONENT_INVOKED =2 + SA_AMF_HEALTHCHECK_COMPONENT_INVOKED =2 } SaAmfHealthcheckInvocationT; #define SA_AMF_HEALTHCHECK_KEY_MAX 32 diff --git a/test/testamf1.c b/test/testamf1.c index 30a4bba6..a3ee7725 100644 --- a/test/testamf1.c +++ b/test/testamf1.c @@ -131,13 +131,24 @@ void CSISetCallback ( SaAmfHAStateT haState, SaAmfCSIDescriptorT *csiDescriptor) { - + SaAmfHAStateT state; int res; switch (haState) { case SA_AMF_HA_ACTIVE: printf ("Component '%s' requested to enter hastate SA_AMF_ACTIVE for \n\tCSI '%s'\n", compName->value, csiDescriptor->csiName.value); res = saAmfResponse (handle, invocation, SA_AIS_OK); + if (res != SA_AIS_OK) { + fprintf (stderr, "saAmfResponse failed: %d\n", res); + exit (-1); + } + + res = saAmfHAStateGet (handle, compName, &csiDescriptor->csiName, &state); + if (res != SA_AIS_OK || haState != state) { + fprintf (stderr, "saAmfHAStateGet failed: %d\n", res); + exit (-1); + } + int i; TR(TRU, csiDescriptor->csiAttr.number); for(i=0; icsiAttr.number; i++) {