This ticket adds support for container/contained in amfd.
---
 src/amf/amfd/comp.cc     |  65 ++++++++++++++++++--
 src/amf/amfd/comp.h      |   4 +-
 src/amf/amfd/comptype.cc |   6 +-
 src/amf/amfd/csi.cc      |   6 ++
 src/amf/amfd/csi.h       |   3 +
 src/amf/amfd/ndproc.cc   |  14 +++++
 src/amf/amfd/node.cc     |  29 +++++++++
 src/amf/amfd/node.h      |   1 +
 src/amf/amfd/sg.cc       |  29 +++++++++
 src/amf/amfd/sg.h        |   4 ++
 src/amf/amfd/sgproc.cc   | 142 ++++++++++++++++++++++++++++++++++++++++++-
 src/amf/amfd/si.cc       |  17 ++++++
 src/amf/amfd/si.h        |   1 +
 src/amf/amfd/su.cc       | 155 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/amf/amfd/su.h        |  15 ++++-
 src/amf/amfd/util.cc     |  39 ++++++++++++
 src/amf/amfd/util.h      |   2 +
 17 files changed, 517 insertions(+), 15 deletions(-)

diff --git a/src/amf/amfd/comp.cc b/src/amf/amfd/comp.cc
index 482322d2e..571ac34fb 100644
--- a/src/amf/amfd/comp.cc
+++ b/src/amf/amfd/comp.cc
@@ -73,7 +73,7 @@ void AVD_COMP::initialize() {
   curr_num_csi_actv = {};
   curr_num_csi_stdby = {};
   comp_proxy_csi = {};
-  comp_container_csi = {};
+  saAmfCompContainerCsi = {};
   saAmfCompRestartCount = {};
   saAmfCompCurrProxyName = {};
   saAmfCompCurrProxiedNames = {};
@@ -357,7 +357,10 @@ static int is_config_valid(const std::string &dn,
                        0, &aname);
   osafassert(rc == SA_AIS_OK);
 
-  if (comptype_db->find(Amf::to_string(&aname)) == nullptr) {
+  AVD_COMP_TYPE *comptype(comptype_db->find(Amf::to_string(&aname)));
+  CcbUtilOperationData_t *ccbCompTypeOpData(nullptr);
+
+  if (comptype == nullptr) {
     /* Comp type does not exist in current model, check CCB */
     if (opdata == nullptr) {
       report_ccb_validation_error(opdata, "'%s' does not exist in model",
@@ -365,7 +368,8 @@ static int is_config_valid(const std::string &dn,
       return 0;
     }
 
-    if (ccbutil_getCcbOpDataByDN(opdata->ccbId, &aname) == nullptr) {
+    ccbCompTypeOpData = ccbutil_getCcbOpDataByDN(opdata->ccbId, &aname);
+    if (ccbCompTypeOpData == nullptr) {
       report_ccb_validation_error(
           opdata, "'%s' does not exist in existing model or in CCB",
           osaf_extended_name_borrow(&aname));
@@ -399,6 +403,24 @@ static int is_config_valid(const std::string &dn,
     return 0;
   }
 
+  if ((comptype && IS_COMP_CONTAINED(comptype->saAmfCtCompCategory)) ||
+      (ccbCompTypeOpData &&
+      ccbCompTypeOpData->operationType == CCBUTIL_CREATE &&
+      immutil_getAttr(const_cast<SaImmAttrNameT>("saAmfCtCompCategory"),
+                      ccbCompTypeOpData->param.create.attrValues,
+                      0, &value) == SA_AIS_OK &&
+      value & SA_AMF_COMP_CONTAINED)) {
+    rc = immutil_getAttr(const_cast<SaImmAttrNameT>("saAmfCompContainerCsi"),
+                       attributes, 0, &value);
+    if (rc != SA_AIS_OK) {
+      report_ccb_validation_error(
+          opdata, "Contained component '%s' must have saAmfCompContainerCsi "
+          "attribute set", dn.c_str());
+      return 0;
+    }
+  }
+
+
 #if 0
         if ((comp->comp_info.category == AVSV_COMP_TYPE_SA_AWARE) && 
(comp->comp_info.init_len == 0)) {
                 LOG_ER("Sa Aware Component: instantiation command not 
configured");
@@ -716,6 +738,20 @@ static AVD_COMP *comp_create(const std::string &dn,
                       &comp->comp_info.comp_restart) != SA_AIS_OK)
     comp->comp_info.comp_restart = comptype->saAmfCtDefDisableRestart;
 
+  if (comp->contained()) {
+    SaNameT container_csi;
+
+    if (immutil_getAttr(const_cast<SaImmAttrNameT>("saAmfCompContainerCsi"),
+                          attributes, 0, &container_csi) != SA_AIS_OK) {
+      LOG_ER("unable to get container csi for %s", dn.c_str());
+      goto done;
+    }
+
+    comp->saAmfCompContainerCsi = Amf::to_string(&container_csi);
+    //XXX TODO_70: verify db if container csi. DO we requre this.
+    container_csis.insert(comp->saAmfCompContainerCsi);
+  }
+
   comp->max_num_csi_actv = -1;   // TODO
   comp->max_num_csi_stdby = -1;  // TODO
 
@@ -770,6 +806,7 @@ SaAisErrorT avd_comp_config_get(const std::string &su_name, 
AVD_SU *su) {
       const_cast<SaImmAttrNameT>("saAmfCompQuiescingCompleteTimeout"),
       const_cast<SaImmAttrNameT>("saAmfCompRecoveryOnError"),
       const_cast<SaImmAttrNameT>("saAmfCompDisableRestart"),
+      const_cast<SaImmAttrNameT>("saAmfCompContainerCsi"),
       nullptr};
 
   TRACE_ENTER();
@@ -1735,9 +1772,9 @@ static void comp_ccb_apply_modify_hdlr(struct 
CcbUtilOperationData *opdata) {
         comp->comp_proxy_csi = Amf::to_string((SaNameT *)value);
     } else if (!strcmp(attribute->attrName, "saAmfCompContainerCsi")) {
       if (value_is_deleted)
-        comp->comp_proxy_csi = "";
+        comp->saAmfCompContainerCsi = "";
       else
-        comp->comp_container_csi = Amf::to_string((SaNameT *)value);
+        comp->saAmfCompContainerCsi = Amf::to_string((SaNameT *)value);
     } else {
       osafassert(0);
     }
@@ -1842,6 +1879,8 @@ void avd_comp_constructor(void) {
 bool AVD_COMP::is_preinstantiable() const {
   AVSV_COMP_TYPE_VAL category = comp_info.category;
   return ((category == AVSV_COMP_TYPE_SA_AWARE) ||
+          (category == AVSV_COMP_TYPE_CONTAINER) ||
+          (category == AVSV_COMP_TYPE_CONTAINED) ||
           (category == AVSV_COMP_TYPE_PROXIED_LOCAL_PRE_INSTANTIABLE) ||
           (category == AVSV_COMP_TYPE_EXTERNAL_PRE_INSTANTIABLE));
 }
@@ -1904,3 +1943,19 @@ bool AVD_COMP::proxied_npi() const {
   AVD_COMP_TYPE *comptype = comptype_db->find(saAmfCompType);
   return (IS_COMP_PROXIED_NPI(comptype->saAmfCtCompCategory));
 }
+/**
+ * @brief  Checks if component is a container comp.
+ * @Return true/false.
+ */
+bool AVD_COMP::container(void) const {
+  AVD_COMP_TYPE *comptype(comptype_db->find(saAmfCompType));
+  return (IS_COMP_CONTAINER(comptype->saAmfCtCompCategory));
+}
+/**
+ * @brief  Checks if component is contained comp.
+ * @Return true/false.
+ */
+bool AVD_COMP::contained(void) const {
+  AVD_COMP_TYPE *comptype(comptype_db->find(saAmfCompType));
+  return (IS_COMP_CONTAINED(comptype->saAmfCtCompCategory));
+}
diff --git a/src/amf/amfd/comp.h b/src/amf/amfd/comp.h
index 1493d717c..4265f16d6 100644
--- a/src/amf/amfd/comp.h
+++ b/src/amf/amfd/comp.h
@@ -141,7 +141,7 @@ class AVD_COMP {
                                  * Checkpointing - Sent update independently.
                                  */
   std::string comp_proxy_csi;
-  std::string comp_container_csi;
+  std::string saAmfCompContainerCsi;
 
   /* runtime attributes */
   SaAmfOperationalStateT saAmfCompOperState;
@@ -166,6 +166,8 @@ class AVD_COMP {
   bool saaware() const;
   bool proxied_pi() const;
   bool proxied_npi() const;
+  bool container(void) const;
+  bool contained(void) const;
 
  private:
   void initialize();
diff --git a/src/amf/amfd/comptype.cc b/src/amf/amfd/comptype.cc
index 787c0bcb6..843a406aa 100644
--- a/src/amf/amfd/comptype.cc
+++ b/src/amf/amfd/comptype.cc
@@ -223,9 +223,8 @@ static bool config_is_valid(const std::string &dn,
                        attributes, 0, &category);
   osafassert(rc == SA_AIS_OK);
 
-  /* We do not support Proxy, Container and Contained as of now. */
-  if (IS_COMP_PROXY(category) || IS_COMP_CONTAINER(category) ||
-      IS_COMP_CONTAINED(category)) {
+  /* We do not support Proxy as of now. */
+  if (IS_COMP_PROXY(category)) {
     report_ccb_validation_error(
         opdata, "Unsupported saAmfCtCompCategory value '%u' for '%s'", 
category,
         dn.c_str());
@@ -312,6 +311,7 @@ static bool config_is_valid(const std::string &dn,
   */
   if (IS_COMP_LOCAL(category) &&
       !(IS_COMP_PROXIED(category) || IS_COMP_PROXIED_NPI(category)) &&
+      !IS_COMP_CONTAINER(category) && !IS_COMP_CONTAINED(category) &&
       !IS_COMP_SAAWARE(category)) {
     attr_name = "saAmfCtRelPathTerminateCmd";
 
diff --git a/src/amf/amfd/csi.cc b/src/amf/amfd/csi.cc
index 82829566c..f7e3730dd 100644
--- a/src/amf/amfd/csi.cc
+++ b/src/amf/amfd/csi.cc
@@ -26,6 +26,7 @@
 #include "amf/amfd/proc.h"
 
 AmfDb<std::string, AVD_CSI> *csi_db = nullptr;
+std::set<std::string> container_csis;
 
 //
 AVD_COMP *AVD_CSI::find_assigned_comp(
@@ -1670,3 +1671,8 @@ void avd_compcsi_cleanup_imm_object(AVD_CL_CB *cb) {
 done:
   TRACE_LEAVE();
 }
+
+bool AVD_CSI::is_container_csi(void) const {
+  auto iter(container_csis.find(name));
+  return (iter != container_csis.end()) ? true : false;
+}
diff --git a/src/amf/amfd/csi.h b/src/amf/amfd/csi.h
index 837fbc67d..166d9dec4 100644
--- a/src/amf/amfd/csi.h
+++ b/src/amf/amfd/csi.h
@@ -98,6 +98,8 @@ class AVD_CSI {
       const std::string &cstype, const AVD_SU_SI_REL *sisu,
       const std::vector<AVD_COMP *> &list_of_comp);
 
+  bool is_container_csi(void) const;
+
  private:
   AVD_CSI();
   // disallow copy and assign
@@ -106,6 +108,7 @@ class AVD_CSI {
 };
 
 extern AmfDb<std::string, AVD_CSI> *csi_db;
+extern std::set<std::string> container_csis;
 
 class AVD_CS_TYPE {
  public:
diff --git a/src/amf/amfd/ndproc.cc b/src/amf/amfd/ndproc.cc
index 31d2263d2..eb5d2b3d8 100644
--- a/src/amf/amfd/ndproc.cc
+++ b/src/amf/amfd/ndproc.cc
@@ -1113,6 +1113,20 @@ void avd_data_update_req_evh(AVD_CL_CB *cb, AVD_EVT 
*evt) {
             /* send response to pending clm callback */
             if (su->su_on_node->clm_pend_inv != 0)
               clm_pend_response(su, static_cast<SaAmfPresenceStateT>(l_val));
+
+            /*
+             * If the contained su has finished terminating we can now finish
+             * with the container su.
+             */
+            if (su->contained() && l_val == SA_AMF_PRESENCE_UNINSTANTIATED) {
+              AVD_SU *container_su(su->get_container_su_on_same_node());
+
+              if (container_su->wait_for_contained_to_quiesce) {
+                // XXX fix me, could be quiescing
+                avd_sg_su_si_mod_snd(cb, container_su, SA_AMF_HA_QUIESCED);
+                container_su->wait_for_contained_to_quiesce = false;
+              }
+            }
           } else {
             /* log error that a the  value len is invalid */
             LOG_ER("%s:%u: %u", __FILE__, __LINE__,
diff --git a/src/amf/amfd/node.cc b/src/amf/amfd/node.cc
index 0ffcfb782..b5ff0eab3 100644
--- a/src/amf/amfd/node.cc
+++ b/src/amf/amfd/node.cc
@@ -1676,3 +1676,32 @@ bool AVD_AVND::is_campaign_set_for_all_sus() const {
     return false;
   }
 }
+
+void AVD_AVND::instantiate_contained_sus(AVD_SU *container_su,
+                                         const AVD_CSI *container_csi) {
+  TRACE_ENTER();
+  for (auto &su : list_of_su) {
+    if (su == container_su)
+      continue;
+    if ((su->contained() == false) ||
+        (su->list_of_comp.empty() == true) ||
+        (su->saAmfSUPresenceState == SA_AMF_PRESENCE_INSTANTIATED))
+      continue;
+    if (su->list_of_comp.front()->saAmfCompContainerCsi == 
container_csi->name) {
+      if (((su->su_on_node->node_state == AVD_AVND_STATE_PRESENT) ||
+           (su->su_on_node->node_state == AVD_AVND_STATE_NO_CONFIG) ||
+           (su->su_on_node->node_state == AVD_AVND_STATE_NCS_INIT)) &&
+          ((su->su_on_node->saAmfNodeAdminState != 
SA_AMF_ADMIN_LOCKED_INSTANTIATION) &&
+           (su->sg_of_su->saAmfSGAdminState != 
SA_AMF_ADMIN_LOCKED_INSTANTIATION)) &&
+          ((su->saAmfSUOperState == SA_AMF_OPERATIONAL_ENABLED) ||
+           (su->sg_of_su->sg_ncs_spec == true)) &&
+          (su->sg_of_su->saAmfSGNumPrefInserviceSUs >
+           sg_instantiated_su_count(su->sg_of_su))) {
+        if (avd_instantiate_contained_su(avd_cb, container_su, su, false) == 
NCSCC_RC_SUCCESS) {
+          su->set_term_state(false);
+        }
+      }
+    }
+  }
+  TRACE_LEAVE();
+}
diff --git a/src/amf/amfd/node.h b/src/amf/amfd/node.h
index e64bf8c93..55e50504a 100644
--- a/src/amf/amfd/node.h
+++ b/src/amf/amfd/node.h
@@ -148,6 +148,7 @@ class AVD_AVND {
   bool is_campaign_set_for_all_sus() const;
   // Member functions.
   void node_sus_termstate_set(bool term_state) const;
+  void instantiate_contained_sus(AVD_SU* su, const AVD_CSI *container_csi);
 
  private:
   void initialize();
diff --git a/src/amf/amfd/sg.cc b/src/amf/amfd/sg.cc
index f973e3a97..83af5292b 100644
--- a/src/amf/amfd/sg.cc
+++ b/src/amf/amfd/sg.cc
@@ -497,6 +497,14 @@ SaAisErrorT avd_sg_config_get(const std::string &app_dn, 
AVD_APP *app) {
       error = SA_AIS_ERR_FAILED_OPERATION;
       goto done2;
     }
+
+    if ((sg->any_container_su() == true) &&
+        (sg->sg_redundancy_model != SA_AMF_N_WAY_ACTIVE_REDUNDANCY_MODEL)) {
+       LOG_ER("%s: red model for container sg must be N-Way Active: %u",
+              sg->name.c_str(),sg->sg_redundancy_model);
+       error = SA_AIS_ERR_FAILED_OPERATION;
+       goto done2;
+    }
   }
 
   if (rc == SA_AIS_ERR_NOT_EXIST) {
@@ -2400,3 +2408,24 @@ bool AVD_SG::find_instantiable_same_rank_su(AVD_SU *su) {
   }
   return false;
 }
+
+/**
+ * @brief  Checks if any su of Sg is a container su.
+ * @return true/false
+ */
+bool AVD_SG::any_container_su(void) const {
+  return (std::any_of(list_of_su.begin(), list_of_su.end(),
+                  [&](AVD_SU *su) -> bool {
+                    return su->container();
+                  }));
+}
+/**
+ * @brief  Checks if any su of Sg is a contained su.
+ * @return true/false
+ */
+bool AVD_SG::any_contained_su(void) const {
+  return (std::any_of(list_of_su.begin(), list_of_su.end(),
+                  [&](AVD_SU *su) -> bool {
+                    return su->contained();
+                  }));
+}
diff --git a/src/amf/amfd/sg.h b/src/amf/amfd/sg.h
index 81595a2b1..426f1ba4d 100644
--- a/src/amf/amfd/sg.h
+++ b/src/amf/amfd/sg.h
@@ -451,6 +451,10 @@ class AVD_SG {
   // Checks if si_equal_distribution is configured for the SG.
   bool is_equal() const;
   bool find_instantiable_same_rank_su(AVD_SU *su);
+  //Checks if any SU of sg is a container su.
+  bool any_container_su(void) const;
+  //Checks if any SU of sg is a contained su.
+  bool any_contained_su(void) const;
 
  private:
   // disallow copy and assign, TODO(hafe) add common macro for this
diff --git a/src/amf/amfd/sgproc.cc b/src/amf/amfd/sgproc.cc
index 2bee8754d..7fba62ba7 100644
--- a/src/amf/amfd/sgproc.cc
+++ b/src/amf/amfd/sgproc.cc
@@ -41,6 +41,8 @@
 #include "amf/amfd/si_dep.h"
 #include "amf/amfd/cluster.h"
 
+extern bool all_assignments_done(const AVD_SU *);
+
 /**
  * @brief       While creating compcsi relationship in SUSI, AMF may assign
  *              a dependent csi to a component in the SU when its one or more
@@ -1134,6 +1136,54 @@ void 
process_su_si_response_for_surestart_admin_op(AVD_SU *su) {
   }
   TRACE_LEAVE();
 }
+
+static void process_su_si_response_for_container_contained(
+  AVD_CL_CB *cb, AVD_SU *su, SaAmfHAStateT state, AVSV_SUSI_ACT msg_act) {
+  TRACE_ENTER();
+
+  if (su->container() || su->contained()) {
+    TRACE("su: %s state: %i msg_act: %i", su->name.c_str(), state, msg_act);
+
+    if (su->contained() &&
+        ((state == SA_AMF_HA_QUIESCED && msg_act == AVSV_SUSI_ACT_DEL) ||
+        (state == SA_AMF_HA_STANDBY && msg_act == AVSV_SUSI_ACT_DEL))) {
+      // notify container su that contained has quiesced and removed
+      AVD_SU *container_su(su->get_container_su_on_same_node());
+
+      TRACE("container: %s wait: %i",
+            container_su->name.c_str(),
+            container_su->wait_for_contained_to_quiesce);
+
+      if (container_su->wait_for_contained_to_quiesce) {
+        // contained SU has been removed, now terminate it
+        if (avd_snd_presence_msg(avd_cb, su, true) == NCSCC_RC_SUCCESS)
+          su->set_term_state(true);
+
+        /*
+         * If all the contained SUs are done change the admin state of the
+         * contained SG back to unlocked.
+         */
+        bool all_unassigned(true);
+        for (const auto &iter : su->sg_of_su->list_of_su) {
+          if (iter->list_of_susi != AVD_SU_SI_REL_NULL) {
+            all_unassigned = false;
+            break;
+          }
+        }
+
+        if (container_su->sg_of_su->saAmfSGAdminState == SA_AMF_ADMIN_LOCKED &&
+            all_unassigned) {
+          su->sg_of_su->saAmfSGAdminState = SA_AMF_ADMIN_UNLOCKED;
+        }
+      }
+    } else if (su->container() && state == SA_AMF_HA_ACTIVE)
+      su->instantiate_associated_contained_sus();
+  }
+
+  TRACE_LEAVE();
+  return;
+}
+
 /*****************************************************************************
  * Function: avd_su_si_assign_func
  *
@@ -1247,6 +1297,14 @@ void avd_su_si_assign_evh(AVD_CL_CB *cb, AVD_EVT *evt) {
     TRACE("%u", n2d_msg->msg_info.n2d_su_si_assign.msg_act);
     switch (n2d_msg->msg_info.n2d_su_si_assign.msg_act) {
       case AVSV_SUSI_ACT_DEL:
+        if (su->contained()) {
+          AVD_SU *container_su(su->get_container_su_on_same_node());
+          if (container_su->wait_for_contained_to_quiesce &&
+              container_su->sg_of_su->saAmfSGAdminState ==
+                SA_AMF_ADMIN_LOCKED) {
+              avd_sg_su_oper_list_del(cb, su, false);
+          }
+        }
         break;
 
       case AVSV_SUSI_ACT_MOD:
@@ -1724,6 +1782,12 @@ void avd_su_si_assign_evh(AVD_CL_CB *cb, AVD_EVT *evt) {
         su->su_on_node->clm_pend_inv = 0;
       } /* else wait for some more time */
     }
+
+    process_su_si_response_for_container_contained(
+      cb,
+      su,
+      n2d_msg->msg_info.n2d_su_si_assign.ha_state,
+      n2d_msg->msg_info.n2d_su_si_assign.msg_act);
   }
 
   /* Check whether the node belonging to this su is disable and susi of all su
@@ -1813,7 +1877,8 @@ void avd_sg_app_node_su_inst_func(AVD_CL_CB *cb, AVD_AVND 
*avnd) {
 
   if (cb->init_state == AVD_INIT_DONE) {
     for (const auto &i_su : avnd->list_of_su) {
-      if ((i_su->term_state == false) &&
+      if (!i_su->contained() && // contained sus are instantiated by container
+          (i_su->term_state == false) &&
           (i_su->saAmfSUPresenceState == SA_AMF_PRESENCE_UNINSTANTIATED) &&
           (i_su->saAmfSUAdminState != SA_AMF_ADMIN_LOCKED_INSTANTIATION) &&
           (i_su->sg_of_su->saAmfSGAdminState !=
@@ -1994,7 +2059,8 @@ uint32_t avd_sg_app_su_inst_func(AVD_CL_CB *cb, AVD_SG 
*sg) {
           num_insvc_su++;
         }
 
-      } else if ((i_su->saAmfSUPreInstantiable == true) &&
+      } else if (!i_su->contained() && // contained su instantiated by 
container
+                 (i_su->saAmfSUPreInstantiable == true) &&
                  (i_su->saAmfSUPresenceState ==
                   SA_AMF_PRESENCE_UNINSTANTIATED) &&
                  ((i_su->saAmfSUAdminState == SA_AMF_ADMIN_UNLOCKED) ||
@@ -2423,6 +2489,71 @@ done:
   return rc;
 }
 
+static uint32_t shutdown_contained_sus(AVD_CL_CB *cb, AVD_SU *container_su,
+                                       SaAmfHAStateT state) {
+  TRACE_ENTER();
+
+  uint32_t rc(NCSCC_RC_FAILURE);
+
+  // get the container csi
+  AVD_COMP_CSI_REL *container_csi_rel(nullptr);
+
+  for (const auto &comp : container_su->list_of_comp) {
+    if (comp->container()) {
+      for (const auto &si : container_su->sg_of_su->list_of_si) {
+        for (AVD_CSI *csi = si->list_of_csi; csi; csi = 
csi->si_list_of_csi_next) {
+          for (AVD_COMP_CSI_REL *compcsi = csi->list_compcsi; compcsi;
+               compcsi = compcsi->csi_csicomp_next) {
+            if (compcsi->comp == comp) {
+              TRACE("found container csi: %s", compcsi->csi->name.c_str());
+              container_csi_rel = compcsi;
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  const std::string& container_csi(container_csi_rel->csi->name);
+
+  for (auto &su : container_su->su_on_node->list_of_su) {
+    if (su == container_su)
+      continue;
+    if ((su->contained() == false) ||
+        (su->list_of_comp.empty() == true))
+      continue;
+    if (su->list_of_comp.front()->saAmfCompContainerCsi == container_csi) {
+      su->set_readiness_state(SA_AMF_READINESS_OUT_OF_SERVICE);
+
+      if (su->list_of_susi->state == SA_AMF_HA_ACTIVE)
+        rc = avd_sg_su_si_mod_snd(cb, su, SA_AMF_HA_QUIESCED);
+      else
+        rc = avd_sg_su_si_del_snd(cb, su);
+
+      if (rc != NCSCC_RC_SUCCESS)
+        goto done;
+
+      if (container_su->sg_of_su->saAmfSGAdminState == SA_AMF_ADMIN_LOCKED) {
+        // this is dangerous...
+        // XXX use ng_using_saAmfSGAdminState
+        su->sg_of_su->saAmfSGAdminState = SA_AMF_ADMIN_LOCKED;
+
+        su->sg_of_su->set_fsm_state(AVD_SG_FSM_SG_ADMIN);
+      } else {
+        su->sg_of_su->set_fsm_state(AVD_SG_FSM_SU_OPER);
+      }
+
+      avd_sg_su_oper_list_add(cb, su, false);
+    }
+  }
+
+done:
+  return rc;
+
+  TRACE_LEAVE();
+}
+
 /*****************************************************************************
  * Function: avd_sg_su_si_mod_snd
  *
@@ -2456,6 +2587,13 @@ uint32_t avd_sg_su_si_mod_snd(AVD_CL_CB *cb, AVD_SU *su, 
SaAmfHAStateT state) {
     goto done;
   }
 
+  if (su->container() && !su->wait_for_contained_to_quiesce) {
+    TRACE("this is a container su; need to shut down contained sus");
+    rc = shutdown_contained_sus(cb, su, state);
+    su->wait_for_contained_to_quiesce = true;
+    goto done;
+  }
+
   /* change the state for all assignments to the specified state. */
   i_susi = su->list_of_susi;
   while (i_susi != AVD_SU_SI_REL_NULL) {
diff --git a/src/amf/amfd/si.cc b/src/amf/amfd/si.cc
index cf026d7b8..5308a7ac8 100644
--- a/src/amf/amfd/si.cc
+++ b/src/amf/amfd/si.cc
@@ -703,6 +703,13 @@ SaAisErrorT avd_si_config_get(AVD_APP *app) {
     if (avd_sirankedsu_config_get(si_str, si) != SA_AIS_OK) goto done2;
 
     if (avd_csi_config_get(si_str, si) != SA_AIS_OK) goto done2;
+
+    if ((si->sg_of_si != nullptr) && (si->sg_of_si->any_container_su() == true)
+        && (si->csi_count() > 1)) {
+      LOG_ER("More than one CSIs configured in a container si:'%s'",
+              si->name.c_str());
+      goto done2;
+    }
   }
 
   if (rc == SA_AIS_ERR_NOT_EXIST) {
@@ -1917,3 +1924,13 @@ SaAisErrorT AVD_SI::si_swap_validate() {
 done:
   return rc;
 }
+
+uint32_t AVD_SI::csi_count(void) const {
+  uint32_t count(0);
+  for (const AVD_CSI *csi(list_of_csi);
+       csi;
+       csi = csi->si_list_of_csi_next) {
+    count++;
+  }
+  return count;
+}
diff --git a/src/amf/amfd/si.h b/src/amf/amfd/si.h
index 45b37cc33..cca42a400 100644
--- a/src/amf/amfd/si.h
+++ b/src/amf/amfd/si.h
@@ -155,6 +155,7 @@ class AVD_SI {
   uint32_t count_sisu_with(SaAmfHAStateT ha);
   bool is_all_sponsor_si_unassigned() const;
   bool is_all_dependent_si_unassigned() const;
+  uint32_t csi_count(void) const;
 
  private:
   bool is_assigned() const { return list_of_sisu ? true : false; }
diff --git a/src/amf/amfd/su.cc b/src/amf/amfd/su.cc
index c3609d8aa..2c8256a37 100644
--- a/src/amf/amfd/su.cc
+++ b/src/amf/amfd/su.cc
@@ -64,6 +64,7 @@ void AVD_SU::initialize() {
   pend_cbk.invocation = 0;
   pend_cbk.admin_oper = (SaAmfAdminOperationIdT)0;
   surestart = false;
+  wait_for_contained_to_quiesce = false;
 }
 
 AVD_SU::AVD_SU() { initialize(); }
@@ -748,6 +749,23 @@ SaAisErrorT avd_su_config_get(const std::string &sg_name, 
AVD_SG *sg) {
       error = SA_AIS_ERR_FAILED_OPERATION;
       goto done2;
     }
+
+    if (su->any_container_comp() == true)  {
+      if (su->container() == false) {
+        LOG_ER("%s: comps of other category mixed with container comp: %u",
+               su->name.c_str(), error);
+        error = SA_AIS_ERR_FAILED_OPERATION;
+        goto done2;
+      }
+    }
+    if (su->any_contained_comp() == true)  {
+      if (su->contained() == false) {
+        LOG_ER("%s: comps of other category mixed with contained comp: %u",
+               su->name.c_str(), error);
+        error = SA_AIS_ERR_FAILED_OPERATION;
+        goto done2;
+      }
+    }
   }
 
   if (rc == SA_AIS_ERR_NOT_EXIST) {
@@ -1120,6 +1138,9 @@ done:
 void AVD_SU::unlock_instantiation(SaImmOiHandleT immoi_handle,
                                   SaInvocationT invocation) {
   AVD_AVND *node = get_node_ptr();
+  bool is_container_ready = true;
+  AVD_SU *container_ptr = nullptr;
+  uint32_t rc;
 
   TRACE_ENTER2("'%s'", name.c_str());
 
@@ -1149,6 +1170,15 @@ void AVD_SU::unlock_instantiation(SaImmOiHandleT 
immoi_handle,
     goto done;
   }
 
+  if (contained() == true) {
+    container_ptr = get_container_su_on_same_node();
+    if ((container_ptr == nullptr) ||
+        (container_ptr->is_ready_for_contained() == false)) {
+      is_container_ready = false;
+      TRACE("Container su not available or ready.");
+    }
+  }
+
   /* Middleware sus are not enabled until node joins. During
      starting of opensaf, if mw su is locked-in and unlock-in
      command is issued, su should get instantiated. */
@@ -1160,10 +1190,16 @@ void AVD_SU::unlock_instantiation(SaImmOiHandleT 
immoi_handle,
       ((saAmfSUOperState == SA_AMF_OPERATIONAL_ENABLED) ||
        (sg_of_su->sg_ncs_spec == true)) &&
       (sg_of_su->pref_inservice_sus() >
-       sg_instantiated_su_count(sg_of_su))) {
+       sg_instantiated_su_count(sg_of_su)) &&
+      (is_container_ready == true)) {
     /* When the SU will instantiate then prescence state change message will
        come and so store the callback parameters to send response later on. */
-    if (avd_snd_presence_msg(avd_cb, this, false) == NCSCC_RC_SUCCESS) {
+    if (contained() == true)
+      rc = avd_instantiate_contained_su(avd_cb, container_ptr, this, false);
+    else
+      rc = avd_snd_presence_msg(avd_cb, this, false);
+
+    if (rc == NCSCC_RC_SUCCESS) {
       set_term_state(false);
       set_admin_state(SA_AMF_ADMIN_LOCKED);
       pend_cbk.admin_oper = SA_AMF_ADMIN_UNLOCK_INSTANTIATION;
@@ -2359,7 +2395,7 @@ AVD_AVND *AVD_SU::get_node_ptr(void) const {
  * @param su
  * @return true if SU can be made in-service
  */
-bool AVD_SU::is_in_service(void) {
+bool AVD_SU::is_in_service(void) const {
   AVD_AVND *node = get_node_ptr();
   const AVD_SG *sg = sg_of_su;
   const AVD_APP *app = sg->app;
@@ -2803,3 +2839,116 @@ uint32_t AVD_SU::count_susi_without_fsm(uint32_t fsm) {
   }
   return count;
 }
+
+/**
+ * @brief  Checks if all comps of SU are container comps.
+ * @return true/false
+ */
+bool AVD_SU::container(void) const {
+  if (std::all_of(list_of_comp.begin(), list_of_comp.end(),
+                  [&](AVD_COMP *comp) -> bool {
+                    return comp->container();
+                  })) {
+    return true;
+  } else {
+    return false;
+  }
+}
+/**
+ * @brief  Checks if all comps of SU are contained comps.
+ * @return true/false
+ */
+bool AVD_SU::contained(void) const {
+  if (std::all_of(list_of_comp.begin(), list_of_comp.end(),
+                  [&](AVD_COMP *comp) -> bool {
+                    return comp->contained();
+                  })) {
+    return true;
+  } else {
+    return false;
+  }
+}
+/**
+ * @brief  Checks if any comp of SU is a container comp.
+ * @return true/false
+ */
+bool AVD_SU::any_container_comp(void) const {
+  return (std::any_of(list_of_comp.begin(), list_of_comp.end(),
+                  [&](AVD_COMP *comp) -> bool {
+                    return comp->container();
+                  }));
+
+}
+
+/**
+ * @brief  Checks if any comp of SU is a contained comp.
+ * @return true/false
+ */
+bool AVD_SU::any_contained_comp(void) const {
+  return (std::any_of(list_of_comp.begin(), list_of_comp.end(),
+                  [&](AVD_COMP *comp) -> bool {
+                    return comp->contained();
+                  }));
+}
+
+bool AVD_SU::is_ready_for_contained(void) const {
+  if ((container() == true) && (list_of_susi != nullptr) &&
+      (is_in_service() == true) && (any_container_csi_assigned() == true))
+    return true;
+  return false;
+}
+
+void AVD_SU::instantiate_associated_contained_sus(void) {
+  TRACE_ENTER();
+  if (is_ready_for_contained() == false) {
+    TRACE_LEAVE();
+    return;
+  }
+  for (AVD_SU_SI_REL *susi = list_of_susi; susi != nullptr;
+       susi = susi->su_next) {
+     if (susi->fsm != AVD_SU_SI_STATE_ASGND)
+       continue;
+     for (AVD_COMP_CSI_REL *compcsi = susi->list_of_csicomp; compcsi;
+          compcsi = compcsi->susi_csicomp_next) {
+       if (compcsi->csi->is_container_csi() == true) {
+         su_on_node->instantiate_contained_sus(this, compcsi->csi);
+       }
+     }
+  }
+  TRACE_LEAVE();
+}
+
+bool AVD_SU::any_container_csi_assigned(void) const {
+  for (AVD_SU_SI_REL *susi = list_of_susi; susi != nullptr;
+       susi = susi->su_next) {
+    if (susi->fsm != AVD_SU_SI_STATE_ASGND)
+      continue;
+    for (AVD_COMP_CSI_REL *compcsi = susi->list_of_csicomp; compcsi;
+         compcsi = compcsi->susi_csicomp_next) {
+      if (compcsi->csi->is_container_csi() == true)
+        return true;
+     }
+  }
+  return false;
+}
+
+AVD_CSI *AVD_SU::get_container_csi(void) {
+  if (list_of_comp.empty())
+    return nullptr;
+  auto comp = list_of_comp.front();
+  return csi_db->find(comp->saAmfCompContainerCsi);
+}
+
+AVD_SU *AVD_SU::get_container_su_on_same_node(void) {
+  AVD_CSI *container_csi = get_container_csi();
+  if (container_csi != nullptr)  {
+    for (AVD_COMP_CSI_REL *compcsi = container_csi->list_compcsi;
+         compcsi;
+         compcsi = compcsi->csi_csicomp_next) {
+      if (compcsi->comp->su->su_on_node == su_on_node)
+        return compcsi->comp->su;
+    }
+  }
+  //TODO:70: return a higher rank su always. It should match other function.
+  return nullptr;
+}
diff --git a/src/amf/amfd/su.h b/src/amf/amfd/su.h
index cf29f25de..7afc5abee 100644
--- a/src/amf/amfd/su.h
+++ b/src/amf/amfd/su.h
@@ -37,6 +37,7 @@
 #include "amf/common/amf_db_template.h"
 
 class AVD_SG;
+class AVD_CSI;
 class AVD_SUTYPE;
 
 /**
@@ -88,6 +89,8 @@ class AVD_SU {
 
   int su_act_state;  // not used, kept for EDU, remove later
 
+  bool wait_for_contained_to_quiesce;
+
   AVD_SG *sg_of_su;     /* the service group of this SU */
   AVD_AVND *su_on_node; /*  the node on which this SU resides */
   struct avd_su_si_rel_tag
@@ -122,7 +125,7 @@ class AVD_SU {
   void remove_from_model();
   void set_su_switch(SaToggleState state, bool wrt_to_imm = true);
   AVD_AVND *get_node_ptr(void) const;
-  bool is_in_service(void);
+  bool is_in_service(void) const;
   bool is_instantiable(void);
   void reset_all_comps_assign_flag();
   AVD_COMP *find_unassigned_comp_that_provides_cstype(
@@ -156,6 +159,16 @@ class AVD_SU {
   void set_surestart(bool state);
   bool get_surestart() const;
   void update_susis_in_imm_and_ntf(SaAmfHAStateT ha_state) const;
+  bool any_container_comp(void) const;
+  bool any_contained_comp(void) const;
+  bool container(void) const;
+  bool contained(void) const;
+  void instantiate_associated_contained_sus(void);
+  bool is_ready_for_contained(void) const;
+  bool any_container_csi_assigned(void) const;
+  AVD_CSI *get_container_csi(void);
+  AVD_SU *get_container_su_on_same_node(void);
+
 
  private:
   void initialize();
diff --git a/src/amf/amfd/util.cc b/src/amf/amfd/util.cc
index 288d77483..14a4e0485 100644
--- a/src/amf/amfd/util.cc
+++ b/src/amf/amfd/util.cc
@@ -2123,3 +2123,42 @@ done:
   delete d2n_msg;
   return rc;
 }
+
+uint32_t avd_instantiate_contained_su(AVD_CL_CB *cb, AVD_SU *container_su,
+                                      AVD_SU *contained_su, bool term_state) {
+  uint32_t rc = NCSCC_RC_FAILURE;
+  AVD_DND_MSG *d2n_msg;
+  AVD_AVND *node = container_su->get_node_ptr();
+
+  TRACE_ENTER2("%s '%s'", (term_state == true) ? "Terminate" : "Instantiate",
+               contained_su->name.c_str());
+
+  /* prepare the node update message. */
+  d2n_msg = new AVSV_DND_MSG();
+  SaNameT container_su_name, contained_su_name;
+  osaf_extended_name_alloc(container_su->name.c_str(), &container_su_name);
+  osaf_extended_name_alloc(contained_su->name.c_str(), &contained_su_name);
+
+  /* prepare the SU presence state change notification message */
+  d2n_msg->msg_type = AVSV_D2N_CONTAINED_SU_MSG;
+  d2n_msg->msg_info.d2n_contained_su_msg_info.msg_id = ++(node->snd_msg_id);
+  d2n_msg->msg_info.d2n_contained_su_msg_info.node_id = node->node_info.nodeId;
+  d2n_msg->msg_info.d2n_contained_su_msg_info.container_su_name = 
container_su_name;
+  d2n_msg->msg_info.d2n_contained_su_msg_info.contained_su_name = 
contained_su_name;
+  d2n_msg->msg_info.d2n_contained_su_msg_info.term_state = term_state;
+
+  TRACE("Sending %u to %x", AVSV_D2N_CONTAINED_SU_MSG, node->node_info.nodeId);
+
+  if (avd_d2n_msg_snd(cb, node, d2n_msg) != NCSCC_RC_SUCCESS) {
+    LOG_ER("%s: snd to %x failed", __FUNCTION__, node->node_info.nodeId);
+    d2n_msg_free(d2n_msg);
+    --(node->snd_msg_id);
+    goto done;
+  }
+
+  m_AVSV_SEND_CKPT_UPDT_ASYNC_UPDT(cb, (node), AVSV_CKPT_AVND_SND_MSG_ID);
+  rc = NCSCC_RC_SUCCESS;
+done:
+  TRACE_LEAVE2("%u", rc);
+  return rc;
+}
diff --git a/src/amf/amfd/util.h b/src/amf/amfd/util.h
index 28709493b..39ca5a344 100644
--- a/src/amf/amfd/util.h
+++ b/src/amf/amfd/util.h
@@ -122,5 +122,7 @@ uint32_t avd_snd_compcsi_msg(AVD_COMP *comp, AVD_CSI *csi,
                              avd_comp_csi_rel_tag *compcsi,
                              AVSV_COMPCSI_ACT act);
 uint32_t avd_send_reboot_msg_directly(AVD_AVND *node);
+uint32_t avd_instantiate_contained_su(AVD_CL_CB *cb, AVD_SU *container_su,
+                                      AVD_SU *contained_su, bool term_state);
 
 #endif  // AMF_AMFD_UTIL_H_
-- 
2.14.4


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to