syncd/SingleReiniter.cpp (735 lines of code) (raw):
#include "SingleReiniter.h"
#include "VidManager.h"
#include "CommandLineOptions.h"
#include "NotificationHandler.h"
#include "Workaround.h"
#include "RedisClient.h"
#include "swss/logger.h"
#include "meta/sai_serialize.h"
#include <unistd.h>
#include <inttypes.h>
using namespace syncd;
using namespace saimeta;
SingleReiniter::SingleReiniter(
_In_ std::shared_ptr<RedisClient> client,
_In_ std::shared_ptr<VirtualOidTranslator> translator,
_In_ std::shared_ptr<sairedis::SaiInterface> sai,
_In_ std::shared_ptr<NotificationHandler> handler,
_In_ const ObjectIdMap& vidToRidMap,
_In_ const ObjectIdMap& ridToVidMap,
_In_ const std::vector<std::string>& asicKeys):
m_vendorSai(sai),
m_vidToRidMap(vidToRidMap),
m_ridToVidMap(ridToVidMap),
m_asicKeys(asicKeys),
m_translator(translator),
m_client(client),
m_handler(handler)
{
SWSS_LOG_ENTER();
m_switch_rid = SAI_NULL_OBJECT_ID;
m_switch_vid = SAI_NULL_OBJECT_ID;
}
SingleReiniter::~SingleReiniter()
{
SWSS_LOG_ENTER();
// empty
}
std::shared_ptr<SaiSwitch> SingleReiniter::hardReinit()
{
SWSS_LOG_ENTER();
SWSS_LOG_TIMER("hard reinit");
prepareAsicState();
processSwitches();
processFdbs();
processNeighbors();
processOids();
processRoutes(true);
processRoutes(false);
processInsegs();
processNatEntries();
#ifdef ENABLE_PERF
double total_create = 0;
double total_set = 0;
for (const auto &p: m_perf_create)
{
SWSS_LOG_NOTICE("create %s: %d: %f",
sai_serialize_object_type(p.first).c_str(),
std::get<0>(p.second),
std::get<1>(p.second));
total_create += std::get<1>(p.second);
}
for (const auto &p: m_perf_set)
{
SWSS_LOG_NOTICE("set %s: %d: %f",
sai_serialize_object_type(p.first).c_str(),
std::get<0>(p.second),
std::get<1>(p.second));
total_set += std::get<1>(p.second);
}
SWSS_LOG_NOTICE("create %lf, set: %lf", total_create, total_set);
#endif
checkAllIds();
return m_sw;
}
void SingleReiniter::prepareAsicState()
{
SWSS_LOG_ENTER();
SWSS_LOG_TIMER("read asic state");
for (auto& key: m_asicKeys)
{
sai_object_type_t objectType = getObjectTypeFromAsicKey(key);
const std::string &strObjectId = getObjectIdFromAsicKey(key);
auto info = sai_metadata_get_object_type_info(objectType);
switch (objectType)
{
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
m_routes[strObjectId] = key;
break;
case SAI_OBJECT_TYPE_FDB_ENTRY:
m_fdbs[strObjectId] = key;
break;
case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:
m_neighbors[strObjectId] = key;
break;
case SAI_OBJECT_TYPE_NAT_ENTRY:
m_nats[strObjectId] = key;
break;
case SAI_OBJECT_TYPE_SWITCH:
m_switches[strObjectId] = key;
m_oids[strObjectId] = key;
break;
default:
if (info->isnonobjectid)
{
SWSS_LOG_THROW("passing non object id %s as generic object", info->objecttypename);
}
m_oids[strObjectId] = key;
break;
}
m_attributesLists[key] = redisGetAttributesFromAsicKey(key);
}
}
sai_object_type_t SingleReiniter::getObjectTypeFromAsicKey(
_In_ const std::string &key)
{
SWSS_LOG_ENTER();
auto start = key.find_first_of(":") + 1;
auto end = key.find(":", start);
const std::string strObjectType = key.substr(start, end - start);
sai_object_type_t objectType;
sai_deserialize_object_type(strObjectType, objectType);
if (!sai_metadata_is_object_type_valid(objectType))
{
SWSS_LOG_THROW("invalid object type: %s on asic key: %s",
sai_serialize_object_type(objectType).c_str(),
key.c_str());
}
return objectType;
}
std::string SingleReiniter::getObjectIdFromAsicKey(
_In_ const std::string &key)
{
SWSS_LOG_ENTER();
auto start = key.find_first_of(":") + 1;
auto end = key.find(":", start);
return key.substr(end + 1);
}
void SingleReiniter::processSwitches()
{
SWSS_LOG_ENTER();
/*
* If there are any switches, we need to create them first to perform any
* other operations.
*
* NOTE: This method needs to be revisited if we want to support multiple
* switches.
*/
if (m_switches.size() > 1)
{
SWSS_LOG_THROW("multiple switches %zu in single hard reinit are not allowed", m_switches.size());
}
/*
* Sanity check in metadata make sure that there are no mandatory on create
* and create only attributes that are object id attributes, since we would
* need create those objects first but we need switch first. So here we
* selecting only MANDATORY_ON_CREATE and CREATE_ONLY attributes to create
* switch.
*/
for (const auto& s: m_switches)
{
std::string strSwitchVid = s.first;
std::string asicKey = s.second;
sai_deserialize_object_id(strSwitchVid, m_switch_vid);
if (m_switch_vid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_THROW("switch id can't be NULL");
}
auto oit = m_oids.find(strSwitchVid);
if (oit == m_oids.end())
{
SWSS_LOG_THROW("failed to find VID %s in OIDs map", strSwitchVid.c_str());
}
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
/*
* If any of those attributes are pointers, fix them, so they will
* point to callbacks in syncd memory.
*/
m_handler->updateNotificationsPointers(attrCount, attrList); // TODO need per switch template static
/*
* Now we need to select only attributes MANDATORY_ON_CREATE and
* CREATE_ONLY and which will not contain object ids.
*
* No need to call processAttributesForOids since we know that there
* are no OID attributes.
*/
uint32_t attr_count = 0; // attr count needed for create
uint32_t attr_count_left = 0; // attr count after create
std::vector<sai_attribute_t> attrs; // attrs for create
std::vector<sai_attribute_t> attrs_left; // attrs for set
for (uint32_t idx = 0; idx < attrCount; ++idx)
{
auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_SWITCH, attrList[idx].id);
if (SAI_HAS_FLAG_MANDATORY_ON_CREATE(meta->flags) || SAI_HAS_FLAG_CREATE_ONLY(meta->flags))
{
/*
* If attribute is mandatory on create or create only, we need
* to select it for switch create method, since it's required
* on create or it will not be possible to change it after
* create.
*
* Currently switch don't have any conditional attributes but
* we could take this into account. Even if any of those
* conditional attributes will present, it will be not be oid
* attribute.
*/
attrs.push_back(attrList[idx]); // struct copy, we will keep the same pointers
attr_count++;
}
else
{
/*
* Those attributes can be OID attributes, so we need to
* process them after creating switch.
*/
attrs_left.push_back(attrList[idx]); // struct copy, we will keep the same pointers
attr_count_left++;
}
}
sai_attribute_t *attr_list = attrs.data();
SWSS_LOG_NOTICE("creating switch VID: %s",
sai_serialize_object_id(m_switch_vid).c_str());
sai_status_t status;
{
SWSS_LOG_TIMER("Cold boot: create switch");
status = m_vendorSai->create(SAI_OBJECT_TYPE_SWITCH, &m_switch_rid, 0, attr_count, attr_list);
}
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_THROW("failed to create switch RID: %s",
sai_serialize_status(status).c_str());
}
SWSS_LOG_NOTICE("created switch RID: %s",
sai_serialize_object_id(m_switch_rid).c_str());
/*
* Save this switch ids as translated.
*/
m_translatedV2R[m_switch_vid] = m_switch_rid;
m_translatedR2V[m_switch_rid] = m_switch_vid;
/*
* SaiSwitch class object must be created before before any other
* object, so when doing discover we will get full default ASIC view.
*/
m_sw = std::make_shared<SaiSwitch>(m_switch_vid, m_switch_rid, m_client, m_translator, m_vendorSai);
/*
* We processed switch. We have switch vid/rid so we can process all
* other attributes of switches that are not mandatory on create and are
* not crate only.
*
* Since those left attributes may contain VIDs we need to process
* attributes for oids.
*/
processAttributesForOids(SAI_OBJECT_TYPE_SWITCH, attr_count_left, attrs_left.data());
for (uint32_t idx = 0; idx < attr_count_left; ++idx)
{
sai_attribute_t *attr = &attrs_left[idx];
status = m_vendorSai->set(SAI_OBJECT_TYPE_SWITCH, m_switch_rid, attr);
if (status != SAI_STATUS_SUCCESS)
{
if (Workaround::isSetAttributeWorkaround(SAI_OBJECT_TYPE_SWITCH, attr->id, status))
{
continue;
}
SWSS_LOG_THROW("failed to set attribute %s on switch VID %s: %s",
sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_SWITCH, attr->id)->attridname,
sai_serialize_object_id(m_switch_rid).c_str(),
sai_serialize_status(status).c_str());
}
}
}
}
void SingleReiniter::processFdbs()
{
SWSS_LOG_ENTER();
for (auto &kv: m_fdbs)
{
const std::string &strFdbEntry = kv.first;
const std::string &asicKey = kv.second;
sai_object_meta_key_t meta_key;
meta_key.objecttype = SAI_OBJECT_TYPE_FDB_ENTRY;
sai_deserialize_fdb_entry(strFdbEntry, meta_key.objectkey.key.fdb_entry);
processStructNonObjectIds(meta_key);
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(SAI_OBJECT_TYPE_FDB_ENTRY, attrCount, attrList);
sai_status_t status = m_vendorSai->create(&meta_key.objectkey.key.fdb_entry, attrCount, attrList);
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(SAI_OBJECT_TYPE_FDB_ENTRY, attrCount, attrList);
SWSS_LOG_THROW("failed to create_fdb_entry %s: %s",
strFdbEntry.c_str(),
sai_serialize_status(status).c_str());
}
}
}
void SingleReiniter::processNeighbors()
{
SWSS_LOG_ENTER();
for (auto &kv: m_neighbors)
{
const std::string &strNeighborEntry = kv.first;
const std::string &asicKey = kv.second;
sai_object_meta_key_t meta_key;
meta_key.objecttype = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY;
sai_deserialize_neighbor_entry(strNeighborEntry, meta_key.objectkey.key.neighbor_entry);
processStructNonObjectIds(meta_key);
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, attrCount, attrList);
sai_status_t status = m_vendorSai->create(&meta_key.objectkey.key.neighbor_entry, attrCount, attrList);
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, attrCount, attrList);
SWSS_LOG_THROW("failed to create_neighbor_entry %s: %s",
strNeighborEntry.c_str(),
sai_serialize_status(status).c_str());
}
}
}
void SingleReiniter::processRoutes(
_In_ bool defaultOnly)
{
SWSS_LOG_ENTER();
SWSS_LOG_TIMER("apply routes");
for (auto &kv: m_routes)
{
const std::string &strRouteEntry = kv.first;
const std::string &asicKey = kv.second;
bool isDefault = strRouteEntry.find("/0") != std::string::npos;
if (defaultOnly ^ isDefault)
{
/*
* Since there is a requirement in brcm that default route needs to
* be put first in the asic, then we execute default routes first
* and then other routes.
*/
continue;
}
sai_object_meta_key_t meta_key;
meta_key.objecttype = SAI_OBJECT_TYPE_ROUTE_ENTRY;
sai_deserialize_route_entry(strRouteEntry, meta_key.objectkey.key.route_entry);
processStructNonObjectIds(meta_key);
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(SAI_OBJECT_TYPE_ROUTE_ENTRY, attrCount, attrList);
sai_status_t status = m_vendorSai->create(&meta_key.objectkey.key.route_entry, attrCount, attrList);
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(SAI_OBJECT_TYPE_ROUTE_ENTRY, attrCount, attrList);
SWSS_LOG_ERROR("translated route: %s",
sai_serialize_route_entry(meta_key.objectkey.key.route_entry).c_str());
SWSS_LOG_THROW(
"failed to create ROUTE %s: %s",
strRouteEntry.c_str(),
sai_serialize_status(status).c_str());
}
}
}
void SingleReiniter::processInsegs()
{
SWSS_LOG_ENTER();
for (auto &kv: m_insegs)
{
const std::string &strInsegEntry = kv.first;
const std::string &asicKey = kv.second;
sai_object_meta_key_t meta_key;
meta_key.objecttype = SAI_OBJECT_TYPE_INSEG_ENTRY;
sai_deserialize_inseg_entry(strInsegEntry, meta_key.objectkey.key.inseg_entry);
processStructNonObjectIds(meta_key);
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(SAI_OBJECT_TYPE_INSEG_ENTRY, attrCount, attrList);
sai_status_t status = sai_metadata_sai_mpls_api->
create_inseg_entry(&meta_key.objectkey.key.inseg_entry, attrCount, attrList);
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(SAI_OBJECT_TYPE_INSEG_ENTRY, attrCount, attrList);
SWSS_LOG_THROW("failed to create_inseg_entry %s: %s",
strInsegEntry.c_str(),
sai_serialize_status(status).c_str());
}
}
}
void SingleReiniter::processNatEntries()
{
SWSS_LOG_ENTER();
for (auto &kv: m_nats)
{
const std::string &strNatEntry = kv.first;
const std::string &asicKey = kv.second;
sai_object_meta_key_t meta_key;
meta_key.objecttype = SAI_OBJECT_TYPE_NAT_ENTRY;
sai_deserialize_nat_entry(strNatEntry, meta_key.objectkey.key.nat_entry);
processStructNonObjectIds(meta_key);
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(SAI_OBJECT_TYPE_NAT_ENTRY, attrCount, attrList);
sai_status_t status = m_vendorSai->create(&meta_key.objectkey.key.nat_entry, attrCount, attrList);
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(SAI_OBJECT_TYPE_NAT_ENTRY, attrCount, attrList);
SWSS_LOG_THROW("failed to create_nat_entry %s: %s",
strNatEntry.c_str(),
sai_serialize_status(status).c_str());
}
}
}
void SingleReiniter::trapGroupWorkaround(
_In_ sai_object_id_t vid,
_Inout_ sai_object_id_t& rid,
_In_ bool& createObject,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t* attrList)
{
SWSS_LOG_ENTER();
if (createObject)
{
/*
* There is a bug on brcm that create trap group with queue attribute
* will fail, but it can be set after create without this attribute, so
* we will here create tap group and set it later.
*
* This needs to be fixed by brcm.
*/
createObject = false; // force to "SET" left attributes
}
else
{
// default trap group or existing trap group
return;
}
sai_object_type_t objectType = SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP;
SWSS_LOG_INFO("creating trap group and setting attributes 1 by 1 as workaround");
const sai_attribute_t* queue_attr = sai_metadata_get_attr_by_id(SAI_HOSTIF_TRAP_GROUP_ATTR_QUEUE, attrCount, attrList);
if (queue_attr == NULL)
{
SWSS_LOG_THROW("missing QUEUE attribute on TRAP_GROUP creation even if it's not MANDATORY");
}
sai_status_t status = m_vendorSai->create(SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP, &rid, m_switch_rid, 1, queue_attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_THROW("failed to create TRAP_GROUP %s",
sai_serialize_status(status).c_str());
}
SWSS_LOG_DEBUG("created TRAP_GROUP (%s), processed VID %s to RID %s",
sai_serialize_object_type(objectType).c_str(),
sai_serialize_object_id(vid).c_str(),
sai_serialize_object_id(rid).c_str());
}
void SingleReiniter::listFailedAttributes(
_In_ sai_object_type_t objectType,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t* attrList)
{
SWSS_LOG_ENTER();
for (uint32_t idx = 0; idx < attrCount; idx++)
{
const sai_attribute_t *attr = &attrList[idx];
auto meta = sai_metadata_get_attr_metadata(objectType, attr->id);
if (meta == NULL)
{
SWSS_LOG_ERROR("failed to get attribute metadata %s %d",
sai_serialize_object_type(objectType).c_str(),
attr->id);
continue;
}
SWSS_LOG_ERROR("%s = %s", meta->attridname, sai_serialize_attr_value(*meta, *attr).c_str());
}
}
sai_object_id_t SingleReiniter::processSingleVid(
_In_ sai_object_id_t vid)
{
SWSS_LOG_ENTER();
if (vid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_DEBUG("processed VID 0 to RID 0");
return SAI_NULL_OBJECT_ID;
}
auto it = m_translatedV2R.find(vid);
if (it != m_translatedV2R.end())
{
/*
* This object was already processed, just return real object id.
*/
SWSS_LOG_DEBUG("processed VID %s to RID %s",
sai_serialize_object_id(vid).c_str(),
sai_serialize_object_id(it->second).c_str());
return it->second;
}
sai_object_type_t objectType = VidManager::objectTypeQuery(vid);
std::string strVid = sai_serialize_object_id(vid);
auto oit = m_oids.find(strVid);
if (oit == m_oids.end())
{
SWSS_LOG_THROW("failed to find VID %s in OIDs map", strVid.c_str());
}
std::string asicKey = oit->second;;
std::shared_ptr<SaiAttributeList> list = m_attributesLists[asicKey];
sai_attribute_t *attrList = list->get_attr_list();
uint32_t attrCount = list->get_attr_count();
processAttributesForOids(objectType, attrCount, attrList);
bool createObject = true;
/*
* Now let's determine whether this object need to be created. Default
* objects like default virtual router, queues or cpu can't be created.
* When object exists on the switch (even VLAN member) it will not be
* created, but matched. We just need to watch for RO/CO attributes.
*
* NOTE: this also should be per switch.
*/
auto v2rMapIt = m_vidToRidMap.find(vid);
if (v2rMapIt == m_vidToRidMap.end())
{
SWSS_LOG_THROW("failed to find VID %s in VIDTORID map",
sai_serialize_object_id(vid).c_str());
}
sai_object_id_t rid;
if (m_sw->isDiscoveredRid(v2rMapIt->second))
{
rid = v2rMapIt->second;
createObject = false;
SWSS_LOG_DEBUG("object %s will not be created, processed VID %s to RID %s",
sai_serialize_object_type(objectType).c_str(),
sai_serialize_object_id(vid).c_str(),
sai_serialize_object_id(rid).c_str());
}
if (objectType == SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP)
{
/*
* We need special case for trap group, look inside for details.
*/
trapGroupWorkaround(vid, rid, createObject, attrCount, attrList);
}
if (createObject)
{
sai_object_meta_key_t meta_key;
meta_key.objecttype = objectType;
/*
* Since we have only one switch, we can get away using m_switch_rid here.
*/
#ifdef ENABLE_PERF
auto start = std::chrono::high_resolution_clock::now();
#endif
sai_status_t status = m_vendorSai->create(meta_key.objecttype, &meta_key.objectkey.key.object_id, m_switch_rid, attrCount, attrList);
#ifdef ENABLE_PERF
auto end = std::chrono::high_resolution_clock::now();
typedef std::chrono::duration<double, std::ratio<1>> second_t;
double duration = std::chrono::duration_cast<second_t>(end - start).count();
std::get<0>(m_perf_create[objectType])++;
std::get<1>(m_perf_create[objectType]) += duration;
#endif
if (status != SAI_STATUS_SUCCESS)
{
listFailedAttributes(objectType, attrCount, attrList);
SWSS_LOG_THROW("failed to create object %s: %s",
sai_serialize_object_type(objectType).c_str(),
sai_serialize_status(status).c_str());
}
rid = meta_key.objectkey.key.object_id;
SWSS_LOG_DEBUG("created object of type %s, processed VID %s to RID %s",
sai_serialize_object_type(objectType).c_str(),
sai_serialize_object_id(vid).c_str(),
sai_serialize_object_id(rid).c_str());
}
else
{
SWSS_LOG_DEBUG("setting attributes on object of type %x, processed VID 0x%" PRIx64 " to RID 0x%" PRIx64 " ", objectType, vid, rid);
for (uint32_t idx = 0; idx < attrCount; idx++)
{
sai_attribute_t *attr = &attrList[idx];
sai_object_meta_key_t meta_key;
meta_key.objecttype = objectType;
meta_key.objectkey.key.object_id = rid;
auto meta = sai_metadata_get_attr_metadata(objectType, attr->id);
if (meta == NULL)
{
SWSS_LOG_THROW("failed to get attribute metadata %s: %d",
sai_serialize_object_type(objectType).c_str(),
attr->id);
}
// XXX workaround
if (meta->objecttype == SAI_OBJECT_TYPE_SWITCH &&
attr->id == SAI_SWITCH_ATTR_SRC_MAC_ADDRESS)
{
SWSS_LOG_WARN("skipping to set MAC address since not supported on Mellanox platforms");
continue;
}
if (SAI_HAS_FLAG_CREATE_ONLY(meta->flags))
{
/*
* If we will be performing this on default existing created
* object then it may happen that during snoop in previous
* iteration we put some attribute that is create only, then
* this set will fail and we need to skip this set.
*
* NOTE: We could do get here to see if it actually matches.
*/
if (m_sw->isDiscoveredRid(rid))
{
continue;
}
SWSS_LOG_WARN("skipping create only attr %s: %s",
meta->attridname,
sai_serialize_attr_value(*meta, *attr).c_str());
continue;
}
#ifdef ENABLE_PERF
auto start = std::chrono::high_resolution_clock::now();
#endif
sai_status_t status = m_vendorSai->set(meta_key.objecttype, meta_key.objectkey.key.object_id, attr);
#ifdef ENABLE_PERF
auto end = std::chrono::high_resolution_clock::now();
typedef std::chrono::duration<double, std::ratio<1>> second_t;
double duration = std::chrono::duration_cast<second_t>(end - start).count();
std::get<0>(m_perf_set[objectType])++;
std::get<1>(m_perf_set[objectType]) += duration;
#endif
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_THROW(
"failed to set %s value %s: %s",
meta->attridname,
sai_serialize_attr_value(*meta, *attr).c_str(),
sai_serialize_status(status).c_str());
}
}
}
m_translatedV2R[vid] = rid;
m_translatedR2V[rid] = vid;
return rid;
}
void SingleReiniter::processAttributesForOids(
_In_ sai_object_type_t objectType,
_In_ uint32_t attr_count,
_In_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
SWSS_LOG_DEBUG("processing list for object type %s",
sai_serialize_object_type(objectType).c_str());
for (uint32_t idx = 0; idx < attr_count; idx++)
{
sai_attribute_t &attr = attr_list[idx];
auto meta = sai_metadata_get_attr_metadata(objectType, attr.id);
if (meta == NULL)
{
SWSS_LOG_THROW("unable to get metadata for object type %s, attribute %d",
sai_serialize_object_type(objectType).c_str(),
attr.id);
}
uint32_t count = 0;
sai_object_id_t *objectIdList;
switch (meta->attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
count = 1;
objectIdList = &attr.value.oid;
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
count = attr.value.objlist.count;
objectIdList = attr.value.objlist.list;
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (attr.value.aclfield.enable)
{
count = 1;
objectIdList = &attr.value.aclfield.data.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (attr.value.aclfield.enable)
{
count = attr.value.aclfield.data.objlist.count;
objectIdList = attr.value.aclfield.data.objlist.list;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (attr.value.aclaction.enable)
{
count = 1;
objectIdList = &attr.value.aclaction.parameter.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (attr.value.aclaction.enable)
{
count = attr.value.aclaction.parameter.objlist.count;
objectIdList = attr.value.aclaction.parameter.objlist.list;
}
break;
default:
// TODO later isoidattribute
if (meta->allowedobjecttypeslength > 0)
{
SWSS_LOG_THROW("attribute %s is oid attribute, but not processed, FIXME", meta->attridname);
}
/*
* This is not oid attribute, we can skip processing.
*/
continue;
}
/*
* Attribute contains object id's, they need to be translated some of
* them could be already translated.
*/
for (uint32_t j = 0; j < count; j++)
{
sai_object_id_t vid = objectIdList[j];
sai_object_id_t rid = processSingleVid(vid);
objectIdList[j] = rid;
}
}
}
void SingleReiniter::processOids()
{
SWSS_LOG_ENTER();
for (const auto &kv: m_oids)
{
const std::string &strObjectId = kv.first;
sai_object_id_t vid;
sai_deserialize_object_id(strObjectId, vid);
processSingleVid(vid);
}
}
void SingleReiniter::processStructNonObjectIds(
_In_ sai_object_meta_key_t &meta_key)
{
SWSS_LOG_ENTER();
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
/*
* Call processSingleVid method for each oid in non object id (struct
* entry) in generic way.
*/
if (info->isnonobjectid)
{
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
sai_object_id_t vid = m->getoid(&meta_key);
sai_object_id_t rid = processSingleVid(vid);
m->setoid(&meta_key, rid);
SWSS_LOG_DEBUG("processed vid 0x%" PRIx64 " to rid 0x%" PRIx64 " in %s:%s", vid, rid,
info->objecttypename,
m->membername);
}
}
}
void SingleReiniter::checkAllIds()
{
SWSS_LOG_ENTER();
for (auto &kv: m_translatedV2R)
{
auto it = m_vidToRidMap.find(kv.first);
if (it == m_vidToRidMap.end())
{
SWSS_LOG_THROW("failed to find vid %s in previous map",
sai_serialize_object_id(kv.first).c_str());
}
m_vidToRidMap.erase(it);
}
size_t size = m_vidToRidMap.size();
if (size != 0)
{
for (auto &kv: m_vidToRidMap)
{
sai_object_type_t objectType = VidManager::objectTypeQuery(kv.first);
SWSS_LOG_ERROR("vid not translated: %s, object type: %s",
sai_serialize_object_id(kv.first).c_str(),
sai_serialize_object_type(objectType).c_str());
}
SWSS_LOG_THROW("vid to rid map is not empty (%zu) after translation", size);
}
}
SingleReiniter::ObjectIdMap SingleReiniter::getTranslatedVid2Rid() const
{
SWSS_LOG_ENTER();
return m_translatedV2R;
}
void SingleReiniter::postRemoveActions()
{
SWSS_LOG_ENTER();
/*
* Now we must check whether we need to remove some objects like VLAN
* members etc.
*
* TODO: Should this be done at start, before other operations?
* We are able to determine which objects are missing from rid map
* as long as id's between restart don't change.
*/
if (m_sw == nullptr)
{
/*
* No switch was created.
*/
return;
}
/*
* We can have situation here, that some objects were removed but they
* still exists in default map, like vlan members, and this will introduce
* inconsistency redis vs defaults. This will be ok since switch will not
* hold all id's, it only will hold defaults. But this swill mean, that we
* need to remove those VLAN members from ASIC.
*
* We could just call discover again, but that's too long, we just need to
* remove removed objects since we need Existing objects for ApplyView.
*
* Order matters here, we can't remove bridge before removing all bridge
* ports etc. We would need to use dependency tree to do it in order.
* But since we will only remove default objects we can try
*
* 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,
SAI_OBJECT_TYPE_NULL };
for (sai_object_type_t ot: removeOrder)
{
for (sai_object_id_t rid: m_sw->getDiscoveredRids())
{
if (m_translatedR2V.find(rid) != m_translatedR2V.end())
{
continue;
}
if (ot == m_vendorSai->objectTypeQuery(rid) ||
ot == SAI_OBJECT_TYPE_NULL)
{
m_sw->removeExistingObject(rid);
/*
* If removing existing object, also make sure we remove it
* from COLDVIDS map since this object will no longer exists.
*/
if (m_ridToVidMap.find(rid) == m_ridToVidMap.end())
continue;
auto vid = m_ridToVidMap.at(rid);
SWSS_LOG_INFO("removing existing cold VID: %s",
sai_serialize_object_id(vid).c_str());
m_client->removeColdVid(vid);
}
}
}
}
std::shared_ptr<SaiAttributeList> SingleReiniter::redisGetAttributesFromAsicKey(
_In_ const std::string &key)
{
SWSS_LOG_ENTER();
sai_object_type_t objectType = getObjectTypeFromAsicKey(key);
std::vector<swss::FieldValueTuple> values;
auto hash = m_client->getAttributesFromAsicKey(key);
for (auto &kv: hash)
{
const std::string &skey = kv.first;
const std::string &svalue = kv.second;
swss::FieldValueTuple fvt(skey, svalue);
values.push_back(fvt);
}
return std::make_shared<SaiAttributeList>(objectType, values, false);
}
std::shared_ptr<SaiSwitch> SingleReiniter::getSwitch() const
{
SWSS_LOG_ENTER();
return m_sw;
}