void ComparisonLogic::applyViewTransition()

in syncd/ComparisonLogic.cpp [3075:3289]


void ComparisonLogic::applyViewTransition(
        _In_ AsicView &current,
        _In_ AsicView &temp)
{
    SWSS_LOG_ENTER();

    SWSS_LOG_TIMER("comparison logic");

    checkSwitch(current, temp);

    checkMatchedPorts(temp);

    /*
     * Process all objects
     */

    /*
     * During iteration no object from temp view are removed, so no need to
     * worry about any iterator issues here since removed objects are only from
     * current view.
     *
     * Order here can't be random, since it can mean that we will be adding
     * routes here, and on some ASICs there is limitation that default routes
     * must be put to ASIC first, so we need to compensate for that.
     *
     * TODO what about remove? can they be removed first ?
     *
     * There is another issue that when we are removing next hop group member
     * and it's the last next hop group member in group where group is still in
     * use by some group, then we can't remove it, we need to first remove
     * route that uses this group, this puts this task in conflict when
     * creating routes.
     *
     * XXX this is workaround. FIXME
     */

    for (auto &obj: temp.m_soAll)
    {
        // TODO make generic list of root objects (or meta SAI for this)

        if (obj.second->getObjectType() == SAI_OBJECT_TYPE_ACL_TABLE_GROUP ||
            obj.second->getObjectType() == SAI_OBJECT_TYPE_ACL_ENTRY)
        {
            if (temp.m_preMatchMap.find(obj.second->getVid()) == temp.m_preMatchMap.end())
            {
                // object not in pre match
                continue;
            }

            SWSS_LOG_INFO("processing explicit pre match: %s:%s",
                    obj.second->m_str_object_type.c_str(),
                    obj.second->m_str_object_id.c_str());

            processObjectForViewTransition(current, temp, obj.second);
        }
    }

    for (auto &obj: temp.m_soAll)
    {
        /*
         * Make sure we will create all neighbor entries before next hop that
         * have the same IP address as neighbor entry. In Broadcom platform
         * neighbor entry needs to be created before next hop with the same ip
         * address otherwise create next hop will fail (hardware limitation?).
         */

        if (obj.second->getObjectType() == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY)
        {
            processObjectForViewTransition(current, temp, obj.second);
        }
    }

    for (auto &obj: temp.m_soAll)
    {
        if (obj.second->getObjectType() != SAI_OBJECT_TYPE_ROUTE_ENTRY)
        {
            processObjectForViewTransition(current, temp, obj.second);
        }
    }

    for (auto &obj: temp.m_soAll)
    {
        if (obj.second->getObjectType() == SAI_OBJECT_TYPE_ROUTE_ENTRY)
        {
            bool isDefault = obj.second->m_str_object_id.find("/0") != std::string::npos;

            if (isDefault)
            {
                processObjectForViewTransition(current, temp, obj.second);
            }
        }
    }

    for (auto &obj: temp.m_soAll)
    {
        if (obj.second->getObjectType() == SAI_OBJECT_TYPE_ROUTE_ENTRY)
        {
            bool isDefault = obj.second->m_str_object_id.find("/0") != std::string::npos;

            if (!isDefault)
            {
                processObjectForViewTransition(current, temp, obj.second);
            }
        }
    }

    /*
     * There is a problem here with default trap group, since when other trap
     * groups are created and used in traps, then when removing them we reset
     * trap group on traps to default one, and this increases reference count
     * so in this loop, default trap group will not be considered to be removed
     * and it will stay not processed since it will hold reference count on
     * traps. So what we can do here, we can explicitly move default trap group
     * to FINAL state if it's not defined in temporary view, but this problem
     * should go away when we will put all existing objects to temporary view
     * if they don't exist. This apply to v0.9.4 and v1.0
     *
     * Similar thing can happen when we start using PROFILE_ID on
     * SCHEDULER_GROUP.
     *
     * TODO Revisit, since v1.0
     */

    bringDefaultTrapGroupToFinalState(current, temp);

    /*
     * Removing needs to be done from leaf with no references and it can be
     * multiple passes since if in first pass object had non zero references,
     * it can have zero in next pass so it is safe to remove.
     */

    /*
     * Another issue, since user may remove bridge port and vlan members and we
     * don't have references on them on the first place, then it may happen
     * that bridge port remove will be before vlan member remove and it will
     * fail. Similar problem is on hard reinit when removing existing objects.
     *
     * TODO we need dependency tree during sai discovery! but if we put those
     * to redis it will cause another problem, since some of those attributes
     * are create only, so object will be selected to "SET" after vid processing
     * but it wont be able to set create only attributes, we would need to skip
     * those.
     *
     * XXX this is workaround. FIXME
     */

    std::vector<sai_object_type_t> removeOrder = {
        SAI_OBJECT_TYPE_VLAN_MEMBER,
        SAI_OBJECT_TYPE_STP_PORT,
        SAI_OBJECT_TYPE_BRIDGE_PORT };

    for (const sai_object_type_t ot: removeOrder)
    {
        for (const auto &obj: current.getObjectsByObjectType(ot))
        {
            if (obj->getObjectStatus() == SAI_OBJECT_STATUS_NOT_PROCESSED)
            {
                if (current.getVidReferenceCount(obj->getVid()) == 0)
                {
                    removeExistingObjectFromCurrentView(current, temp, obj);
                }
            }
        }
    }

    for (int removed = 1; removed != 0 ;)
    {
        removed = 0;

        for (const auto &obj: current.getAllNotProcessedObjects())
        {
            /*
             * What can happen during this processing some object state during
             * processing can change from not processed to removed, if it have
             * references, currently we are only removing objects with zero
             * references, so this will not happen but in general case this
             * will be the case.
             */

            if (obj->isOidObject())
            {
                if (current.getVidReferenceCount(obj->getVid()) == 0)
                {
                    /*
                     * Reference count on this VID is zero, so it's safe to
                     * remove this object.
                     */

                    removeExistingObjectFromCurrentView(current, temp, obj);
                    removed++;
                }
            }
            else
            {
                /*
                 * Non object id objects don't have references count, they are leafs
                 * so we can remove them right away
                 */

                removeExistingObjectFromCurrentView(current, temp, obj);
                removed++;
            }
        }

        if (removed)
        {
            SWSS_LOG_NOTICE("loop removed %d objects", removed);
        }
    }

    /*
     * Check statuses will make sure that there are no objects with removed
     * status.
     */
}