Przeglądaj źródła

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

Hans Feldt 19 lat temu
rodzic
commit
e993689ac5
15 zmienionych plików z 3990 dodań i 2574 usunięć
  1. 1 1
      Doxyfile
  2. 59 26
      exec/Makefile
  3. 163 2068
      exec/amf.c
  4. 679 0
      exec/amf.h
  5. 113 0
      exec/amfapp.c
  6. 123 0
      exec/amfcluster.c
  7. 1521 0
      exec/amfcomp.c
  8. 0 378
      exec/amfconfig.h
  9. 107 0
      exec/amfnode.c
  10. 422 0
      exec/amfsg.c
  11. 132 0
      exec/amfsi.c
  12. 456 0
      exec/amfsu.c
  13. 201 99
      exec/amfutil.c
  14. 1 1
      include/saAmf.h
  15. 12 1
      test/testamf1.c

+ 1 - 1
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           = 

+ 59 - 26
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

Plik diff jest za duży
+ 163 - 2068
exec/amf.c


+ 679 - 0
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 <limits.h>
+#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 */

+ 113 - 0
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");
+}
+

+ 123 - 0
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 <stdlib.h>
+#include <errno.h>
+
+#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");
+}
+

+ 1521 - 0
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_<api callback function name>_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 <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#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");
+}
+

+ 0 - 378
exec/amfconfig.h

@@ -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 <limits.h>
-#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 */

+ 107 - 0
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. 
+ * 
+ */
+

+ 422 - 0
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 <stdlib.h>
+#include <errno.h>
+
+#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");
+}
+

+ 132 - 0
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 <assert.h>
+#include <stdio.h>
+#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");
+}
+

+ 456 - 0
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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#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");
+}
+

+ 201 - 99
exec/amfconfig.c → 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 <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -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;
-
-	/* 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;
-	}
+static const char *ha_state_text[] = {
+	"UNKNOWN",
+	"ACTIVE",
+	"STANDBY",
+	"QUIESCED",
+	"QUIESCING",
+};
 
-	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];
+}
+

+ 1 - 1
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

+ 12 - 1
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; i<csiDescriptor->csiAttr.number; i++) {

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików