in syncd/ComparisonLogic.cpp [3075:3289]
void ComparisonLogic::applyViewTransition(
_In_ AsicView ¤t,
_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.
*/
}