4
0

amfsi.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /** @file amfsi.c
  2. *
  3. * Copyright (c) 2006 Ericsson AB.
  4. * Author: Hans Feldt
  5. * - Refactoring of code into several AMF files
  6. * Author: Anders Eriksson, Lars Holm
  7. * - Component/SU restart, SU failover
  8. *
  9. * All rights reserved.
  10. *
  11. *
  12. * This software licensed under BSD license, the text of which follows:
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice,
  18. * this list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  23. * contributors may be used to endorse or promote products derived from this
  24. * software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  36. * THE POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * AMF Workload related classes Implementation
  39. *
  40. * This file contains functions for handling :
  41. * - AMF service instances(SI)
  42. * - AMF SI Dependency
  43. * - AMF SI Ranked SU
  44. * - AMF SI Assignment
  45. * - AMF component service instances (CSI)
  46. * - AMF CSI Assignment
  47. * - AMF CSI Type
  48. * - AMF CSI Attribute
  49. * The file can be viewed as the implementation of the classes listed above
  50. * as described in SAI-Overview-B.02.01. The SA Forum specification
  51. * SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour
  52. * and is referred to as 'the spec' below.
  53. *
  54. * The functions in this file are responsible for:
  55. * - calculating and storing an SI_dependency_level integer per SI
  56. * - calculating and storing a csi_dependency_level integer per CSI
  57. * - on request change HA state of an SI or CSI in such a way that the
  58. * requirements regarding SI -> SI dependencies (paragraphs 3.9.1.1 and
  59. * 3.9.1.2) and CSI -> CSI dependencies (paragraph 3.9.1.3) are fully
  60. * respected
  61. *
  62. * The si_dependency_level is an attribute calculated at init (in the future
  63. * also at reconfiguration) which indicates dependencies between SIs as
  64. * an integer. The si_dependency level indicates to which extent an SI depends
  65. * on other SIs such that an SI that depends on no other SI is on
  66. * si_dependecy_level == 1, an SI that depends only on an SI on
  67. * si_dependency_level == 1 is on si_dependency-level == 2.
  68. * An SI that depends on several SIs gets a si_dependency_level that is one
  69. * unit higher than the SI with the highest si_dependency_level it depends on.
  70. *
  71. * The csi_dependency_level attribute works the same way.
  72. *
  73. * According to paragraph 3.9.1 of the spec, a change to or from the ACTIVE
  74. * HA state is not always allowed without first deactivate dependent SI and CSI
  75. * assignments. Dependencies between CSIs are absolute while an SI that depends
  76. * on another SI may tolerate that the SI on which it depends is inactive for a
  77. * configurable time (the tolerance time). The consequence of this is that a
  78. * request to change the SI state may require a sequence of requests to
  79. * components to assume a new HA state for a CSI-assignment and to guarantee
  80. * the dependency rules, the active response from the component has to be
  81. * awaited before next HA state can be set.
  82. *
  83. * This file implements an SI state machine that fully implements these rules.
  84. * This state machine is called SI Dependency Control State Machine (dcsm)
  85. * and has the following states:
  86. * - DEACTIVATED (there is no SI-assignment with active HA state)
  87. * - ACTIVATING (a request to set the ACTIVE HA state has been received and
  88. * setting ACTIVE HA states to the appropriate components are
  89. * in progress)
  90. * - ACTIVATED (there is at least one SI-assignment with the ACTIVE HA-state)
  91. * - DEACTIVATING (a request to de-activate an SI or only a specific CSI
  92. * within an SI has been received and setting the QUISCED
  93. * HA states to the appropriate components are in progress)
  94. * - DEPENDENCY_DEACTIVATING (the SI-SI dependency tolerance timer has expired
  95. * and setting the QUISCED HA states to the
  96. * appropriate components are in progress)
  97. * - DEPENDENCY_DEACTIVATED (as state DEACTIVATED but will automatically
  98. * transition to state ACTIVATING when the
  99. * dependency problem is solved, i.e. the SI on
  100. * which it depends has re-assumed the ACTIVE HA
  101. * state)
  102. * - SETTING (a request to change the HA state when neither the existing
  103. * nor the requested state is ACTIVE)
  104. *
  105. * This file also implements:
  106. * - SI: Assignment state (for report purposes)
  107. * - SI Assignment: HA state
  108. * - CSI Assignment: HA state
  109. *
  110. */
  111. #include <assert.h>
  112. #include <stdio.h>
  113. #include "amf.h"
  114. #include "print.h"
  115. #include "util.h"
  116. #include "aispoll.h"
  117. #include "main.h"
  118. /**
  119. * Check if any CSI assignment belonging to SU has the requested
  120. * state.
  121. * @param su
  122. * @param hastate
  123. *
  124. * @return int
  125. */
  126. static int any_csi_has_hastate_in_su (struct amf_su *su, SaAmfHAStateT hastate)
  127. {
  128. struct amf_comp *component;
  129. struct amf_csi_assignment *csi_assignment;
  130. int exist = 0;
  131. for (component = su->comp_head; component != NULL;
  132. component = component->next) {
  133. csi_assignment = amf_comp_get_next_csi_assignment (component, NULL);
  134. while (csi_assignment != NULL) {
  135. if (csi_assignment->saAmfCSICompHAState == hastate) {
  136. exist = 1;
  137. goto done;
  138. }
  139. csi_assignment =
  140. amf_comp_get_next_csi_assignment (component, csi_assignment);
  141. }
  142. }
  143. done:
  144. return exist;
  145. }
  146. /**
  147. * Check if all CSI assignments belonging to a
  148. * an SI assignemnt has the requested state.
  149. * @param su
  150. * @param hastate
  151. *
  152. * @return int
  153. */
  154. static int all_csi_has_hastate_for_si (
  155. struct amf_si_assignment *si_assignment, SaAmfHAStateT hastate)
  156. {
  157. struct amf_comp *component;
  158. struct amf_csi_assignment *tmp_csi_assignment;
  159. int all = 1;
  160. for (component = si_assignment->su->comp_head; component != NULL;
  161. component = component->next) {
  162. tmp_csi_assignment = amf_comp_get_next_csi_assignment (component, NULL);
  163. while (tmp_csi_assignment != NULL) {
  164. if ((tmp_csi_assignment->si_assignment == si_assignment) &&
  165. (tmp_csi_assignment->saAmfCSICompHAState != hastate)) {
  166. all = 0;
  167. goto done;
  168. }
  169. tmp_csi_assignment =
  170. amf_comp_get_next_csi_assignment (component, tmp_csi_assignment);
  171. }
  172. }
  173. done:
  174. return all;
  175. }
  176. /**
  177. * Implements table 6 in 3.3.2.4
  178. * TODO: active & standby is not correct calculated acc. to
  179. * table. This knowledge is e.g. used in assign_si_assumed_cbfn
  180. * (sg.c)
  181. * @param csi_assignment
  182. */
  183. static void set_si_ha_state (struct amf_csi_assignment *csi_assignment)
  184. {
  185. SaAmfHAStateT old_ha_state =
  186. csi_assignment->si_assignment->saAmfSISUHAState;
  187. SaAmfAssignmentStateT old_assigment_state =
  188. amf_si_get_saAmfSIAssignmentState (csi_assignment->csi->si);
  189. if (all_csi_has_hastate_for_si (
  190. csi_assignment->si_assignment, SA_AMF_HA_ACTIVE)) {
  191. csi_assignment->si_assignment->saAmfSISUHAState = SA_AMF_HA_ACTIVE;
  192. }
  193. if (all_csi_has_hastate_for_si (
  194. csi_assignment->si_assignment, SA_AMF_HA_STANDBY)) {
  195. csi_assignment->si_assignment->saAmfSISUHAState = SA_AMF_HA_STANDBY;
  196. }
  197. if (any_csi_has_hastate_in_su (
  198. csi_assignment->comp->su, SA_AMF_HA_QUIESCING)) {
  199. csi_assignment->si_assignment->saAmfSISUHAState = SA_AMF_HA_QUIESCING;
  200. }
  201. if (any_csi_has_hastate_in_su (
  202. csi_assignment->comp->su, SA_AMF_HA_QUIESCED)) {
  203. csi_assignment->si_assignment->saAmfSISUHAState = SA_AMF_HA_QUIESCED;
  204. }
  205. /* log changes to HA state */
  206. if (old_ha_state != csi_assignment->si_assignment->saAmfSISUHAState) {
  207. log_printf (LOG_NOTICE, "SU HA state changed to '%s' for:\n"
  208. "\t\tSI '%s', SU '%s'",
  209. amf_ha_state (csi_assignment->si_assignment->saAmfSISUHAState),
  210. csi_assignment->si_assignment->si->name.value,
  211. csi_assignment->si_assignment->name.value);
  212. }
  213. /* log changes to assignment state */
  214. if (old_assigment_state !=
  215. amf_si_get_saAmfSIAssignmentState (csi_assignment->csi->si)) {
  216. log_printf (LOG_NOTICE, "SI Assignment state changed to '%s' for:\n"
  217. "\t\tSI '%s', SU '%s'",
  218. amf_assignment_state (
  219. amf_si_get_saAmfSIAssignmentState (csi_assignment->csi->si)),
  220. csi_assignment->si_assignment->si->name.value,
  221. csi_assignment->si_assignment->name.value);
  222. }
  223. }
  224. char *amf_csi_dn_make (struct amf_csi *csi, SaNameT *name)
  225. {
  226. int i = snprintf((char*) name->value, SA_MAX_NAME_LENGTH,
  227. "safCsi=%s,safSi=%s,safApp=%s",
  228. csi->name.value, csi->si->name.value,
  229. csi->si->application->name.value);
  230. assert (i <= SA_MAX_NAME_LENGTH);
  231. name->length = i;
  232. return(char *)name->value;
  233. }
  234. void amf_si_init (void)
  235. {
  236. log_init ("AMF");
  237. }
  238. void amf_si_comp_set_ha_state_done (
  239. struct amf_si *si, struct amf_csi_assignment *csi_assignment)
  240. {
  241. ENTER ("'%s', '%s'", si->name.value, csi_assignment->csi->name.value);
  242. set_si_ha_state (csi_assignment);
  243. assert (csi_assignment->si_assignment->assumed_callback_fn != NULL);
  244. /*
  245. * Report to caller when the requested SI assignment state is
  246. * confirmed.
  247. */
  248. if (csi_assignment->si_assignment->requested_ha_state ==
  249. csi_assignment->si_assignment->saAmfSISUHAState) {
  250. csi_assignment->si_assignment->assumed_callback_fn (
  251. csi_assignment->si_assignment, 0);
  252. csi_assignment->si_assignment->assumed_callback_fn = NULL;
  253. }
  254. }
  255. void amf_si_activate (
  256. struct amf_si *si,
  257. void (*activated_callback_fn)(struct amf_si *si, int result))
  258. {
  259. struct amf_csi *csi;
  260. ENTER ("'%s'", si->name.value);
  261. for (csi = si->csi_head; csi != NULL; csi = csi->next) {
  262. struct amf_csi_assignment *csi_assignment;
  263. for (csi_assignment = csi->assigned_csis; csi_assignment != NULL;
  264. csi_assignment = csi_assignment->next) {
  265. csi_assignment->si_assignment->requested_ha_state =
  266. SA_AMF_HA_ACTIVE;
  267. /*
  268. * TODO: only active assignments should be set when dependency
  269. * levels are used.
  270. */
  271. csi_assignment->requested_ha_state = SA_AMF_HA_ACTIVE;
  272. amf_comp_hastate_set (csi_assignment->comp, csi_assignment);
  273. }
  274. }
  275. }
  276. void amf_si_comp_set_ha_state_failed (
  277. struct amf_si *si, struct amf_csi_assignment *csi_assignment)
  278. {
  279. ENTER ("");
  280. assert (0);
  281. }
  282. static void timer_function_ha_state_assumed (void *_si_assignment)
  283. {
  284. struct amf_si_assignment *si_assignment = _si_assignment;
  285. ENTER ("");
  286. si_assignment->saAmfSISUHAState = si_assignment->requested_ha_state;
  287. si_assignment->assumed_callback_fn (si_assignment, 0);
  288. }
  289. void amf_si_ha_state_assume (
  290. struct amf_si_assignment *si_assignment,
  291. void (*assumed_ha_state_callback_fn)(struct amf_si_assignment *si_assignment,
  292. int result))
  293. {
  294. struct amf_csi_assignment *csi_assignment;
  295. struct amf_csi *csi;
  296. int csi_assignment_cnt = 0;
  297. int hastate_set_done_cnt = 0;
  298. ENTER ("SI '%s' SU '%s' state %s", si_assignment->si->name.value,
  299. si_assignment->su->name.value,
  300. amf_ha_state (si_assignment->requested_ha_state));
  301. si_assignment->assumed_callback_fn = assumed_ha_state_callback_fn;
  302. for (csi = si_assignment->si->csi_head; csi != NULL; csi = csi->next) {
  303. for (csi_assignment = csi->assigned_csis; csi_assignment != NULL;
  304. csi_assignment = csi_assignment->next) {
  305. /*
  306. * If the CSI assignment and the SI assignment belongs to the
  307. * same SU, we have a match and can request the component to
  308. * change HA state.
  309. */
  310. if (name_match (&csi_assignment->comp->su->name,
  311. &si_assignment->su->name) &&
  312. (csi_assignment->saAmfCSICompHAState !=
  313. si_assignment->requested_ha_state)) {
  314. csi_assignment_cnt++;
  315. csi_assignment->requested_ha_state =
  316. si_assignment->requested_ha_state;
  317. amf_comp_hastate_set (csi_assignment->comp, csi_assignment);
  318. if (csi_assignment->saAmfCSICompHAState ==
  319. csi_assignment->requested_ha_state) {
  320. hastate_set_done_cnt++;
  321. }
  322. }
  323. }
  324. }
  325. /*
  326. * If the SU has only one component which is the faulty one, we
  327. * will not get an asynchronous response from the component.
  328. * This response (amf_si_comp_set_ha_state_done) is used to do
  329. * the next state transition. The asynchronous response is
  330. * simulated using a timeout instead.
  331. */
  332. if (csi_assignment_cnt == hastate_set_done_cnt) {
  333. poll_timer_handle handle;
  334. poll_timer_add (aisexec_poll_handle,
  335. 0,
  336. si_assignment,
  337. timer_function_ha_state_assumed,
  338. &handle);
  339. }
  340. }
  341. /**
  342. * Get number of active assignments for the specified SI
  343. * @param si
  344. *
  345. * @return int
  346. */
  347. int amf_si_get_saAmfSINumCurrActiveAssignments (struct amf_si *si)
  348. {
  349. int cnt = 0;
  350. struct amf_si_assignment *si_assignment;
  351. for (si_assignment = si->assigned_sis; si_assignment != NULL;
  352. si_assignment = si_assignment->next) {
  353. if (si_assignment->saAmfSISUHAState == SA_AMF_HA_ACTIVE) {
  354. cnt++;
  355. }
  356. }
  357. return cnt;
  358. }
  359. int amf_si_get_saAmfSINumCurrStandbyAssignments (struct amf_si *si)
  360. {
  361. int cnt = 0;
  362. struct amf_si_assignment *si_assignment;
  363. for (si_assignment = si->assigned_sis; si_assignment != NULL;
  364. si_assignment = si_assignment->next) {
  365. if (si_assignment->saAmfSISUHAState == SA_AMF_HA_STANDBY) {
  366. cnt++;
  367. }
  368. }
  369. return cnt;
  370. }
  371. SaAmfAssignmentStateT amf_si_get_saAmfSIAssignmentState (struct amf_si *si)
  372. {
  373. if ((amf_si_get_saAmfSINumCurrActiveAssignments (si) ==
  374. si->saAmfSIPrefActiveAssignments) &&
  375. (amf_si_get_saAmfSINumCurrStandbyAssignments (si) ==
  376. si->saAmfSIPrefStandbyAssignments)) {
  377. return SA_AMF_ASSIGNMENT_FULLY_ASSIGNED;
  378. } else if (amf_si_get_saAmfSINumCurrActiveAssignments (si) == 0) {
  379. return SA_AMF_ASSIGNMENT_UNASSIGNED;
  380. } else {
  381. return SA_AMF_ASSIGNMENT_PARTIALLY_ASSIGNED;
  382. }
  383. }
  384. void amf_csi_delete_assignments (struct amf_csi *csi, struct amf_su *su)
  385. {
  386. struct amf_csi_assignment *csi_assignment;
  387. ENTER ("'%s'", su->name.value);
  388. /*
  389. * TODO: this only works for n+m where each CSI list has only
  390. * two assignments, one active and one standby.
  391. * TODO: use DN instead
  392. */
  393. if (csi->assigned_csis->comp->su == su) {
  394. csi_assignment = csi->assigned_csis;
  395. csi->assigned_csis = csi_assignment->next;
  396. } else {
  397. csi_assignment = csi->assigned_csis->next;
  398. csi->assigned_csis->next = NULL;
  399. assert (csi_assignment != NULL && csi_assignment->comp->su == su);
  400. }
  401. assert (csi_assignment != NULL);
  402. free (csi_assignment);
  403. }