amfsg.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /** @file amfsg.c
  2. *
  3. * Copyright (c) 2002-2006 MontaVista Software, Inc.
  4. * Author: Steven Dake (sdake@mvista.com)
  5. *
  6. * Copyright (c) 2006 Ericsson AB.
  7. * Author: Hans Feldt
  8. * - Introduced AMF B.02 information model
  9. * - Use DN in API and multicast messages
  10. * - (Re-)Introduction of event based multicast messages
  11. * - Refactoring of code into several AMF files
  12. * Author: Anders Eriksson
  13. *
  14. * All rights reserved.
  15. *
  16. *
  17. * This software licensed under BSD license, the text of which follows:
  18. *
  19. * Redistribution and use in source and binary forms, with or without
  20. * modification, are permitted provided that the following conditions are met:
  21. *
  22. * - Redistributions of source code must retain the above copyright notice,
  23. * this list of conditions and the following disclaimer.
  24. * - Redistributions in binary form must reproduce the above copyright notice,
  25. * this list of conditions and the following disclaimer in the documentation
  26. * and/or other materials provided with the distribution.
  27. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  28. * contributors may be used to endorse or promote products derived from this
  29. * software without specific prior written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  32. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  35. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  36. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  37. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  38. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  39. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  41. * THE POSSIBILITY OF SUCH DAMAGE.
  42. *
  43. * AMF Service Group Class Implementation
  44. *
  45. * This file contains functions for handling AMF-service groups(SGs). It can be
  46. * viewed as the implementation of the AMF Service Group class (called SG)
  47. * as described in SAI-Overview-B.02.01. The SA Forum specification
  48. * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour
  49. * and is referred to as 'the spec' below.
  50. *
  51. * The functions in this file are responsible for:
  52. * -on request start the service group by instantiating the contained SUs
  53. * -on request assign the service instances it protects to the in-service
  54. * service units it contains respecting as many as possible of the configured
  55. * requirements for the group
  56. * -create and delete an SI-assignment object for each relation between
  57. * an SI and an SU
  58. * -order each contained SU to create and delete CSI-assignments
  59. * -request the Service Instance class (SI) to execute the transfer of the
  60. * HA-state set/remove requests to each component involved
  61. * -fully control the execution of component failover and SU failover
  62. * -on request control the execution of the initial steps of node switchover
  63. * and node failover
  64. * -fully handle the auto adjust procedure
  65. *
  66. * Currently only the 'n+m' redundancy model is implemented. It is the
  67. * ambition to identify n+m specific variables and functions and add the suffix
  68. * '_nplusm' to them so that they can be easily recognized.
  69. *
  70. * When SG is requested to assign workload to all SUs or all SUs hosted on
  71. * a specific node, a procedure containing several steps is executed:
  72. * <1> An algorithm is executed which assigns SIs to SUs respecting the rules
  73. * that has been configured for SG. The algorithm also has to consider
  74. * if assignments between som SIs and SUs already exist. The scope of this
  75. * algorithm is to create SI-assignments and set up requested HA-state for
  76. * each assignment but not to transfer those HA-states to the components.
  77. * <2> All SI-assignments with a requested HA state == ACTIVE are transferred
  78. * to the components concerned before any STANDBY assignments are
  79. * transferred. All components have to acknowledge the setting of the
  80. * ACTIVE HA state before the transfer of any STANDBY assignment is
  81. * initiated.
  82. * <3> All active assignments can not be transferred at the same time to the
  83. * different components because the rules for dependencies between SI and
  84. * SI application wide and CSI and CSI within one SI, has to be respected.
  85. *
  86. * SG is fully responsible for step <1> but not fully responsible for handling
  87. * step <2> and <3>. However, SG uses an attribute called 'dependency level'
  88. * when requsted to assign workload. This parameter refers to an integer that
  89. * has been calculated initially for each SI. The 'dependency level' indicates
  90. * to which extent an SI depends on other SIs such that an SI that depends on
  91. * no other SI is on dependecy_level == 1, an SI that depends only on an SI on
  92. * dependency_level == 1 is on dependency-level == 2.
  93. * An SI that depends on several SIs gets a
  94. * dependency_level that is one unit higher than the SI with the highest
  95. * dependency_level it depends on. When SG is requested to assign the workload
  96. * on a certain dependency level, it requests all SI objects on that level to
  97. * activate (all) SI-assignments that during step <1> has been requested to
  98. * assume the active HA state.
  99. *
  100. * SG contains the following state machines:
  101. * - administrative state machine (ADSM) (NOT IN THIS RELEASE)
  102. * - availability control state machine (ACSM)
  103. *
  104. * The availability control state machine contains two states and one of them
  105. * is composite. Being a composite state means that it contains substates.
  106. * The states are:
  107. * - IDLE (non composite state)
  108. * - MANAGING_SG (composite state)
  109. * MANAGING_SG is entered at several different events which has in common
  110. * the need to set up or change the assignment of SIs to SUs. Only one such
  111. * event can be handled at the time. If new events occur while one event is
  112. * being handled then the new event is saved and will be handled after the
  113. * handling of the first event is ready (return to IDLE state has been done).
  114. * MANAGING_SG handles the following events:
  115. * - start (requests SG to order SU to instantiate all SUs in SG and waits
  116. * for SU to indicate presence state change reports from the SUs and
  117. * finally responds 'started' to the requester)
  118. * - assign (requests SG to assign SIs to SUs according to pre-configured
  119. * rules (if not already done) and transfer the HA state of
  120. * the SIs on the requested SI dependency level. Then SG waits for
  121. * confirmation that the HA state has been succesfully set and
  122. * finally responds 'assigned' to the reqeuster)
  123. * - auto_adjust (this event indicates that the auto-adjust probation timer has
  124. * expired and that SG should evaluate current assignments of
  125. * SIs to SUs and if needed remove current assignments and
  126. * create new according to what is specified in paragraph
  127. * 3.7.1.2)
  128. * - failover_comp (requests SG to failover a specific component according to
  129. * the procedure described in paragraph 3.12.1.3)
  130. * - failover_su (requests SG to failover a specific SU according to the
  131. * procedure described in paragraph 3.12.1.3 and 3.12.1.4)
  132. * - switchover_node (requests SG to execute the recovery actions described
  133. * in 3.12.1.3 and respond to the requester when recovery
  134. * is completed)
  135. * - failover_node (requests SG to execute the recovery actions described
  136. * in 3.12.1.3 and respond to the requester when recovery is
  137. * completed)
  138. *
  139. */
  140. #include <stdlib.h>
  141. #include <errno.h>
  142. #include "amf.h"
  143. #include "print.h"
  144. #include "main.h"
  145. static inline int div_round (int a, int b)
  146. {
  147. int res;
  148. res = a / b;
  149. if ((a % b) != 0)
  150. res++;
  151. return res;
  152. }
  153. static int sg_all_su_in_service(struct amf_sg *sg)
  154. {
  155. struct amf_su *su;
  156. struct amf_comp *comp;
  157. int ready = 1;
  158. for (su = sg->su_head; su != NULL; su = su->next) {
  159. for (comp = su->comp_head; comp != NULL; comp = comp->next) {
  160. if (su->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE) {
  161. ready = 0;
  162. }
  163. }
  164. }
  165. return ready;
  166. }
  167. static int application_si_count_get (struct amf_application *app)
  168. {
  169. struct amf_si *si;
  170. int answer = 0;
  171. for (si = app->si_head; si != NULL; si = si->next) {
  172. answer += 1;
  173. }
  174. return (answer);
  175. }
  176. static void sg_assign_nm_active (struct amf_sg *sg, int su_units_assign)
  177. {
  178. struct amf_su *unit;
  179. struct amf_si *si;
  180. int assigned = 0;
  181. int assign_per_su = 0;
  182. int total_assigned = 0;
  183. assign_per_su = application_si_count_get (sg->application);
  184. assign_per_su = div_round (assign_per_su, su_units_assign);
  185. if (assign_per_su > sg->saAmfSGMaxActiveSIsperSUs) {
  186. assign_per_su = sg->saAmfSGMaxActiveSIsperSUs;
  187. }
  188. si = sg->application->si_head;
  189. unit = sg->su_head;
  190. while (unit != NULL) {
  191. if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE ||
  192. unit->saAmfSUNumCurrActiveSIs == sg->saAmfSGMaxActiveSIsperSUs ||
  193. unit->saAmfSUNumCurrStandbySIs > 0) {
  194. unit = unit->next;
  195. continue; /* Not in service */
  196. }
  197. assigned = 0;
  198. while (si != NULL &&
  199. assigned < assign_per_su &&
  200. total_assigned < application_si_count_get (sg->application)) {
  201. assigned += 1;
  202. total_assigned += 1;
  203. amf_su_assign_si (unit, si, SA_AMF_HA_ACTIVE);
  204. si = si->next;
  205. }
  206. unit = unit->next;
  207. }
  208. if (total_assigned == 0) {
  209. dprintf ("Error: No SIs assigned!");
  210. }
  211. }
  212. static void sg_assign_nm_standby (struct amf_sg *sg, int units_assign_standby)
  213. {
  214. struct amf_su *unit;
  215. struct amf_si *si;
  216. int assigned = 0;
  217. int assign_per_su = 0;
  218. int total_assigned = 0;
  219. if (units_assign_standby == 0) {
  220. return;
  221. }
  222. assign_per_su = application_si_count_get (sg->application);
  223. assign_per_su = div_round (assign_per_su, units_assign_standby);
  224. if (assign_per_su > sg->saAmfSGMaxStandbySIsperSUs) {
  225. assign_per_su = sg->saAmfSGMaxStandbySIsperSUs;
  226. }
  227. si = sg->application->si_head;
  228. unit = sg->su_head;
  229. while (unit != NULL) {
  230. if (unit->saAmfSUReadinessState != SA_AMF_READINESS_IN_SERVICE ||
  231. unit->saAmfSUNumCurrActiveSIs > 0 ||
  232. unit->saAmfSUNumCurrStandbySIs == sg->saAmfSGMaxStandbySIsperSUs) {
  233. unit = unit->next;
  234. continue; /* Not available for assignment */
  235. }
  236. assigned = 0;
  237. while (si != NULL && assigned < assign_per_su) {
  238. assigned += 1;
  239. total_assigned += 1;
  240. amf_su_assign_si (unit, si, SA_AMF_HA_STANDBY);
  241. si = si->next;
  242. }
  243. unit = unit->next;
  244. }
  245. if (total_assigned == 0) {
  246. dprintf ("Error: No SIs assigned!");
  247. }
  248. }
  249. #if 0
  250. static void assign_nm_spare (struct amf_sg *sg)
  251. {
  252. struct amf_su *unit;
  253. for (unit = sg->su_head; unit != NULL; unit = unit->next) {
  254. if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE &&
  255. (unit->requested_ha_state != SA_AMF_HA_ACTIVE &&
  256. unit->requested_ha_state != SA_AMF_HA_STANDBY)) {
  257. dprintf ("Assigning to SU %s with SPARE\n",
  258. getSaNameT (&unit->name));
  259. }
  260. }
  261. }
  262. #endif
  263. static int su_inservice_count_get (struct amf_sg *sg)
  264. {
  265. struct amf_su *unit;
  266. int answer = 0;
  267. for (unit = sg->su_head; unit != NULL; unit = unit->next) {
  268. if (unit->saAmfSUReadinessState == SA_AMF_READINESS_IN_SERVICE) {
  269. answer += 1;
  270. }
  271. }
  272. return (answer);
  273. }
  274. void amf_sg_assign_si (struct amf_sg *sg, int dependency_level)
  275. {
  276. int active_sus_needed;
  277. int standby_sus_needed;
  278. int inservice_count;
  279. int units_for_standby;
  280. int units_for_active;
  281. int ii_spare;
  282. int su_active_assign;
  283. int su_standby_assign;
  284. int su_spare_assign;
  285. ENTER ("'%s'", sg->name.value);
  286. /*
  287. * Number of SUs to assign to active or standby state
  288. */
  289. inservice_count = (float)su_inservice_count_get (sg);
  290. active_sus_needed = div_round (application_si_count_get (sg->application),
  291. sg->saAmfSGMaxActiveSIsperSUs);
  292. standby_sus_needed = div_round (application_si_count_get (sg->application),
  293. sg->saAmfSGMaxStandbySIsperSUs);
  294. units_for_active = inservice_count - sg->saAmfSGNumPrefStandbySUs;
  295. if (units_for_active < 0) {
  296. units_for_active = 0;
  297. }
  298. units_for_standby = inservice_count - sg->saAmfSGNumPrefActiveSUs;
  299. if (units_for_standby < 0) {
  300. units_for_standby = 0;
  301. }
  302. ii_spare = inservice_count - sg->saAmfSGNumPrefActiveSUs - sg->saAmfSGNumPrefStandbySUs;
  303. if (ii_spare < 0) {
  304. ii_spare = 0;
  305. }
  306. /*
  307. * Determine number of active and standby service units
  308. * to assign based upon reduction procedure
  309. */
  310. if ((inservice_count - active_sus_needed) < 0) {
  311. dprintf ("assignment VI - partial assignment with SIs drop outs\n");
  312. su_active_assign = active_sus_needed;
  313. su_standby_assign = 0;
  314. su_spare_assign = 0;
  315. } else
  316. if ((inservice_count - active_sus_needed - standby_sus_needed) < 0) {
  317. dprintf ("assignment V - partial assignment with reduction of standby units\n");
  318. su_active_assign = active_sus_needed;
  319. if (standby_sus_needed > units_for_standby) {
  320. su_standby_assign = units_for_standby;
  321. } else {
  322. su_standby_assign = standby_sus_needed;
  323. }
  324. su_spare_assign = 0;
  325. } else
  326. if ((sg->saAmfSGMaxStandbySIsperSUs * units_for_standby) <= application_si_count_get (sg->application)) {
  327. dprintf ("IV: full assignment with reduction of active service units\n");
  328. su_active_assign = inservice_count - standby_sus_needed;
  329. su_standby_assign = standby_sus_needed;
  330. su_spare_assign = 0;
  331. } else
  332. if ((sg->saAmfSGMaxActiveSIsperSUs * units_for_active) <= application_si_count_get (sg->application)) {
  333. dprintf ("III: full assignment with reduction of standby service units\n");
  334. su_active_assign = sg->saAmfSGNumPrefActiveSUs;
  335. su_standby_assign = units_for_standby;
  336. su_spare_assign = 0;
  337. } else
  338. if (ii_spare == 0) {
  339. dprintf ("II: full assignment with spare reduction\n");
  340. su_active_assign = sg->saAmfSGNumPrefActiveSUs;
  341. su_standby_assign = sg->saAmfSGNumPrefStandbySUs;
  342. su_spare_assign = 0;
  343. } else {
  344. dprintf ("I: full assignment with spares\n");
  345. su_active_assign = sg->saAmfSGNumPrefActiveSUs;
  346. su_standby_assign = sg->saAmfSGNumPrefStandbySUs;
  347. su_spare_assign = ii_spare;
  348. }
  349. dprintf ("(inservice=%d) (assigning active=%d) (assigning standby=%d) (assigning spares=%d)\n",
  350. inservice_count, su_active_assign, su_standby_assign, su_spare_assign);
  351. sg_assign_nm_active (sg, su_active_assign);
  352. sg_assign_nm_standby (sg, su_standby_assign);
  353. LEAVE ("'%s'", sg->name.value);
  354. }
  355. void amf_sg_start (struct amf_sg *sg, struct amf_node *node)
  356. {
  357. struct amf_su *su;
  358. ENTER ("'%s'", sg->name.value);
  359. for (su = sg->su_head; su != NULL; su = su->next) {
  360. amf_su_instantiate (su);
  361. }
  362. }
  363. extern void amf_sg_su_state_changed (
  364. struct amf_sg *sg, struct amf_su *su, SaAmfStateT type, int state)
  365. {
  366. if (sg_all_su_in_service(su->sg)) {
  367. TRACE1 ("All SUs in SG '%s' in service, assigning SIs\n", su->sg->name.value);
  368. amf_sg_assign_si (su->sg, 0);
  369. if (amf_cluster.timeout_handle) {
  370. poll_timer_delete (aisexec_poll_handle, amf_cluster.timeout_handle);
  371. }
  372. }
  373. }
  374. void amf_sg_init (void)
  375. {
  376. log_init ("AMF");
  377. }