diff --git a/platform/saivpp/vpplib/SaiObjectDB.cpp b/platform/saivpp/vpplib/SaiObjectDB.cpp index b3b13af..7c468e6 100644 --- a/platform/saivpp/vpplib/SaiObjectDB.cpp +++ b/platform/saivpp/vpplib/SaiObjectDB.cpp @@ -23,21 +23,18 @@ #include "SaiObjectDB.h" using namespace saivpp; -typedef struct _SaiChildRelation -{ - sai_object_type_t parent_type; - // the attribute id in child object pointing to Parent object - sai_attr_id_t child_link_attr; - sai_attr_value_type_t child_link_attr_type; -} SaiChildRelation; /* - Define the child relation between SAI objects. Child is dependent on parent object. For example, ROUTE_ENTRY is a child of VR. - Key: child object type - Value: list of child relations. Each child relation defines the parent object type, the attribute id in child object pointing - to Parent object and the attribute type. - Child objects defined in this map will be added to the parent object when the child object is created. From parent object, we - can get the child object by calling get_child_objs() method with the child object type. + * Define the child relation between SAI objects. Child is dependent on parent object. For example, ROUTE_ENTRY is a child of VR. + * Key: child object type + * Value: list of child relations. Each child relation defines the parent object type, the attribute id in child object pointing + * to Parent object and the attribute type. + * Child objects defined in this map will be added to the parent object when the child object is created. From parent object, we + * can get the child object by calling get_child_objs() method with the child object type. + * + * Technically, this definition is not needed. Through SAI meta, we can get find which attribute is type of object_id or object_list. + * From the attribute value and RealObjectIdManager::objectTypeQuery, we can find the parent object type. So we can create a complete + * graph of all SAI objects. */ std::map> sai_child_relation_defs = { {SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY, {{SAI_OBJECT_TYPE_TUNNEL_MAP, SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP, SAI_ATTR_VALUE_TYPE_OBJECT_ID}}}, @@ -45,6 +42,7 @@ std::map> sai_child_relation_de {SAI_OBJECT_TYPE_TUNNEL_MAP, SAI_TUNNEL_ATTR_ENCAP_MAPPERS, SAI_ATTR_VALUE_TYPE_OBJECT_LIST}}}, {SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY, {{SAI_OBJECT_TYPE_TUNNEL, SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID, SAI_ATTR_VALUE_TYPE_OBJECT_ID}}}, {SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, {{SAI_OBJECT_TYPE_NEXT_HOP_GROUP, SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID, SAI_ATTR_VALUE_TYPE_OBJECT_ID}}}, + {SAI_OBJECT_TYPE_ROUTE_ENTRY, {{SAI_OBJECT_TYPE_NEXT_HOP_GROUP, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, SAI_ATTR_VALUE_TYPE_OBJECT_ID}}}, }; static std::vector @@ -107,12 +105,12 @@ get_parent_oids(SwitchStateBase* switch_db, sai_object_type_t child_type, const } sai_status_t -SaiObjectDB::add( +SaiObjectDB::create_or_update( _In_ sai_object_type_t object_type, _In_ const std::string& id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list) + _In_ const sai_attribute_t *attr_list, + _In_ bool is_create) { sai_status_t status; auto child_def_it = sai_child_relation_defs.find(object_type); @@ -120,8 +118,7 @@ SaiObjectDB::add( // Not an interesting type return SAI_STATUS_SUCCESS; } - sai_object_id_t oid; - sai_deserialize_object_id(id, oid); + //Get Parent object type and OID const sai_attribute_value_t *attr_val; uint32_t attr_index; @@ -131,15 +128,30 @@ SaiObjectDB::add( status = find_attrib_in_list(attr_count, attr_list, child_def.child_link_attr, &attr_val, &attr_index); if (status != SAI_STATUS_SUCCESS) { - // attribute not found - return SAI_STATUS_SUCCESS; + // attribute not found. move to next child relation. + continue; + } + + if (!is_create) { + //update the parent-child relationship + remove_child_from_parent(object_type, id, child_def); } auto sai_parents = m_sai_parent_objs[child_def.parent_type]; std::shared_ptr sai_parent; - std::vector parent_ids = get_parent_oids(attr_val, child_def); + for (auto parent_id: parent_ids) { + sai_object_id_t parent_oid; + sai_deserialize_object_id(parent_id, parent_oid); + sai_object_type_t parent_type = RealObjectIdManager::objectTypeQuery(parent_oid); + if (parent_type != child_def.parent_type) { + /* + * a child may refer to different type of parents with the same parent OID attribute. For example, + * ROUTE_ENTRY uses SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID to refer to NEXT_HOP or NEXT_HOP_GROUP. + */ + continue; + } auto parent_it = sai_parents.find(parent_id); if (parent_it == sai_parents.end()) { //The Parent object hasn't been created. create the Parent object @@ -149,16 +161,73 @@ SaiObjectDB::add( sai_parent = parent_it->second; } m_sai_parent_objs[child_def.parent_type] = sai_parents; + // multiple copies of child objects can exist as leaf of different parent objects. There can even + // be a copy as parent object if it is created as child first then another object is added as its child. + // Today SaiDBObject is just a wrapper to the underlaying object in switch_db + // until it becomes a parent object, where parent-child relationship is maintained. When the object is + // deleted, it will be removed from the child list of parent objects and from the SaiObjectDB if it is + // also a parent object. Since SaiDBObject is a simple wrapper if it is a child object, it is ok to have + // multiple copies. If we are going to extend it to keep other information, we need to make sure that + // a single copy exists in the SaiObjectDB. auto sai_child = std::make_shared(m_switch_db, object_type, id); sai_parent->add_child(sai_child); - SWSS_LOG_DEBUG("Add child %s to parent %s of type %s", id.c_str(), parent_id.c_str(), - sai_serialize_object_type(child_def.parent_type).c_str()); + SWSS_LOG_INFO("Add child %s:%s to parent %s:%s", + sai_serialize_object_type(object_type).c_str(), id.c_str(), + sai_serialize_object_type(child_def.parent_type).c_str(), parent_id.c_str()); } } return SAI_STATUS_SUCCESS; } +/** + * @brief Removes a child object from its parent in the SaiObjectDB for the give child-parent relationship definition. + * + * This function removes a child object from its parent in the SaiObjectDB. It takes the object type, the ID of the child object, + * and the child-parent relationship definition as input parameters. + * The function retrieves the parent object IDs using the get_parent_oids() function and iterates over each parent ID. + * For each parent ID, it checks if the parent object exists in the SaiObjectDB. If the parent object is not found, a warning + * message is logged and the function returns SAI_STATUS_SUCCESS. + * If the parent object is found, the function removes the child object from the parent object using the remove_child() + * function and logs a debug message. + * + * @param object_type The type of the child object. + * @param id The ID of the child object. + * @param child_def The child-parent relationship definition. + */ +void +SaiObjectDB::remove_child_from_parent( + _In_ sai_object_type_t object_type, + _In_ const std::string& id, + _In_ const SaiChildRelation& child_def) +{ + std::vector parent_ids = get_parent_oids(m_switch_db, object_type, id, child_def); + auto sai_parents = m_sai_parent_objs[child_def.parent_type]; + for (auto parent_id: parent_ids) { + sai_object_id_t parent_oid; + sai_deserialize_object_id(parent_id, parent_oid); + sai_object_type_t parent_type = RealObjectIdManager::objectTypeQuery(parent_oid); + if (parent_type != child_def.parent_type) { + /* + * a child may refer to different type of parents with the same parent OID attribute. For example, + * ROUTE_ENTRY uses SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID to refer to NEXT_HOP or NEXT_HOP_GROUP. + */ + continue; + } + auto parent_it = sai_parents.find(parent_id); + if (parent_it == sai_parents.end()) { + SWSS_LOG_WARN("Parent object %s:%s is not found in SaiObjectDB", + sai_serialize_object_type(child_def.parent_type).c_str(), parent_id.c_str()); + return; + } else { + //remove the child from sai_parent + parent_it->second->remove_child(object_type, id); + SWSS_LOG_INFO("Remove child %s:%s from parent %s:%s of type %s", + sai_serialize_object_type(object_type).c_str(), id.c_str(), + sai_serialize_object_type(child_def.parent_type).c_str(), parent_id.c_str()); + } + } +} sai_status_t SaiObjectDB::remove( _In_ sai_object_type_t object_type, @@ -186,20 +255,7 @@ SaiObjectDB::remove( //Get Parent object type and OID auto& child_defs = child_def_it->second; for (auto child_def: child_defs) { - std::vector parent_ids = get_parent_oids(m_switch_db, object_type, id, child_def); - auto sai_parents = m_sai_parent_objs[child_def.parent_type]; - for (auto parent_id: parent_ids) { - auto parent_it = sai_parents.find(parent_id); - if (parent_it == sai_parents.end()) { - SWSS_LOG_WARN("Parent object is not found in SaiObjectDB %s", parent_id.c_str()); - return SAI_STATUS_SUCCESS; - } else { - //remove the child from sai_parent - parent_it->second->remove_child(object_type, id); - SWSS_LOG_DEBUG("Remove child %s from parent %s of type %s", id.c_str(), parent_id.c_str(), - sai_serialize_object_type(child_def.parent_type).c_str()); - } - } + remove_child_from_parent(object_type, id, child_def); } return SAI_STATUS_SUCCESS; } @@ -217,9 +273,6 @@ SaiObjectDB::get( auto sai_parent_it = sai_parent_type_it->second.find(id); if (sai_parent_it != sai_parent_type_it->second.end()) { return sai_parent_it->second; - } else { - SWSS_LOG_WARN("Parent is not found in SaiObjectDB %s", id.c_str()); - return std::shared_ptr(); } } // check if the object exists @@ -293,26 +346,25 @@ SaiObject::get_attr_name(_In_ sai_attr_id_t attr_id) const return meta->attridname; } } -sai_status_t -SaiCachedObject::get_attr(sai_attribute_t &attr) const + +sai_status_t +SaiObject::get_mandatory_attr(sai_attribute_t &attr) const { - for (uint32_t ii = 0; ii < m_attr_count; ii++) { - if (m_attr_list[ii].id == attr.id) { - return transfer_attributes(m_type, 1, &(m_attr_list[ii]), &attr, false); - } + auto status = get_attr(attr); + if (SAI_STATUS_SUCCESS != status) { + SWSS_LOG_ERROR("Failed to get attribute %s from object %s", get_attr_name(attr.id), m_id.c_str()); } - return SAI_STATUS_ITEM_NOT_FOUND; + return status; } sai_status_t -SaiCachedObject::get_mandatory_attr(sai_attribute_t &attr) const +SaiCachedObject::get_attr(sai_attribute_t &attr) const { for (uint32_t ii = 0; ii < m_attr_count; ii++) { if (m_attr_list[ii].id == attr.id) { return transfer_attributes(m_type, 1, &(m_attr_list[ii]), &attr, false); } } - SWSS_LOG_ERROR("Failed to get attribute %d from object %s", get_attr_name(attr.id), m_id.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } @@ -323,13 +375,27 @@ SaiDBObject::get_attr(sai_attribute_t &attr) const return m_switch_db->get(m_type, m_id, 1, &attr); } +SaiModDBObject::SaiModDBObject(SwitchStateBase* switch_db, sai_object_type_t type, const std::string& id, + uint32_t attr_count, const sai_attribute_t *attr_list) : + SaiObject(switch_db, type, id), m_attr_count(attr_count), m_attr_list(attr_list) +{ + m_sai_db_obj = switch_db->get_sai_object(type, id); + if (!m_sai_db_obj) { + SWSS_LOG_ERROR("SaiModDBObject: the object is not found in switch_db %s", id.c_str()); + } +} + sai_status_t -SaiDBObject::get_mandatory_attr(sai_attribute_t &attr) const +SaiModDBObject::get_attr(sai_attribute_t &attr) const { - /* we could make a copy of all the attributes and cache in this object*/ - auto status = m_switch_db->get(m_type, m_id, 1, &attr); - if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Failed to get attribute %d from object %s", get_attr_name(attr.id), m_id.c_str()); + for (uint32_t ii = 0; ii < m_attr_count; ii++) { + if (m_attr_list[ii].id == attr.id) { + return transfer_attributes(m_type, 1, &(m_attr_list[ii]), &attr, false); + } } - return status; -} \ No newline at end of file + if (m_sai_db_obj) { + return m_sai_db_obj->get_attr(attr); + } else { + return SAI_STATUS_ITEM_NOT_FOUND; + } +} diff --git a/platform/saivpp/vpplib/SaiObjectDB.h b/platform/saivpp/vpplib/SaiObjectDB.h index ed5e2a0..4c94c15 100644 --- a/platform/saivpp/vpplib/SaiObjectDB.h +++ b/platform/saivpp/vpplib/SaiObjectDB.h @@ -31,6 +31,14 @@ namespace saivpp */ class SwitchStateBase; class SaiDBObject; + + typedef struct _SaiChildRelation + { + sai_object_type_t parent_type; + // the attribute id in child object pointing to Parent object + sai_attr_id_t child_link_attr; + sai_attr_value_type_t child_link_attr_type; + } SaiChildRelation; /* SaiObject is the base class for all objects in the SaiObjectDB. @@ -45,8 +53,14 @@ namespace saivpp virtual sai_status_t get_attr(_Out_ sai_attribute_t &attr) const = 0; - // Get the manditory attribute of the object. If not found, log an error and return SAI_STATUS_FAILURE - virtual sai_status_t get_mandatory_attr(_Out_ sai_attribute_t &attr) const = 0; + /** + * @brief Retrieves the value of a specific attribute of the SAI object. If the attribute is not found, log an error and + * return SAI_STATUS_FAILURE. + * + * @param attr [out] A reference to the sai_attribute_t structure to store the attribute value. + * @return sai_status_t The status of the attribute retrieval operation. + */ + sai_status_t get_mandatory_attr(_Out_ sai_attribute_t &attr) const; const std::string& get_id() const { return m_id; } @@ -97,15 +111,6 @@ namespace saivpp */ sai_status_t get_attr(_Out_ sai_attribute_t &attr) const override; - /** - * @brief Retrieves the value of a specific attribute of the SAI object. If the attribute is not found, log an error and - * return SAI_STATUS_FAILURE. - * - * @param attr [out] A reference to the sai_attribute_t structure to store the attribute value. - * @return sai_status_t The status of the attribute retrieval operation. - */ - sai_status_t get_mandatory_attr(_Out_ sai_attribute_t &attr) const override; - private: /**< The number of attributes associated with the SAI object. */ uint32_t m_attr_count; @@ -144,15 +149,6 @@ namespace saivpp * @return The status of the operation. */ sai_status_t get_attr(_Out_ sai_attribute_t &attr) const override; - - /** - * @brief Retrieves the value of a specific attribute of the SAI object. If the attribute is not found, log an error and - * return SAI_STATUS_FAILURE. - * - * @param attr [out] A reference to the sai_attribute_t structure to store the attribute value. - * @return sai_status_t The status of the attribute retrieval operation. - */ - sai_status_t get_mandatory_attr(_Out_ sai_attribute_t &attr) const override; /** * @brief Retrieves the child objects of the specified type. @@ -205,10 +201,39 @@ namespace saivpp private: /** * @brief A map of child objects based on their type and ID. + * child-type -> child-oid -> child-object */ std::unordered_map>> m_child_map; }; + class SaiModDBObject : public SaiObject { + public: + SaiModDBObject(SwitchStateBase* switch_db, sai_object_type_t type, const std::string& id, + uint32_t attr_count, const sai_attribute_t *attr_list); + + ~SaiModDBObject() = default; + + sai_status_t get_attr(_Out_ sai_attribute_t &attr) const override; + + std::shared_ptr get_db_obj() const { + return m_sai_db_obj; + } + + const std::unordered_map>* get_child_objs(sai_object_type_t child_type) const { + if (m_sai_db_obj) { + return m_sai_db_obj->get_child_objs(child_type); + } else { + return nullptr; + } + } + private: + /**< The number of modified attributes associated with the SAI object. */ + uint32_t m_attr_count; + /**< An array of sai_attribute_t structures representing the modified attributes of the SAI object. */ + const sai_attribute_t *m_attr_list; + std::shared_ptr m_sai_db_obj; + }; + /** * @brief The SaiObjectDB class represents a database for managed SAI objects. Only the SAI objects we are interested are * added to SaiObjectDB. See sai_child_relation_defs in SaiObjectDB.cpp for such objects. @@ -233,21 +258,22 @@ namespace saivpp ~SaiObjectDB() = default; /** - * @brief Adds a new SAI object to the database. + * @brief Adds a new SAI object to the database or update an existing one if it already exists, + * which includes removing the child from the current parent and adding it to the new parent. * * @param object_type The type of the SAI object. * @param id The ID of the SAI object. - * @param switch_id The ID of the switch to which the SAI object belongs. * @param attr_count The number of attributes in the attribute list. * @param attr_list An array of attributes for the SAI object. + * @param is_create A flag indicating whether the object is being created. * @return The status of the operation. */ - sai_status_t add( + sai_status_t create_or_update( _In_ sai_object_type_t object_type, _In_ const std::string& id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list); + _In_ const sai_attribute_t *attr_list, + _In_ bool is_create); /** * @brief Removes an existing SAI object from the database. @@ -274,7 +300,27 @@ namespace saivpp private: // Pointer to the switch database SwitchStateBase* m_switch_db; - // Map of SAI parent objects based on their object type and ID + /** + * @brief A map of SAI parent objects based on their type and ID. + * parent-type -> parent-oid -> parent-object + * a parent object has a map of child objects based on their type and ID. + */ std::unordered_map>> m_sai_parent_objs; + /** + * @brief Removes a child object from its parent in the SaiObjectDB for the give child-parent relationship definition. + * + * This function removes a child object from its parent in the SaiObjectDB. It takes the object type, the ID of the child object, + * and the child-parent relationship definition as input parameters. + * The function retrieves the parent object IDs using the get_parent_oids() function and iterates over each parent ID. + * For each parent ID, it checks if the parent object exists in the SaiObjectDB. If the parent object is not found, a warning + * message is logged and the function returns SAI_STATUS_SUCCESS. + * If the parent object is found, the function removes the child object from the parent object using the remove_child() + * function and logs a debug message. + * + * @param object_type The type of the child object. + * @param id The ID of the child object. + * @param child_def The child-parent relationship definition. + */ + void remove_child_from_parent(_In_ sai_object_type_t object_type, _In_ const std::string& id, _In_ const SaiChildRelation& child_def); }; } \ No newline at end of file diff --git a/platform/saivpp/vpplib/SwitchStateBase.cpp b/platform/saivpp/vpplib/SwitchStateBase.cpp index fcb9d35..2092e99 100644 --- a/platform/saivpp/vpplib/SwitchStateBase.cpp +++ b/platform/saivpp/vpplib/SwitchStateBase.cpp @@ -196,7 +196,12 @@ sai_status_t SwitchStateBase::create( { return createNexthop(serializedObjectId, switch_id, attr_count, attr_list); } - + + if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) + { + return createNexthopGroupMember(serializedObjectId, switch_id, attr_count, attr_list); + } + if (object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) { return addIpNbr(serializedObjectId, switch_id, attr_count, attr_list); @@ -329,7 +334,7 @@ sai_status_t SwitchStateBase::create_internal( objectHash[serializedObjectId][a->getAttrMetadata()->attridname] = a; } - m_object_db.add(object_type, serializedObjectId, switch_id, attr_count, attr_list); + m_object_db.create_or_update(object_type, serializedObjectId, attr_count, attr_list, true/*is_create*/); return SAI_STATUS_SUCCESS; } @@ -485,6 +490,11 @@ sai_status_t SwitchStateBase::remove( return removeNexthop(serializedObjectId); } + if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) + { + return removeNexthopGroupMember(serializedObjectId); + } + if (object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) { return removeIpNbr(serializedObjectId); @@ -706,6 +716,9 @@ sai_status_t SwitchStateBase::set_internal( _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); + + //Update child-parent relationship before updating the attribute + m_object_db.create_or_update(objectType, serializedObjectId, 1, attr, false/*is_create*/); auto it = m_objectHash.at(objectType).find(serializedObjectId); diff --git a/platform/saivpp/vpplib/SwitchStateBase.h b/platform/saivpp/vpplib/SwitchStateBase.h index f59302a..2d8945c 100644 --- a/platform/saivpp/vpplib/SwitchStateBase.h +++ b/platform/saivpp/vpplib/SwitchStateBase.h @@ -796,8 +796,7 @@ namespace saivpp _Out_ nexthop_grp_config_t **nxthop_group); sai_status_t IpRouteNexthopEntry( - _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list, + _In_ sai_object_id_t next_hop_oid, _Out_ nexthop_grp_config_t **nxthop_group_cfg); sai_status_t createNexthop( @@ -808,7 +807,16 @@ namespace saivpp sai_status_t removeNexthop( _In_ const std::string &serializedObjectId); - + + sai_status_t createNexthopGroupMember( + _In_ const std::string& serializedObjectId, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t removeNexthopGroupMember( + _In_ const std::string& serializedObjectId); + protected: sai_status_t createRouterif( _In_ sai_object_id_t object_id, @@ -933,9 +941,7 @@ namespace saivpp _In_ const std::string &ipAddress); sai_status_t IpRouteAddRemove( - _In_ const std::string &serializedObjectId, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list, + _In_ const SaiObject* route_obj, _In_ bool is_add); sai_status_t updateIpRoute( _In_ const std::string &serializedObjectId, diff --git a/platform/saivpp/vpplib/SwitchStateBaseNexthop.cpp b/platform/saivpp/vpplib/SwitchStateBaseNexthop.cpp index 737b85b..4582542 100644 --- a/platform/saivpp/vpplib/SwitchStateBaseNexthop.cpp +++ b/platform/saivpp/vpplib/SwitchStateBaseNexthop.cpp @@ -124,21 +124,11 @@ sai_status_t SwitchStateBase::IpRouteNexthopGroupEntry( } sai_status_t SwitchStateBase::IpRouteNexthopEntry( - _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list, + _In_ sai_object_id_t next_hop_oid, _Out_ nexthop_grp_config_t **nxthop_group_cfg) { sai_status_t status; - const sai_attribute_value_t *next_hop; - sai_object_id_t next_hop_oid; - uint32_t next_hop_index; nexthop_grp_config_t *nxthop_group; - status = find_attrib_in_list(attr_count, attr_list, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - &next_hop, &next_hop_index); - if (status != SAI_STATUS_SUCCESS) { - return status; - } - next_hop_oid = next_hop->oid; nxthop_group = (nexthop_grp_config_t *) calloc(1, sizeof(nexthop_grp_config_t) + (1 * sizeof(nexthop_grp_member_t))); @@ -213,7 +203,7 @@ SwitchStateBase::fillNHGrpMember(nexthop_grp_member_t *nxt_grp_member, sai_objec u_int32_t sw_if_index; if (m_tunnel_mgr.get_tunnel_if(next_hop_oid, sw_if_index) == SAI_STATUS_SUCCESS) { nxt_grp_member->sw_if_index = sw_if_index; - SWSS_LOG_DEBUG("Got tunnel interface %d for nexthop %s", sw_if_index, + SWSS_LOG_INFO("Got tunnel interface %d for nexthop %s", sw_if_index, sai_serialize_object_id(next_hop_oid).c_str()); } else { SWSS_LOG_ERROR("Failed to get tunnel interface name for nexthop %s", @@ -270,4 +260,87 @@ sai_status_t SwitchStateBase::removeNexthop( } return remove_internal(SAI_OBJECT_TYPE_NEXT_HOP, serializedObjectId); +} + +sai_status_t +SwitchStateBase::createNexthopGroupMember( + _In_ const std::string& serializedObjectId, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + sai_status_t status; + sai_attribute_t attr; + SWSS_LOG_ENTER(); + + SaiCachedObject nhg_mbr_obj(this, SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, serializedObjectId, attr_count, attr_list); + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; + nhg_mbr_obj.get_mandatory_attr(attr); + SWSS_LOG_NOTICE("Creating NHG member %s in nhg %s", serializedObjectId.c_str(), sai_serialize_object_id(attr.value.oid).c_str()); + auto nhg_obj = nhg_mbr_obj.get_linked_object(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID); + if (nhg_obj == nullptr) { + SWSS_LOG_ERROR("Failed to find SAI_OBJECT_TYPE_NEXT_HOP_GROUP from %s", serializedObjectId.c_str()); + return SAI_STATUS_FAILURE; + } + + //call create_internal to update the mapping from NHG to NHG_MBRs, which is used to update the routes + status = create_internal(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, serializedObjectId, switch_id, attr_count, attr_list); + if (status != SAI_STATUS_SUCCESS) { + return status; + } + + auto routes = nhg_obj->get_child_objs(SAI_OBJECT_TYPE_ROUTE_ENTRY); + if (routes == nullptr) { + return SAI_STATUS_SUCCESS; + } + + for (auto route : *routes) { + SWSS_LOG_NOTICE("NHG member changed. Updating route %s", route.first.c_str()); + IpRouteAddRemove(route.second.get(), false); + IpRouteAddRemove(route.second.get(), true); + } + return SAI_STATUS_SUCCESS; +} + +sai_status_t +SwitchStateBase::removeNexthopGroupMember( + _In_ const std::string &serializedObjectId) +{ + sai_status_t status; + sai_attribute_t attr; + SWSS_LOG_ENTER(); + + auto nhg_mbr_obj = get_sai_object(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, serializedObjectId); + if (!nhg_mbr_obj) { + SWSS_LOG_ERROR("Failed to find SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER SaiObject: %s", serializedObjectId.c_str()); + return SAI_STATUS_FAILURE; + } + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; + nhg_mbr_obj->get_mandatory_attr(attr); + SWSS_LOG_NOTICE("Deleting NHG member %s from nhg %s", serializedObjectId.c_str(), sai_serialize_object_id(attr.value.oid).c_str()); + + auto nhg_obj = nhg_mbr_obj->get_linked_object(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID); + if (nhg_obj == nullptr) { + SWSS_LOG_ERROR("Failed to find SAI_OBJECT_TYPE_NEXT_HOP_GROUP from %s", serializedObjectId.c_str()); + return SAI_STATUS_FAILURE; + } + + auto routes = nhg_obj->get_child_objs(SAI_OBJECT_TYPE_ROUTE_ENTRY); + + //call remove_internal to update the mapping from NHG to NHG_MBRs + status = remove_internal(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, serializedObjectId); + if (status != SAI_STATUS_SUCCESS) { + return status; + } + + if (routes == nullptr) { + return SAI_STATUS_SUCCESS; + } + + for (auto route : *routes) { + SWSS_LOG_NOTICE("NHG member changed. Updating route %s", route.first.c_str()); + IpRouteAddRemove(route.second.get(), false); + IpRouteAddRemove(route.second.get(), true); + } + return SAI_STATUS_SUCCESS; } \ No newline at end of file diff --git a/platform/saivpp/vpplib/SwitchStateBaseRoute.cpp b/platform/saivpp/vpplib/SwitchStateBaseRoute.cpp index c1c7e71..889c618 100644 --- a/platform/saivpp/vpplib/SwitchStateBaseRoute.cpp +++ b/platform/saivpp/vpplib/SwitchStateBaseRoute.cpp @@ -104,24 +104,20 @@ void create_vpp_nexthop_entry ( } sai_status_t SwitchStateBase::IpRouteAddRemove( - _In_ const std::string &serializedObjectId, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list, - _In_ bool is_add) + _In_ const SaiObject* route_obj, + _In_ bool is_add) { SWSS_LOG_ENTER(); int ret = SAI_STATUS_SUCCESS; sai_status_t status; - const sai_attribute_value_t *next_hop; sai_object_id_t next_hop_oid; - uint32_t next_hop_index; - - status = find_attrib_in_list(attr_count, attr_list, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, &next_hop, &next_hop_index); - if (status != SAI_STATUS_SUCCESS) { - return status; - } - next_hop_oid = next_hop->oid; + sai_attribute_t attr; + std::string serializedObjectId = route_obj->get_id(); + + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + CHECK_STATUS_QUIET(route_obj->get_mandatory_attr(attr)); + next_hop_oid = attr.value.oid; sai_route_entry_t route_entry; const char *hwif_name = NULL; @@ -138,47 +134,47 @@ sai_status_t SwitchStateBase::IpRouteAddRemove( } else if (SAI_OBJECT_TYPE_PORT == sai_object_type_query(next_hop_oid)) { - status = find_attrib_in_list(attr_count, attr_list, SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, - &next_hop, &next_hop_index); - if (status == SAI_STATUS_SUCCESS && SAI_PACKET_ACTION_FORWARD == next_hop->s32) { - vpp_add_del_intf_ip_addr_norif(serializedObjectId, route_entry, is_add); - } + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + status = route_obj->get_attr(attr); + + if (status == SAI_STATUS_SUCCESS && SAI_PACKET_ACTION_FORWARD == attr.value.s32) { + vpp_add_del_intf_ip_addr_norif(serializedObjectId, route_entry, is_add); + } } else if (SAI_OBJECT_TYPE_NEXT_HOP == sai_object_type_query(next_hop_oid)) { - - if (IpRouteNexthopEntry(attr_count, attr_list, &nxthop_group) == SAI_STATUS_SUCCESS) + if (IpRouteNexthopEntry(next_hop_oid, &nxthop_group) == SAI_STATUS_SUCCESS) { - config_ip_route = true; - } + config_ip_route = true; + } } else if (SAI_OBJECT_TYPE_NEXT_HOP_GROUP == sai_object_type_query(next_hop_oid)) { - if (IpRouteNexthopGroupEntry(next_hop_oid, &nxthop_group) == SAI_STATUS_SUCCESS) + if (IpRouteNexthopGroupEntry(next_hop_oid, &nxthop_group) == SAI_STATUS_SUCCESS) { - config_ip_route = true; - } + config_ip_route = true; + } } if (config_ip_route == true) { - std::shared_ptr vrf; - uint32_t vrf_id; - - vrf = vpp_get_ip_vrf(route_entry.vr_id); - if (vrf == nullptr) { - vrf_id = 0; - } else { - vrf_id = vrf->m_vrf_id; - } - vpp_ip_route_t *ip_route = (vpp_ip_route_t *) + std::shared_ptr vrf; + uint32_t vrf_id; + + vrf = vpp_get_ip_vrf(route_entry.vr_id); + if (vrf == nullptr) { + vrf_id = 0; + } else { + vrf_id = vrf->m_vrf_id; + } + vpp_ip_route_t *ip_route = (vpp_ip_route_t *) calloc(1, sizeof(vpp_ip_route_t) + (nxthop_group->nmembers * sizeof(vpp_ip_nexthop_t))); - if (!ip_route) { - return SAI_STATUS_FAILURE; - } - create_route_prefix_entry(&route_entry, ip_route); - ip_route->vrf_id = vrf_id; - ip_route->is_multipath = (nxthop_group->nmembers > 1) ? true : false; + if (!ip_route) { + return SAI_STATUS_FAILURE; + } + create_route_prefix_entry(&route_entry, ip_route); + ip_route->vrf_id = vrf_id; + ip_route->is_multipath = (nxthop_group->nmembers > 1) ? true : false; nexthop_grp_member_t *nxt_grp_member; @@ -191,19 +187,19 @@ sai_status_t SwitchStateBase::IpRouteAddRemove( } ip_route->nexthop_cnt = nxthop_group->nmembers; - ret = ip_route_add_del(ip_route, is_add); + ret = ip_route_add_del(ip_route, is_add); - SWSS_LOG_NOTICE("%s ip route in VPP %s status %d table %u", (is_add ? "Add" : "Remove"), - serializedObjectId.c_str(), ret, vrf_id); - SWSS_LOG_NOTICE("%s route nexthop type %s count %u", (is_add ? "Add" : "Remove"), - sai_serialize_object_type(sai_object_type_query(next_hop_oid)).c_str(), - nxthop_group->nmembers); + SWSS_LOG_NOTICE("%s ip route in VPP %s status %d table %u", (is_add ? "Add" : "Remove"), + serializedObjectId.c_str(), ret, vrf_id); + SWSS_LOG_NOTICE("%s route nexthop type %s count %u", (is_add ? "Add" : "Remove"), + sai_serialize_object_type(sai_object_type_query(next_hop_oid)).c_str(), + nxthop_group->nmembers); - free(ip_route); + free(ip_route); free(nxthop_group); } else { - SWSS_LOG_NOTICE("Ignoring VPP ip route %s", serializedObjectId.c_str()); + SWSS_LOG_NOTICE("Ignoring VPP ip route %s", serializedObjectId.c_str()); } return ret; @@ -229,12 +225,12 @@ sai_status_t SwitchStateBase::addIpRoute( } if (isTunnelNh) { - IpRouteAddRemove(serializedObjectId, attr_count, attr_list, true); + IpRouteAddRemove(&ip_route_obj, true); } else { process_interface_loopback(serializedObjectId, isLoopback, true); if (isLoopback == false && is_ip_nbr_active() == true) { - IpRouteAddRemove(serializedObjectId, attr_count, attr_list, true); + IpRouteAddRemove(&ip_route_obj, true); } } @@ -251,24 +247,17 @@ sai_status_t SwitchStateBase::updateIpRoute( if (is_ip_nbr_active() == true) { SWSS_LOG_NOTICE("ip route entry update %s", serializedObjectId.c_str()); - - sai_attribute_t attr_list[2]; - - attr_list[0].id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - - if (get(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, 1, &attr_list[0]) == SAI_STATUS_SUCCESS) { - uint32_t attr_count = 1; - - attr_list[1].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - if (get(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, 1, &attr_list[1]) == SAI_STATUS_SUCCESS) - { - attr_count++; - } - - IpRouteAddRemove(serializedObjectId, attr_count, attr_list, false); - } - - IpRouteAddRemove(serializedObjectId, 1, attr, true); + SaiModDBObject route_mod_obj(this, SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, 1, attr); + + auto route_db_obj = route_mod_obj.get_db_obj(); + if (!route_db_obj) { + SWSS_LOG_ERROR("Failed to find SAI_OBJECT_TYPE_ROUTE_ENTRY SaiObject: %s", serializedObjectId.c_str()); + return SAI_STATUS_FAILURE; + } else { + IpRouteAddRemove(route_db_obj.get(), false); + } + + IpRouteAddRemove(&route_mod_obj, true); } set_internal(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, attr); @@ -285,20 +274,10 @@ sai_status_t SwitchStateBase::removeIpRoute( if (isLoopback == false && is_ip_nbr_active() == true) { - sai_attribute_t attr[2]; - - attr[0].id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - - if (get(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, 1, &attr[0]) == SAI_STATUS_SUCCESS) { - uint32_t attr_count = 1; - - attr[1].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - if (get(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId, 1, &attr[1]) == SAI_STATUS_SUCCESS) - { - attr_count++; - } - - IpRouteAddRemove(serializedObjectId, attr_count, attr, false); + auto route_obj = get_sai_object(SAI_OBJECT_TYPE_ROUTE_ENTRY, serializedObjectId); + + if (route_obj) { + IpRouteAddRemove(route_obj.get(), false); } }