vslib/SwitchStateBase.cpp (2,812 lines of code) (raw):

#include "SwitchStateBase.h" #include "swss/logger.h" #include "meta/sai_serialize.h" #include <net/if.h> #include <unistd.h> #include <algorithm> #define SAI_VS_MAX_PORTS 1024 using namespace saivs; SwitchStateBase::SwitchStateBase( _In_ sai_object_id_t switch_id, _In_ std::shared_ptr<RealObjectIdManager> manager, _In_ std::shared_ptr<SwitchConfig> config): SwitchState(switch_id, config), m_realObjectIdManager(manager) { SWSS_LOG_ENTER(); m_macsecManager.cleanup_macsec_device(); } SwitchStateBase::SwitchStateBase( _In_ sai_object_id_t switch_id, _In_ std::shared_ptr<RealObjectIdManager> manager, _In_ std::shared_ptr<SwitchConfig> config, _In_ std::shared_ptr<WarmBootState> warmBootState): SwitchState(switch_id, config), m_realObjectIdManager(manager) { SWSS_LOG_ENTER(); m_macsecManager.cleanup_macsec_device(); if (warmBootState) { for (auto& kvp: warmBootState->m_objectHash) { // we write only existing ones, since base constructor // created empty entries for non existing object types m_objectHash[kvp.first] = kvp.second; } if (m_switchConfig->m_useTapDevice) { m_fdb_info_set = warmBootState->m_fdbInfoSet; // TODO populate m_hostif_info_map - need to be able to remove port after warm boot // should be auto populated vs_recreate_hostif_tap_interfaces on create_switch } } } SwitchStateBase::~SwitchStateBase() { SWSS_LOG_ENTER(); m_macsecManager.cleanup_macsec_device(); } sai_status_t SwitchStateBase::create( _In_ sai_object_type_t object_type, _Out_ sai_object_id_t *object_id, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); if (object_type == SAI_OBJECT_TYPE_SWITCH) { SWSS_LOG_THROW("this method can't be used to create switch"); } *object_id = m_realObjectIdManager->allocateNewObjectId(object_type, switch_id); auto sid = sai_serialize_object_id(*object_id); return create_internal(object_type, sid, switch_id, attr_count, attr_list); } uint32_t SwitchStateBase::getNewDebugCounterIndex() { SWSS_LOG_ENTER(); for (uint32_t i = 0; i < maxDebugCounters; i++) { if (m_indices.find(i) == m_indices.end()) { m_indices.insert(i); return i; } } return UINT32_MAX; } sai_status_t SwitchStateBase::createDebugCounter( _In_ sai_object_id_t object_id, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); auto index = getNewDebugCounterIndex(); if (index > maxDebugCounters) { SWSS_LOG_ERROR("Cannot create more than %d debug counters", maxDebugCounters); return SAI_STATUS_FAILURE; } auto sid = sai_serialize_object_id(object_id); CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_DEBUG_COUNTER, sid, switch_id, attr_count, attr_list)); sai_attribute_t attr; attr.id = SAI_DEBUG_COUNTER_ATTR_INDEX; attr.value.u32 = index; return set(SAI_OBJECT_TYPE_DEBUG_COUNTER, sid, &attr); } sai_status_t SwitchStateBase::create( _In_ sai_object_type_t object_type, _In_ const std::string &serializedObjectId, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); if (object_type == SAI_OBJECT_TYPE_DEBUG_COUNTER) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createDebugCounter(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_PORT) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createPort(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_HOSTIF) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createHostif(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_MACSEC_PORT) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createMACsecPort(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_MACSEC_SC) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createMACsecSC(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_MACSEC_SA) { sai_object_id_t object_id; sai_deserialize_object_id(serializedObjectId, object_id); return createMACsecSA(object_id, switch_id, attr_count, attr_list); } if (object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY && m_system_port_list.size()) { // Neighbor entry programming for VOQ systems return createVoqSystemNeighborEntry(serializedObjectId, switch_id, attr_count, attr_list); } return create_internal(object_type, serializedObjectId, switch_id, attr_count, attr_list); } sai_status_t SwitchStateBase::create_internal( _In_ sai_object_type_t object_type, _In_ const std::string &serializedObjectId, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); auto &objectHash = m_objectHash.at(object_type); if (m_switchConfig->m_resourceLimiter) { size_t limit = m_switchConfig->m_resourceLimiter->getObjectTypeLimit(object_type); if (objectHash.size() >= limit) { SWSS_LOG_ERROR("too many %s, created %zu is resource limit", sai_serialize_object_type(object_type).c_str(), limit); return SAI_STATUS_INSUFFICIENT_RESOURCES; } } auto it = objectHash.find(serializedObjectId); if (object_type != SAI_OBJECT_TYPE_SWITCH) { /* * Switch is special, and object is already created by init. * * XXX revisit this. */ if (it != objectHash.end()) { SWSS_LOG_ERROR("create failed, object already exists, object type: %s: id: %s", sai_serialize_object_type(object_type).c_str(), serializedObjectId.c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } } if (objectHash.find(serializedObjectId) == objectHash.end()) { /* * Number of attributes may be zero, so see if actual entry was created * with empty hash. */ objectHash[serializedObjectId] = {}; } for (uint32_t i = 0; i < attr_count; ++i) { auto a = std::make_shared<SaiAttrWrap>(object_type, &attr_list[i]); objectHash[serializedObjectId][a->getAttrMetadata()->attridname] = a; } return SAI_STATUS_SUCCESS; } void SwitchStateBase::releaseDebugCounterIndex( _In_ uint32_t index) { SWSS_LOG_ENTER(); m_indices.erase(index); } sai_status_t SwitchStateBase::remove( _In_ sai_object_type_t object_type, _In_ sai_object_id_t objectId) { SWSS_LOG_ENTER(); auto sid = sai_serialize_object_id(objectId); return remove(object_type, sid); } sai_status_t SwitchStateBase::removeDebugCounter( _In_ sai_object_id_t objectId) { SWSS_LOG_ENTER(); sai_attribute_t attr; attr.id = SAI_DEBUG_COUNTER_ATTR_INDEX; CHECK_STATUS(get(SAI_OBJECT_TYPE_DEBUG_COUNTER, objectId, 1, &attr)); auto sid = sai_serialize_object_id(objectId); CHECK_STATUS(remove_internal(SAI_OBJECT_TYPE_DEBUG_COUNTER, sid)); releaseDebugCounterIndex(attr.value.u32); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::createPort( _In_ sai_object_id_t object_id, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); auto sid = sai_serialize_object_id(object_id); CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_PORT, sid, switch_id, attr_count, attr_list)); return create_port_dependencies(object_id); } sai_status_t SwitchStateBase::removePort( _In_ sai_object_id_t objectId) { SWSS_LOG_ENTER(); if (!isPortReadyToBeRemove(objectId)) { SWSS_LOG_ERROR("port %s still have some active dependencies, can't remove", sai_serialize_object_id(objectId).c_str()); return SAI_STATUS_OBJECT_IN_USE; } auto dep = getPortDependencies(objectId); auto sid = sai_serialize_object_id(objectId); CHECK_STATUS(remove_internal(SAI_OBJECT_TYPE_PORT, sid)); SWSS_LOG_NOTICE("port %s was successfully removed, removing depending objects now", sai_serialize_object_id(objectId).c_str()); for (auto oid: dep) { // meta_sai_remove_oid automatically removed related oids internally // so we just need to execute remove for virtual switch db auto status = remove(objectTypeQuery(oid), oid); if (status != SAI_STATUS_SUCCESS) { // we can't continue, there is a bug somewhere if we can't remove // port related objects: queues, ipgs, sg SWSS_LOG_THROW("FATAL: failed to removed port related oid: %s: %s, bug!", sai_serialize_object_type(objectTypeQuery(oid)).c_str(), sai_serialize_object_id(oid).c_str()); } } SWSS_LOG_NOTICE("successfully removed all %zu port related objects", dep.size()); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::remove( _In_ sai_object_type_t object_type, _In_ const std::string &serializedObjectId) { SWSS_LOG_ENTER(); if (object_type == SAI_OBJECT_TYPE_DEBUG_COUNTER) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removeDebugCounter(objectId); } if (object_type == SAI_OBJECT_TYPE_PORT) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removePort(objectId); } if (object_type == SAI_OBJECT_TYPE_HOSTIF) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removeHostif(objectId); } if (object_type == SAI_OBJECT_TYPE_MACSEC_PORT) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removeMACsecPort(objectId); } else if (object_type == SAI_OBJECT_TYPE_MACSEC_SC) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removeMACsecSC(objectId); } else if (object_type == SAI_OBJECT_TYPE_MACSEC_SA) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return removeMACsecSA(objectId); } return remove_internal(object_type, serializedObjectId); } sai_status_t SwitchStateBase::remove_internal( _In_ sai_object_type_t object_type, _In_ const std::string &serializedObjectId) { SWSS_LOG_ENTER(); SWSS_LOG_INFO("removing object: %s", serializedObjectId.c_str()); auto &objectHash = m_objectHash.at(object_type); auto it = objectHash.find(serializedObjectId); if (it == objectHash.end()) { SWSS_LOG_ERROR("not found %s:%s", sai_serialize_object_type(object_type).c_str(), serializedObjectId.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } objectHash.erase(it); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::setPort( _In_ sai_object_id_t portId, _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); if (attr && attr->id == SAI_PORT_ATTR_ADMIN_STATE && m_switchConfig->m_useTapDevice) { bool up = attr->value.booldata; // find corresponding host if interface and bring it down ! for (auto& kvp: m_hostif_info_map) { auto tapname = kvp.first; if (kvp.second->m_portId == portId) { std::string vethname = vs_get_veth_name(tapname, portId); if (ifup(vethname.c_str(), portId, up, false)) { SWSS_LOG_ERROR("if admin %s failed on %s failed: %s", (up ? "UP" : "DOWN"), vethname.c_str(), strerror(errno)); return SAI_STATUS_FAILURE; } SWSS_LOG_NOTICE("if admin %s success on %s", (up ? "UP" : "DOWN"), vethname.c_str()); break; } } } else if (attr && attr->id == SAI_PORT_ATTR_MTU && m_switchConfig->m_useTapDevice) { uint32_t mtu = attr->value.u32; std::string name; if (getTapNameFromPortId(portId, name)) { SWSS_LOG_INFO("setting new MTU: %d on %s", mtu, name.c_str()); std::string vname = vs_get_veth_name(name, portId); if (vs_set_dev_mtu(vname.c_str(), mtu) < 0) { SWSS_LOG_ERROR("failed to set MTU on portId %s", sai_serialize_object_id(portId).c_str()); return SAI_STATUS_FAILURE; } } } auto sid = sai_serialize_object_id(portId); return set_internal(SAI_OBJECT_TYPE_PORT, sid, attr); } sai_status_t SwitchStateBase::setAclEntry( _In_ sai_object_id_t entry_id, _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); if (attr && attr->id == SAI_ACL_ENTRY_ATTR_ACTION_MACSEC_FLOW) { return setAclEntryMACsecFlowActive(entry_id, attr); } auto sid = sai_serialize_object_id(entry_id); return set_internal(SAI_OBJECT_TYPE_ACL_ENTRY, sid, attr); } sai_status_t SwitchStateBase::set( _In_ sai_object_type_t objectType, _In_ const std::string &serializedObjectId, _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); if (objectType == SAI_OBJECT_TYPE_PORT) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return setPort(objectId, attr); } if (objectType == SAI_OBJECT_TYPE_ACL_ENTRY) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return setAclEntry(objectId, attr); } if (objectType == SAI_OBJECT_TYPE_MACSEC_SA) { sai_object_id_t objectId; sai_deserialize_object_id(serializedObjectId, objectId); return setMACsecSA(objectId, attr); } return set_internal(objectType, serializedObjectId, attr); } sai_status_t SwitchStateBase::set_internal( _In_ sai_object_type_t objectType, _In_ const std::string &serializedObjectId, _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); auto it = m_objectHash.at(objectType).find(serializedObjectId); if (it == m_objectHash.at(objectType).end()) { SWSS_LOG_ERROR("not found %s:%s", sai_serialize_object_type(objectType).c_str(), serializedObjectId.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } auto &attrHash = it->second; auto a = std::make_shared<SaiAttrWrap>(objectType, attr); // set have only one attribute attrHash[a->getAttrMetadata()->attridname] = a; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set( _In_ sai_object_type_t objectType, _In_ sai_object_id_t objectId, _In_ const sai_attribute_t* attr) { SWSS_LOG_ENTER(); auto sid = sai_serialize_object_id(objectId); return set(objectType, sid, attr); } sai_status_t SwitchStateBase::get( _In_ sai_object_type_t object_type, _In_ sai_object_id_t object_id, _In_ uint32_t attr_count, _Out_ sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); auto sid = sai_serialize_object_id(object_id); return get(object_type, sid, attr_count, attr_list); } sai_status_t SwitchStateBase::get( _In_ sai_object_type_t objectType, _In_ const std::string &serializedObjectId, _In_ uint32_t attr_count, _Out_ sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); const auto &objectHash = m_objectHash.at(objectType); auto it = objectHash.find(serializedObjectId); if (it == objectHash.end()) { SWSS_LOG_ERROR("not found %s:%s", sai_serialize_object_type(objectType).c_str(), serializedObjectId.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } /* * We need reference here since we can potentially update attr hash for RO * object. */ auto& attrHash = it->second; /* * Some of the list query maybe for length, so we can't do * normal serialize, maybe with count only. */ sai_status_t final_status = SAI_STATUS_SUCCESS; for (uint32_t idx = 0; idx < attr_count; ++idx) { sai_attr_id_t id = attr_list[idx].id; auto meta = sai_metadata_get_attr_metadata(objectType, id); if (meta == NULL) { SWSS_LOG_ERROR("failed to find attribute %d for %s:%s", id, sai_serialize_object_type(objectType).c_str(), serializedObjectId.c_str()); return SAI_STATUS_FAILURE; } sai_status_t status; if (SAI_HAS_FLAG_READ_ONLY(meta->flags)) { /* * Read only attributes may require recalculation. * Metadata makes sure that non object id's can't have * read only attributes. So here is definitely OID. */ sai_object_id_t oid; sai_deserialize_object_id(serializedObjectId, oid); status = refresh_read_only(meta, oid); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_INFO("%s read only not implemented on %s", meta->attridname, serializedObjectId.c_str()); return status; } } auto ait = attrHash.find(meta->attridname); if (ait == attrHash.end()) { SWSS_LOG_WARN("%s not implemented on %s", meta->attridname, serializedObjectId.c_str()); return SAI_STATUS_NOT_IMPLEMENTED; } auto attr = ait->second->getAttr(); status = transfer_attributes(objectType, 1, attr, &attr_list[idx], false); if (status == SAI_STATUS_BUFFER_OVERFLOW) { /* * This is considered partial success, since we get correct list * length. Note that other items ARE processes on the list. */ SWSS_LOG_NOTICE("BUFFER_OVERFLOW %s: %s", serializedObjectId.c_str(), meta->attridname); /* * We still continue processing other attributes for get as long as * we only will be getting buffer overflow error. */ final_status = status; continue; } if (status != SAI_STATUS_SUCCESS) { // all other errors SWSS_LOG_ERROR("get failed %s: %s: %s", serializedObjectId.c_str(), meta->attridname, sai_serialize_status(status).c_str()); return status; } } return final_status; } sai_status_t SwitchStateBase::bulkCreate( _In_ sai_object_id_t switch_id, _In_ sai_object_type_t object_type, _In_ const std::vector<std::string> &serialized_object_ids, _In_ const uint32_t *attr_count, _In_ const sai_attribute_t **attr_list, _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses) { SWSS_LOG_ENTER(); uint32_t object_count = (uint32_t) serialized_object_ids.size(); if (!object_count || !attr_count || !attr_list || !object_statuses) { SWSS_LOG_ERROR("Invalid arguments"); return SAI_STATUS_FAILURE; } sai_status_t status = SAI_STATUS_SUCCESS; uint32_t it; for (it = 0; it < object_count; it++) { object_statuses[it] = create(object_type, serialized_object_ids[it], switch_id, attr_count[it], attr_list[it]); if (object_statuses[it] != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create object with type = %u", object_type); status = SAI_STATUS_FAILURE; if (mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) { break; } } } while (++it < object_count) { object_statuses[it] = SAI_STATUS_NOT_EXECUTED; } return status; } sai_status_t SwitchStateBase::bulkRemove( _In_ sai_object_type_t object_type, _In_ const std::vector<std::string> &serialized_object_ids, _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses) { SWSS_LOG_ENTER(); uint32_t object_count = (uint32_t) serialized_object_ids.size(); if (!object_count || !object_statuses) { SWSS_LOG_ERROR("Invalid arguments"); return SAI_STATUS_FAILURE; } sai_status_t status = SAI_STATUS_SUCCESS; uint32_t it; for (it = 0; it < object_count; it++) { object_statuses[it] = remove(object_type, serialized_object_ids[it]); if (object_statuses[it] != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove object with type = %u", object_type); status = SAI_STATUS_FAILURE; if (mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) { break; } } } while (++it < object_count) { object_statuses[it] = SAI_STATUS_NOT_EXECUTED; } return status; } sai_status_t SwitchStateBase::bulkSet( _In_ sai_object_type_t object_type, _In_ const std::vector<std::string> &serialized_object_ids, _In_ const sai_attribute_t *attr_list, _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses) { SWSS_LOG_ENTER(); uint32_t object_count = (uint32_t) serialized_object_ids.size(); if (!object_count || !attr_list || !object_statuses) { SWSS_LOG_ERROR("Invalid arguments"); return SAI_STATUS_FAILURE; } sai_status_t status = SAI_STATUS_SUCCESS; uint32_t it; for (it = 0; it < object_count; it++) { object_statuses[it] = set_internal(object_type, serialized_object_ids[it], &attr_list[it]); if (object_statuses[it] != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set attribute for object with type = %u", object_type); status = SAI_STATUS_FAILURE; if (mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) { break; } } } while (++it < object_count) { object_statuses[it] = SAI_STATUS_NOT_EXECUTED; } return status; } sai_status_t SwitchStateBase::bulkGet( _In_ sai_object_type_t object_type, _In_ const std::vector<std::string> &serialized_object_ids, _In_ const uint32_t *attr_count, _Inout_ sai_attribute_t **attr_list, _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses) { SWSS_LOG_ENTER(); uint32_t it; uint32_t object_count = (uint32_t) serialized_object_ids.size(); sai_status_t status = SAI_STATUS_SUCCESS; if (!object_count || !attr_list || !attr_count || !object_statuses) { SWSS_LOG_ERROR("Invalid arguments"); return SAI_STATUS_FAILURE; } for (it = 0; it < object_count; it++) { if (!attr_list[it] || !attr_count[it]) { SWSS_LOG_ERROR("Invalid arguments"); return SAI_STATUS_FAILURE; } } for (it = 0; it < object_count; it++) { object_statuses[it] = get(object_type, serialized_object_ids[it], attr_count[it], attr_list[it]); if (object_statuses[it] != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to get attribute for object with type = %u", object_type); status = SAI_STATUS_FAILURE; if (mode == SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR) { break; } } } while (++it < object_count) { object_statuses[it] = SAI_STATUS_NOT_EXECUTED; } return status; } int SwitchStateBase::get_default_gw_mac_address( _Out_ sai_mac_t& mac) { SWSS_LOG_ENTER(); auto file = std::ifstream("/proc/net/route"); if (!file) { return -1; } std::string buf; while (std::getline(file, buf)) { char iface[IF_NAMESIZE]; long destination, gateway; if (std::sscanf(buf.c_str(), "%s %lx %lx", iface, &destination, &gateway) == 3) { if (destination == 0) { file = std::ifstream("/sys/class/net/" + std::string(iface) + "/address"); if ( !file ) { return -1; } file >> buf; return std::sscanf(buf.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6 ? 0 : -1; } } } return -1; } sai_status_t SwitchStateBase::set_switch_mac_address() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create switch src mac address"); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; if (get_default_gw_mac_address(attr.value.mac) < 0) { attr.value.mac[0] = 0x22; attr.value.mac[1] = 0x33; attr.value.mac[2] = 0x44; attr.value.mac[3] = 0x55; attr.value.mac[4] = 0x66; attr.value.mac[5] = 0x77; } return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::set_switch_supported_object_types() { SWSS_LOG_ENTER(); sai_attribute_t attr; // Fill this with supported SAI_OBJECT_TYPEs sai_object_type_t supported_obj_list[] = { SAI_OBJECT_TYPE_PORT, SAI_OBJECT_TYPE_LAG, SAI_OBJECT_TYPE_TAM, SAI_OBJECT_TYPE_TAM_COLLECTOR, SAI_OBJECT_TYPE_TAM_REPORT, SAI_OBJECT_TYPE_TAM_TRANSPORT, SAI_OBJECT_TYPE_TAM_TELEMETRY, SAI_OBJECT_TYPE_TAM_EVENT_THRESHOLD }; attr.id = SAI_SWITCH_ATTR_SUPPORTED_OBJECT_TYPE_LIST; attr.value.s32list.count = sizeof(supported_obj_list)/sizeof(sai_object_type_t); attr.value.s32list.list = (int32_t *) supported_obj_list; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::set_switch_default_attributes() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create switch default attributes"); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY; attr.value.ptr = NULL; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_BFD_SESSION_STATE_CHANGE_NOTIFY; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_FDB_AGING_TIME; attr.value.u32 = 0; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_RESTART_WARM; attr.value.booldata = false; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_TYPE; attr.value.s32 = SAI_SWITCH_TYPE_NPU; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_WARM_RECOVER; attr.value.booldata = false; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); return set_switch_supported_object_types(); } sai_status_t SwitchStateBase::create_default_hash() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default hash"); // Hash defaults according to SAI headers std::vector<sai_native_hash_field_t> hfList = { SAI_NATIVE_HASH_FIELD_DST_MAC, SAI_NATIVE_HASH_FIELD_SRC_MAC, SAI_NATIVE_HASH_FIELD_ETHERTYPE, SAI_NATIVE_HASH_FIELD_IN_PORT }; // create and populate default ecmp hash object sai_attribute_t attr; attr.id = SAI_HASH_ATTR_NATIVE_HASH_FIELD_LIST; attr.value.s32list.list = reinterpret_cast<sai_int32_t*>(hfList.data()); attr.value.s32list.count = static_cast<sai_uint32_t>(hfList.size()); CHECK_STATUS(create(SAI_OBJECT_TYPE_HASH, &m_ecmp_hash_id, m_switch_id, 1, &attr)); // set default ecmp hash on switch attr.id = SAI_SWITCH_ATTR_ECMP_HASH; attr.value.oid = m_ecmp_hash_id; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); // create and populate default lag hash object attr.id = SAI_HASH_ATTR_NATIVE_HASH_FIELD_LIST; attr.value.s32list.list = reinterpret_cast<sai_int32_t*>(hfList.data()); attr.value.s32list.count = static_cast<sai_uint32_t>(hfList.size()); CHECK_STATUS(create(SAI_OBJECT_TYPE_HASH, &m_lag_hash_id, m_switch_id, 1, &attr)); // set default lag hash on switch attr.id = SAI_SWITCH_ATTR_LAG_HASH; attr.value.oid = m_lag_hash_id; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::set_static_crm_values() { SWSS_LOG_ENTER(); std::map<sai_switch_attr_t, int> crm_resource_lookup = { { SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY, m_maxIPv4RouteEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY, m_maxIPv6RouteEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY, m_maxIPv4NextHopEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY, m_maxIPv6NextHopEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY, m_maxIPv4NeighborEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY, m_maxIPv6NeighborEntries }, { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY, m_maxNextHopGroupMemberEntries }, { SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY, m_maxNextHopGroupEntries }, { SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY, m_maxFdbEntries }, { SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY, m_maxSNATEntries }, { SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY, m_maxDNATEntries }, { SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY, m_maxIPMCEntries }, { SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY, m_maxDoubleNATEntries } }; for (auto const &resource: crm_resource_lookup) { sai_attribute_t attr; attr.id = resource.first; attr.value.u32 = resource.second; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); } CHECK_STATUS(set_static_acl_resource_list(SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE, m_maxAclTables)); return set_static_acl_resource_list(SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE_GROUP, m_maxAclTableGroups); } sai_status_t SwitchStateBase::set_static_acl_resource_list( _In_ sai_switch_attr_t acl_resource, _In_ int max_count) { SWSS_LOG_ENTER(); auto acl_stages = {SAI_ACL_STAGE_INGRESS, SAI_ACL_STAGE_EGRESS}; auto acl_bind_points = { SAI_ACL_BIND_POINT_TYPE_PORT, SAI_ACL_BIND_POINT_TYPE_LAG, SAI_ACL_BIND_POINT_TYPE_VLAN, SAI_ACL_BIND_POINT_TYPE_ROUTER_INTERFACE, SAI_ACL_BIND_POINT_TYPE_SWITCH }; std::vector<sai_acl_resource_t> acl_resource_list; for (auto stage: acl_stages) { for (auto bp: acl_bind_points) { sai_acl_resource_t acl_resource_count; acl_resource_count.stage = stage; acl_resource_count.bind_point = bp; acl_resource_count.avail_num = max_count; acl_resource_list.push_back(acl_resource_count); } } sai_acl_resource_list_t available_acl_resources; available_acl_resources.count = static_cast<uint32_t>(acl_resource_list.size()); available_acl_resources.list = acl_resource_list.data(); sai_attribute_t attr; attr.id = acl_resource; attr.value.aclresource = available_acl_resources; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_default_vlan() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default vlan"); sai_attribute_t attr; attr.id = SAI_VLAN_ATTR_VLAN_ID; attr.value.u16 = DEFAULT_VLAN_NUMBER; CHECK_STATUS(create(SAI_OBJECT_TYPE_VLAN, &m_default_vlan_id, m_switch_id, 1, &attr)); /* set default vlan on switch */ attr.id = SAI_SWITCH_ATTR_DEFAULT_VLAN_ID; attr.value.oid = m_default_vlan_id; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_cpu_port() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create cpu port"); sai_attribute_t attr; CHECK_STATUS(create(SAI_OBJECT_TYPE_PORT, &m_cpu_port_id, m_switch_id, 0, &attr)); // populate cpu port object on switch attr.id = SAI_SWITCH_ATTR_CPU_PORT; attr.value.oid = m_cpu_port_id; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); // set type on cpu attr.id = SAI_PORT_ATTR_TYPE; attr.value.s32 = SAI_PORT_TYPE_CPU; return set(SAI_OBJECT_TYPE_PORT, m_cpu_port_id, &attr); } sai_status_t SwitchStateBase::create_default_1q_bridge() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default 1q bridge"); sai_attribute_t attr; attr.id = SAI_BRIDGE_ATTR_TYPE; attr.value.s32 = SAI_BRIDGE_TYPE_1Q; CHECK_STATUS(create(SAI_OBJECT_TYPE_BRIDGE, &m_default_1q_bridge, m_switch_id, 1, &attr)); attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; attr.value.oid = m_default_1q_bridge; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_ports() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create ports"); auto map = m_switchConfig->m_laneMap; if (!map) { SWSS_LOG_ERROR("lane map for switch %s is NULL", sai_serialize_object_id(m_switch_id).c_str()); return SAI_STATUS_FAILURE; } auto lanesVector = map->getLaneVector(); if (m_switchConfig->m_useTapDevice) { SWSS_LOG_DEBUG("Check available lane"); CHECK_STATUS(filter_available_lanes(lanesVector)); } uint32_t port_count = (uint32_t)lanesVector.size(); m_port_list.clear(); for (uint32_t i = 0; i < port_count; i++) { SWSS_LOG_DEBUG("create port index %u", i); sai_object_id_t port_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_PORT, &port_id, m_switch_id, 0, NULL)); m_port_list.push_back(port_id); sai_attribute_t attr; attr.id = SAI_PORT_ATTR_ADMIN_STATE; attr.value.booldata = false; /* default admin state is down as defined in SAI */ CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_MTU; attr.value.u32 = 1514; /* default MTU is 1514 as defined in SAI */ CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_SPEED; attr.value.u32 = 40 * 1000; // TODO from config CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); std::vector<uint32_t> lanes = lanesVector.at(i); attr.id = SAI_PORT_ATTR_HW_LANE_LIST; attr.value.u32list.count = (uint32_t)lanes.size(); attr.value.u32list.list = lanes.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_TYPE; attr.value.s32 = SAI_PORT_TYPE_LOGICAL; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_OPER_STATUS; attr.value.s32 = SAI_PORT_OPER_STATUS_DOWN; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_PORT_VLAN_ID; attr.value.u32 = DEFAULT_VLAN_NUMBER; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_HOST_TX_READY_STATUS; attr.value.u32 = SAI_PORT_HOST_TX_READY_STATUS_READY; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_AUTO_NEG_MODE; attr.value.booldata = true; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set_port_list() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set port list"); // NOTE: this is static, but will be refreshed on read only get sai_attribute_t attr; uint32_t port_count = (uint32_t)m_port_list.size(); attr.id = SAI_SWITCH_ATTR_PORT_LIST; attr.value.objlist.count = port_count; attr.value.objlist.list = m_port_list.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_PORT_NUMBER; attr.value.u32 = port_count; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::set_port_capabilities() { SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("set port capabilities"); sai_attribute_t attr; for (auto &port_id: m_port_list) { attr.id = SAI_PORT_ATTR_SUPPORTED_AUTO_NEG_MODE; attr.value.booldata = true; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_default_virtual_router() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default virtual router"); sai_object_id_t virtual_router_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_VIRTUAL_ROUTER, &virtual_router_id, m_switch_id, 0, NULL)); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; attr.value.oid = virtual_router_id; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_default_stp_instance() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default stp instance"); sai_object_id_t stp_instance_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_STP, &stp_instance_id, m_switch_id, 0, NULL)); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_DEFAULT_STP_INST_ID; attr.value.oid = stp_instance_id; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_default_trap_group() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create default trap group"); sai_object_id_t trap_group_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP, &trap_group_id, m_switch_id, 0, NULL)); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP; attr.value.oid = trap_group_id; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_ingress_priority_groups_per_port( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); const uint32_t port_pgs_count = 8; // NOTE: must be per switch (mlnx and brcm is 8) std::vector<sai_object_id_t> pgs; for (uint32_t i = 0; i < port_pgs_count; ++i) { sai_object_id_t pg_id; sai_attribute_t attr[3]; // NOTE: on brcm this attribute is not added attr[0].id = SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE; attr[0].value.oid = SAI_NULL_OBJECT_ID; attr[1].id = SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT; attr[1].value.oid = port_id; attr[2].id = SAI_INGRESS_PRIORITY_GROUP_ATTR_INDEX; attr[2].value.oid = i; CHECK_STATUS(create(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, &pg_id, m_switch_id, 3, attr)); pgs.push_back(pg_id); } sai_attribute_t attr; attr.id = SAI_PORT_ATTR_NUMBER_OF_INGRESS_PRIORITY_GROUPS; attr.value.u32 = port_pgs_count; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST; attr.value.objlist.count = port_pgs_count; attr.value.objlist.list = pgs.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_ingress_priority_groups() { SWSS_LOG_ENTER(); // XXX priority groups size may change when we will modify pg or ports SWSS_LOG_INFO("create ingress priority groups"); for (auto &port_id: m_port_list) { create_ingress_priority_groups_per_port(port_id); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_vlan_members() { SWSS_LOG_ENTER(); // Crete vlan members for bridge ports. for (auto bridge_port_id: m_bridge_port_list_port_based) { SWSS_LOG_DEBUG("create vlan member for bridge port %s", sai_serialize_object_id(bridge_port_id).c_str()); sai_attribute_t attrs[3]; attrs[0].id = SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID; attrs[0].value.oid = bridge_port_id; attrs[1].id = SAI_VLAN_MEMBER_ATTR_VLAN_ID; attrs[1].value.oid = m_default_vlan_id; attrs[2].id = SAI_VLAN_MEMBER_ATTR_VLAN_TAGGING_MODE; attrs[2].value.s32 = SAI_VLAN_TAGGING_MODE_UNTAGGED; sai_object_id_t vlan_member_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_VLAN_MEMBER, &vlan_member_id, m_switch_id, 3, attrs)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_bridge_ports() { SWSS_LOG_ENTER(); // Create bridge port for 1q router. sai_attribute_t attr; attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; attr.value.s32 = SAI_BRIDGE_PORT_TYPE_1Q_ROUTER; CHECK_STATUS(create(SAI_OBJECT_TYPE_BRIDGE_PORT, &m_default_bridge_port_1q_router, m_switch_id, 1, &attr)); attr.id = SAI_BRIDGE_PORT_ATTR_PORT_ID; attr.value.oid = SAI_NULL_OBJECT_ID; CHECK_STATUS(set(SAI_OBJECT_TYPE_BRIDGE_PORT, m_default_bridge_port_1q_router, &attr)); // Create bridge ports for regular ports. m_bridge_port_list_port_based.clear(); for (const auto &port_id: m_port_list) { SWSS_LOG_DEBUG("create bridge port for port %s", sai_serialize_object_id(port_id).c_str()); sai_attribute_t attrs[4]; attrs[0].id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID; attrs[0].value.oid = m_default_1q_bridge; attrs[1].id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE; attrs[1].value.s32 = SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW; attrs[2].id = SAI_BRIDGE_PORT_ATTR_PORT_ID; attrs[2].value.oid = port_id; attrs[3].id = SAI_BRIDGE_PORT_ATTR_TYPE; attrs[3].value.s32 = SAI_BRIDGE_PORT_TYPE_PORT; sai_object_id_t bridge_port_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_BRIDGE_PORT, &bridge_port_id, m_switch_id, 4, attrs)); m_bridge_port_list_port_based.push_back(bridge_port_id); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set_acl_entry_min_prio() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set acl entry min prio"); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_ACL_ENTRY_MINIMUM_PRIORITY; attr.value.u32 = 1; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_ACL_ENTRY_MAXIMUM_PRIORITY; attr.value.u32 = 16000; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::set_acl_capabilities() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set acl capabilities"); sai_attribute_t attr; m_ingress_acl_action_list.clear(); m_egress_acl_action_list.clear(); for (int action_type = SAI_ACL_ENTRY_ATTR_ACTION_START; action_type <= SAI_ACL_ENTRY_ATTR_ACTION_END; action_type++) { m_ingress_acl_action_list.push_back(static_cast<sai_acl_action_type_t>(action_type - SAI_ACL_ENTRY_ATTR_ACTION_START)); m_egress_acl_action_list.push_back(static_cast<sai_acl_action_type_t>(action_type - SAI_ACL_ENTRY_ATTR_ACTION_START)); } attr.id = SAI_SWITCH_ATTR_MAX_ACL_ACTION_COUNT; attr.value.u32 = static_cast<uint32_t>(std::max(m_ingress_acl_action_list.size(), m_egress_acl_action_list.size())); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_ACL_STAGE_INGRESS; attr.value.aclcapability.is_action_list_mandatory = false; attr.value.aclcapability.action_list.list = reinterpret_cast<int32_t*>(m_ingress_acl_action_list.data()); attr.value.aclcapability.action_list.count = static_cast<uint32_t>(m_ingress_acl_action_list.size()); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_ACL_STAGE_EGRESS; attr.value.aclcapability.is_action_list_mandatory = false; attr.value.aclcapability.action_list.list = reinterpret_cast<int32_t*>(m_egress_acl_action_list.data()); attr.value.aclcapability.action_list.count = static_cast<uint32_t>(m_egress_acl_action_list.size()); return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_cpu_qos_queues( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_qos_queues_per_port( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_qos_queues() { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_scheduler_group_tree( _In_ const std::vector<sai_object_id_t>& sgs, _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_scheduler_groups_per_port( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_scheduler_groups() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create scheduler groups"); // XXX scheduler groups size may change when we will modify sg or ports for (auto &port_id: m_port_list) { CHECK_STATUS(create_scheduler_groups_per_port(port_id)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set_maximum_number_of_childs_per_scheduler_group() { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::set_number_of_ecmp_groups() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set number of ecmp groups"); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_NUMBER_OF_ECMP_GROUPS; attr.value.u32 = 512; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::create_port_serdes() { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::create_port_serdes_per_port( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::initialize_default_objects( _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); CHECK_STATUS(set_switch_mac_address()); CHECK_STATUS(create_cpu_port()); CHECK_STATUS(create_default_hash()); CHECK_STATUS(create_default_vlan()); CHECK_STATUS(create_default_virtual_router()); CHECK_STATUS(create_default_stp_instance()); CHECK_STATUS(create_default_1q_bridge()); CHECK_STATUS(create_default_trap_group()); CHECK_STATUS(create_ports()); CHECK_STATUS(create_port_serdes()); CHECK_STATUS(set_port_list()); CHECK_STATUS(set_port_capabilities()); CHECK_STATUS(create_bridge_ports()); CHECK_STATUS(create_vlan_members()); CHECK_STATUS(set_acl_entry_min_prio()); CHECK_STATUS(set_acl_capabilities()); CHECK_STATUS(create_ingress_priority_groups()); CHECK_STATUS(create_qos_queues()); CHECK_STATUS(set_maximum_number_of_childs_per_scheduler_group()); CHECK_STATUS(set_number_of_ecmp_groups()); CHECK_STATUS(set_switch_default_attributes()); CHECK_STATUS(create_scheduler_groups()); CHECK_STATUS(set_static_crm_values()); // Initialize switch for VOQ attributes CHECK_STATUS(initialize_voq_switch_objects(attr_count, attr_list)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_port_dependencies( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); // params are not needed since they were already set SWSS_LOG_WARN("check attributes and set, FIXME"); // this method is post create action on generic create object sai_attribute_t attr; // default admin state is down as defined in SAI attr.id = SAI_PORT_ATTR_ADMIN_STATE; attr.value.booldata = false; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_HOST_TX_READY_STATUS; attr.value.u32 = SAI_PORT_HOST_TX_READY_STATUS_READY; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); attr.id = SAI_PORT_ATTR_AUTO_NEG_MODE; attr.value.booldata = true; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); // attributes are not required since they will be set outside this function CHECK_STATUS(create_ingress_priority_groups_per_port(port_id)); CHECK_STATUS(create_qos_queues_per_port(port_id)); CHECK_STATUS(create_scheduler_groups_per_port(port_id)); CHECK_STATUS(create_port_serdes_per_port(port_id)); // XXX should bridge ports should also be created when new port is created? // this needs to be checked on real ASIC and updated here return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_ingress_priority_group( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); /* * TODO Currently we don't have index in groups, so we don't know how to * sort. Returning success, since assuming that we will not create more * ingress priority groups. */ return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_qos_queues( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); /* * TODO Currently we don't have index in groups, so we don't know how to * sort. Returning success, since assuming that we will not create more * ingress priority groups. */ return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_scheduler_groups( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); /* * TODO Currently we don't have index in groups, so we don't know how to * sort. Returning success, since assuming that we will not create more * ingress priority groups. */ return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::warm_boot_initialize_objects() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("warm boot init objects"); /* * We need to bring back previous state in case user will get some read * only attributes and recalculation will need to be done. * * We need to refresh: * - ports * - default bridge port 1q router */ m_port_list.resize(SAI_VS_MAX_PORTS); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_PORT_LIST; attr.value.objlist.count = SAI_VS_MAX_PORTS; attr.value.objlist.list = m_port_list.data(); CHECK_STATUS(get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr)); m_port_list.resize(attr.value.objlist.count); SWSS_LOG_NOTICE("port list size: %zu", m_port_list.size()); attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; CHECK_STATUS(get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr)); m_default_bridge_port_1q_router = attr.value.oid; SWSS_LOG_NOTICE("default bridge port 1q router: %s", sai_serialize_object_id(m_default_bridge_port_1q_router).c_str()); attr.id = SAI_SWITCH_ATTR_CPU_PORT; CHECK_STATUS(get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr)); m_cpu_port_id = attr.value.oid; SWSS_LOG_NOTICE("cpu port id: %s", sai_serialize_object_id(m_cpu_port_id).c_str()); // TODO refresh // // m_bridge_port_list_port_based; // m_default_1q_bridge; // m_default_vlan_id; // // other objects/numbers if added (per switch also) // TODO update // std::unordered_set<uint32_t> m_indices; // When booting from older virtual switch (eg. 201811) some attributes // could not be populated at that time, but they can be populated on master // (mostly default values of those attributes) so they will require manual // update after warm boot, for example: SAI_OBJECT_TYPE_QUEUE has no // attributes on 201811 branch but on master there are 3 attributes // populated SAI_QUEUE_ATTR_INDEX, PORT and TYPE. This could be per asic, // so those functions are virtual and could be overridden in child class. CHECK_STATUS(warm_update_queues()); CHECK_STATUS(warm_update_scheduler_groups()); CHECK_STATUS(warm_update_ingress_priority_groups()); CHECK_STATUS(warm_update_switch()); CHECK_STATUS(warm_update_cpu_queues()); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::warm_update_queues() { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::warm_update_scheduler_groups() { SWSS_LOG_ENTER(); for (auto port: m_port_list) { sai_attribute_t attr; std::vector<sai_object_id_t> list(MAX_OBJLIST_LEN); // get all scheduler list on current port attr.id = SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST; attr.value.objlist.count = MAX_OBJLIST_LEN; attr.value.objlist.list = list.data(); CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port , 1, &attr)); list.resize(attr.value.objlist.count); for (auto sg: list) { attr.id = SAI_SCHEDULER_GROUP_ATTR_PORT_ID; if (get(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, 1, &attr) != SAI_STATUS_SUCCESS) { attr.value.oid = port; CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr)); } } } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::warm_update_ingress_priority_groups() { SWSS_LOG_ENTER(); for (auto port: m_port_list) { sai_attribute_t attr; std::vector<sai_object_id_t> list(MAX_OBJLIST_LEN); // get all ingress priority groups list on current port attr.id = SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST; attr.value.objlist.count = MAX_OBJLIST_LEN; attr.value.objlist.list = list.data(); CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port , 1, &attr)); list.resize(attr.value.objlist.count); uint8_t index = 0; for (auto ipg: list) { attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT; if (get(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, 1, &attr) != SAI_STATUS_SUCCESS) { attr.value.oid = port; CHECK_STATUS(set(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, &attr)); } attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE; if (get(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, 1, &attr) != SAI_STATUS_SUCCESS) { attr.value.oid = SAI_NULL_OBJECT_ID; CHECK_STATUS(set(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, &attr)); } attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_INDEX; if (get(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, 1, &attr) != SAI_STATUS_SUCCESS) { attr.value.u8 = index; // warn, we are guessing index here if it was not defined CHECK_STATUS(set(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, ipg, &attr)); } index++; } } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::warm_update_switch() { SWSS_LOG_ENTER(); sai_attribute_t attr; // check for default available attributes attr.id = SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY; if (get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr) != SAI_STATUS_SUCCESS) { CHECK_STATUS(set_static_crm_values()) } // check for default switch type attr.id = SAI_SWITCH_ATTR_TYPE; if (get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr) != SAI_STATUS_SUCCESS) { attr.value.s32 = SAI_SWITCH_TYPE_NPU; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); } // check for default acl stages attr.id = SAI_SWITCH_ATTR_MAX_ACL_ACTION_COUNT; if (get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr) != SAI_STATUS_SUCCESS) { CHECK_STATUS(set_acl_capabilities()); } // check for default supported object types attr.id = SAI_SWITCH_ATTR_SUPPORTED_OBJECT_TYPE_LIST; std::vector<sai_object_type_t> objs(MAX_OBJLIST_LEN); attr.value.s32list.count = MAX_OBJLIST_LEN; attr.value.s32list.list = (int32_t*)objs.data(); if (get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr) != SAI_STATUS_SUCCESS) { CHECK_STATUS(set_switch_supported_object_types()); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::warm_update_cpu_queues() { SWSS_LOG_ENTER(); sai_attribute_t attr; // check for queues attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_QUEUES; if (get(SAI_OBJECT_TYPE_PORT, m_cpu_port_id, 1, &attr) != SAI_STATUS_SUCCESS) { SWSS_LOG_WARN("creating cpu queues"); CHECK_STATUS(create_cpu_qos_queues(m_cpu_port_id)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_bridge_port_list( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t bridge_id) { SWSS_LOG_ENTER(); SWSS_LOG_ERROR("implement in child class"); return SAI_STATUS_NOT_IMPLEMENTED; } sai_status_t SwitchStateBase::refresh_vlan_member_list( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t vlan_id) { SWSS_LOG_ENTER(); auto &all_vlan_members = m_objectHash.at(SAI_OBJECT_TYPE_VLAN_MEMBER); auto m_member_list = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_VLAN, SAI_VLAN_ATTR_MEMBER_LIST); auto md_vlan_id = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_VLAN_MEMBER, SAI_VLAN_MEMBER_ATTR_VLAN_ID); //auto md_brportid = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_VLAN_MEMBER, SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID); std::vector<sai_object_id_t> vlan_member_list; /* * We want order as bridge port order (so port order) */ sai_attribute_t attr; auto me = m_objectHash.at(SAI_OBJECT_TYPE_VLAN).at(sai_serialize_object_id(vlan_id)); for (auto vm: all_vlan_members) { if (vm.second.at(md_vlan_id->attridname)->getAttr()->value.oid != vlan_id) { /* * Only interested in our vlan */ continue; } // TODO we need order as bridge ports, but we need bridge id! { sai_object_id_t vlan_member_id; sai_deserialize_object_id(vm.first, vlan_member_id); vlan_member_list.push_back(vlan_member_id); } } uint32_t vlan_member_list_count = (uint32_t)vlan_member_list.size(); SWSS_LOG_NOTICE("recalculated %s: %u", m_member_list->attridname, vlan_member_list_count); attr.id = SAI_VLAN_ATTR_MEMBER_LIST; attr.value.objlist.count = vlan_member_list_count; attr.value.objlist.list = vlan_member_list.data(); return set(SAI_OBJECT_TYPE_VLAN, vlan_id, &attr); } sai_status_t SwitchStateBase::refresh_port_list( _In_ const sai_attr_metadata_t *meta) { SWSS_LOG_ENTER(); // since now port can be added or removed, we need to update port list // dynamically sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_CPU_PORT; CHECK_STATUS(get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr)); const sai_object_id_t cpu_port_id = attr.value.oid; std::unordered_set<sai_object_id_t> fabric_port_set(m_fabric_port_list.begin(), m_fabric_port_list.end()); m_port_list.clear(); // iterate via ASIC state to find all the ports for (const auto& it: m_objectHash.at(SAI_OBJECT_TYPE_PORT)) { sai_object_id_t port_id; sai_deserialize_object_id(it.first, port_id); // don't put CPU port id on the list if (port_id == cpu_port_id) continue; // don't put fabric ports on the list if (fabric_port_set.find(port_id) != fabric_port_set.end()) continue; m_port_list.push_back(port_id); } /* * XXX Currently we don't know what's happen on brcm SAI implementation * when port is removed and then added, will new port could get the same * vendor OID or always different, and what is order of those new oids on * the PORT_LIST attribute. * * This needs to be investigated, and to reflect exact behaviour here. * Currently we just sort all the port oids. */ std::sort(m_port_list.begin(), m_port_list.end()); uint32_t port_count = (uint32_t)m_port_list.size(); attr.id = SAI_SWITCH_ATTR_PORT_LIST; attr.value.objlist.count = port_count; attr.value.objlist.list = m_port_list.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_PORT_NUMBER; attr.value.u32 = port_count; CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); SWSS_LOG_NOTICE("refreshed port list, current port number: %zu, not counting cpu port", m_port_list.size()); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_macsec_sci_in_ingress_macsec_acl( _In_ sai_object_id_t object_id) { SWSS_LOG_ENTER(); /* * SAI_MACSEC_ATTR_SCI_IN_INGRESS_MACSEC_ACL indicates the MACsec ASIC capability * of whether SCI can only be used as ACL field. * To set SAI_MACSEC_ATTR_SCI_IN_INGRESS_MACSEC_ACL is always true, * which indicates that here is emulating a kind of MACsec ASIC that use SCI as ACL field. */ sai_attribute_t attr; attr.id = SAI_MACSEC_ATTR_SCI_IN_INGRESS_MACSEC_ACL; attr.value.booldata = true; CHECK_STATUS(set(SAI_OBJECT_TYPE_MACSEC, object_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_queue_pause_status( _In_ sai_object_id_t object_id) { SWSS_LOG_ENTER(); // To trigger fake PFC storm on fake Broadcom platform, PFC storm detection // lua requires SAI_QUEUE_ATTR_PAUSE_STATUS field to be present in COUNTERS_DB. // However, the actual value of the attribute does not matter in this regard, // so a dummy one is assigned here. sai_attribute_t attr; attr.id = SAI_QUEUE_ATTR_PAUSE_STATUS; attr.value.booldata = false; CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, object_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_macsec_sa_stat( _In_ sai_object_id_t object_id) { SWSS_LOG_ENTER(); sai_attribute_t attr; attr.id = SAI_MACSEC_SA_ATTR_CURRENT_XPN; CHECK_STATUS(getMACsecSAPacketNumber(object_id, attr)); CHECK_STATUS(set(SAI_OBJECT_TYPE_MACSEC_SA, object_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_port_serdes_id( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); // port serdes could be removed by user explicitly, so try to find port // serdes object with this specific port sai_attribute_t attr; attr.id = SAI_PORT_ATTR_PORT_SERDES_ID; attr.value.oid = SAI_NULL_OBJECT_ID; auto* meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_PORT_SERDES, SAI_PORT_SERDES_ATTR_PORT_ID); // loop via all port serdes objects auto &serdeses = m_objectHash.at(SAI_OBJECT_TYPE_PORT_SERDES); auto strPortId = sai_serialize_object_id(port_id); for (auto& kvp: serdeses) { if (kvp.second.find(meta->attridname) != kvp.second.end()) { if (kvp.second.at(meta->attridname)->getAttrStrValue() != strPortId) { // this is not the port we are looking for continue; } SWSS_LOG_INFO("found corresponding port serdes %s for port %s", kvp.first.c_str(), sai_serialize_object_id(port_id).c_str()); sai_deserialize_object_id(kvp.first, attr.value.oid); break; } } CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_port_oper_speed( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); sai_attribute_t attr; attr.id = SAI_PORT_ATTR_OPER_STATUS; CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attr)); if (attr.value.s32 == SAI_PORT_OPER_STATUS_DOWN) { attr.value.u32 = 0; } else { if (m_switchConfig->m_useConfiguredSpeedAsOperSpeed) { attr.id = SAI_PORT_ATTR_SPEED; CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attr)); } else if (!vs_get_oper_speed(port_id, attr.value.u32)) { return SAI_STATUS_FAILURE; } } attr.id = SAI_PORT_ATTR_OPER_SPEED; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_acl_table_entries( _In_ sai_object_id_t acl_table_id) { SWSS_LOG_ENTER(); std::vector<sai_object_id_t> acl_entries; sai_attribute_t attr; attr.id = SAI_ACL_ENTRY_ATTR_TABLE_ID; attr.value.oid = acl_table_id; findObjects(SAI_OBJECT_TYPE_ACL_ENTRY, attr, acl_entries); attr.id = SAI_ACL_TABLE_ATTR_AVAILABLE_ACL_ENTRY; attr.value.u32 = m_maxAclTableEntries - (uint32_t) acl_entries.size(); CHECK_STATUS(set(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::refresh_acl_table_counters( _In_ sai_object_id_t acl_table_id) { SWSS_LOG_ENTER(); std::vector<sai_object_id_t> acl_counters; sai_attribute_t attr; attr.id = SAI_ACL_COUNTER_ATTR_TABLE_ID; attr.value.oid = acl_table_id; findObjects(SAI_OBJECT_TYPE_ACL_COUNTER, attr, acl_counters); attr.id = SAI_ACL_TABLE_ATTR_AVAILABLE_ACL_COUNTER; attr.value.u32 = m_maxAclTableCounters - (uint32_t) acl_counters.size(); CHECK_STATUS(set(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_id, &attr)); return SAI_STATUS_SUCCESS; } // XXX extra work may be needed on GET api if N on list will be > then actual /* * We can use local variable here for initialization (init should be in class * constructor anyway, we can move it there later) because each switch init is * done under global lock. */ /* * NOTE For recalculation we can add flag on create/remove specific object type * so we can deduce whether actually need to perform recalculation, as * optimization. */ sai_status_t SwitchStateBase::refresh_read_only( _In_ const sai_attr_metadata_t *meta, _In_ sai_object_id_t object_id) { SWSS_LOG_ENTER(); if (meta->objecttype == SAI_OBJECT_TYPE_SWITCH) { switch (meta->attrid) { case SAI_SWITCH_ATTR_CPU_PORT: case SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID: case SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP: case SAI_SWITCH_ATTR_DEFAULT_VLAN_ID: case SAI_SWITCH_ATTR_DEFAULT_STP_INST_ID: case SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_ECMP_HASH: case SAI_SWITCH_ATTR_LAG_HASH: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_ACL_ENTRY_MINIMUM_PRIORITY: case SAI_SWITCH_ATTR_ACL_ENTRY_MAXIMUM_PRIORITY: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_MAX_ACL_ACTION_COUNT: case SAI_SWITCH_ATTR_ACL_STAGE_INGRESS: case SAI_SWITCH_ATTR_ACL_STAGE_EGRESS: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_NUMBER_OF_ECMP_GROUPS: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_PORT_NUMBER: case SAI_SWITCH_ATTR_PORT_LIST: return refresh_port_list(meta); case SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_CHILDS_PER_SCHEDULER_GROUP: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_AVAILABLE_IPV4_ROUTE_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPV6_ROUTE_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEXTHOP_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEXTHOP_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPV4_NEIGHBOR_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPV6_NEIGHBOR_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_MEMBER_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_NEXT_HOP_GROUP_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE: case SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE_GROUP: case SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY: case SAI_SWITCH_ATTR_AVAILABLE_DOUBLE_NAT_ENTRY: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_NUMBER_OF_SYSTEM_PORTS: case SAI_SWITCH_ATTR_SYSTEM_PORT_LIST: return refresh_system_port_list(meta); case SAI_SWITCH_ATTR_NUMBER_OF_FABRIC_PORTS: case SAI_SWITCH_ATTR_FABRIC_PORT_LIST: return SAI_STATUS_SUCCESS; case SAI_SWITCH_ATTR_SUPPORTED_OBJECT_TYPE_LIST: return SAI_STATUS_SUCCESS; } } if (meta->objecttype == SAI_OBJECT_TYPE_PORT) { switch (meta->attrid) { case SAI_PORT_ATTR_QOS_NUMBER_OF_QUEUES: case SAI_PORT_ATTR_QOS_QUEUE_LIST: return refresh_qos_queues(meta, object_id); case SAI_PORT_ATTR_NUMBER_OF_INGRESS_PRIORITY_GROUPS: case SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST: return refresh_ingress_priority_group(meta, object_id); case SAI_PORT_ATTR_QOS_NUMBER_OF_SCHEDULER_GROUPS: case SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST: return refresh_scheduler_groups(meta, object_id); /* * This status is based on hostif vEthernetX status. */ case SAI_PORT_ATTR_OPER_STATUS: case SAI_PORT_ATTR_HOST_TX_READY_STATUS: return SAI_STATUS_SUCCESS; case SAI_PORT_ATTR_FABRIC_ATTACHED: case SAI_PORT_ATTR_FABRIC_ATTACHED_SWITCH_ID: case SAI_PORT_ATTR_FABRIC_ATTACHED_PORT_INDEX: case SAI_PORT_ATTR_HW_LANE_LIST: return SAI_STATUS_SUCCESS; case SAI_PORT_ATTR_PORT_SERDES_ID: return refresh_port_serdes_id(object_id); case SAI_PORT_ATTR_SUPPORTED_AUTO_NEG_MODE: return SAI_STATUS_SUCCESS; case SAI_PORT_ATTR_OPER_SPEED: return refresh_port_oper_speed(object_id); } } if (meta->objecttype == SAI_OBJECT_TYPE_SYSTEM_PORT) { switch (meta->attrid) { case SAI_SYSTEM_PORT_ATTR_TYPE: case SAI_SYSTEM_PORT_ATTR_PORT: case SAI_SYSTEM_PORT_ATTR_QOS_NUMBER_OF_VOQS: case SAI_SYSTEM_PORT_ATTR_QOS_VOQ_LIST: return SAI_STATUS_SUCCESS; } } if (meta->objecttype == SAI_OBJECT_TYPE_SCHEDULER_GROUP) { switch (meta->attrid) { case SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT: case SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST: return refresh_scheduler_groups(meta, object_id); } } if (meta->objecttype == SAI_OBJECT_TYPE_BRIDGE && meta->attrid == SAI_BRIDGE_ATTR_PORT_LIST) { return refresh_bridge_port_list(meta, object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_VLAN && meta->attrid == SAI_VLAN_ATTR_MEMBER_LIST) { return refresh_vlan_member_list(meta, object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_DEBUG_COUNTER && meta->attrid == SAI_DEBUG_COUNTER_ATTR_INDEX) { return SAI_STATUS_SUCCESS; } if (meta->objecttype == SAI_OBJECT_TYPE_MACSEC && meta->attrid == SAI_MACSEC_ATTR_SCI_IN_INGRESS_MACSEC_ACL) { return refresh_macsec_sci_in_ingress_macsec_acl(object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_QUEUE && meta->attrid == SAI_QUEUE_ATTR_PAUSE_STATUS) { return refresh_queue_pause_status(object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_MACSEC_SA) { return refresh_macsec_sa_stat(object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_ACL_TABLE && meta->attrid == SAI_ACL_TABLE_ATTR_AVAILABLE_ACL_ENTRY) { return refresh_acl_table_entries(object_id); } if (meta->objecttype == SAI_OBJECT_TYPE_ACL_TABLE && meta->attrid == SAI_ACL_TABLE_ATTR_AVAILABLE_ACL_COUNTER) { return refresh_acl_table_counters(object_id); } auto mmeta = m_meta.lock(); if (mmeta) { if (mmeta->meta_unittests_enabled()) { SWSS_LOG_NOTICE("unittests enabled, SET could be performed on %s, not recalculating", meta->attridname); return SAI_STATUS_SUCCESS; } } else { SWSS_LOG_WARN("meta pointer expired"); } SWSS_LOG_WARN("need to recalculate RO: %s", meta->attridname); return SAI_STATUS_NOT_IMPLEMENTED; } void SwitchStateBase::processFdbEntriesForAging() { SWSS_LOG_ENTER(); SWSS_LOG_DEBUG("fdb infos to process: %zu", m_fdb_info_set.size()); uint32_t current = (uint32_t)time(NULL); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_FDB_AGING_TIME; sai_status_t status = get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_WARN("failed to get FDB aging time for switch %s", sai_serialize_object_id(m_switch_id).c_str()); return; } uint32_t aging_time = attr.value.u32; if (aging_time == 0) { SWSS_LOG_DEBUG("aging is disabled"); return; } // find aged fdb entries for (auto it = m_fdb_info_set.begin(); it != m_fdb_info_set.end();) { if ((current - it->getTimestamp()) >= aging_time) { FdbInfo fi = *it; processFdbInfo(fi, SAI_FDB_EVENT_AGED); it = m_fdb_info_set.erase(it); } else { ++it; } } } bool SwitchStateBase::isPortReadyToBeRemove( _In_ sai_object_id_t portId) { SWSS_LOG_ENTER(); std::vector<sai_object_id_t> dep; auto status = check_port_dependencies(portId, dep); return status == SAI_STATUS_SUCCESS; } std::vector<sai_object_id_t> SwitchStateBase::getPortDependencies( _In_ sai_object_id_t portId) { SWSS_LOG_ENTER(); std::vector<sai_object_id_t> dep; check_port_dependencies(portId, dep); return dep; } bool SwitchStateBase::check_port_reference_count( _In_ sai_object_id_t port_id) { SWSS_LOG_ENTER(); // TODO make generic // TODO currently when switch is initialized, there is no metadata yet // and objects are created without reference count, this needs to be // addressed in refactoring metadata and meta_create_oid to correct // count references, but now we need to check if port is used in any // bridge port (and bridge port in any vlan member), after metadata // refactor this function can be removed. // check if port is used on any bridge port object (only switch init one // matters, user created bridge ports will have correct reference count auto& bridgePorts = m_objectHash.at(SAI_OBJECT_TYPE_BRIDGE_PORT); auto* meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE_PORT, SAI_BRIDGE_PORT_ATTR_PORT_ID); for (auto& bp: bridgePorts) { for (auto&attr: bp.second) { if (attr.first != meta->attridname) continue; // not this attribute if (attr.second->getAttr()->value.oid == port_id) { SWSS_LOG_ERROR("port id %s is in use on bridge port %s", sai_serialize_object_id(port_id).c_str(), bp.first.c_str()); return false; } } } auto& serdeses = m_objectHash.at(SAI_OBJECT_TYPE_PORT_SERDES); meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_PORT_SERDES, SAI_PORT_SERDES_ATTR_PORT_ID); for (auto& ps: serdeses) { for (auto&attr: ps.second) { if (attr.first != meta->attridname) continue; // not this attribute if (attr.second->getAttr()->value.oid == port_id) { SWSS_LOG_ERROR("port id %s is in use on port serdes %s", sai_serialize_object_id(port_id).c_str(), ps.first.c_str()); return false; } } } return true; } sai_status_t SwitchStateBase::check_port_dependencies( _In_ sai_object_id_t port_id, _Out_ std::vector<sai_object_id_t>& dep) { SWSS_LOG_ENTER(); // check if port exists's sai_object_id_t switch_id = switchIdQuery(port_id); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("failed to obtain switch_id from object %s", sai_serialize_object_id(port_id).c_str()); return SAI_STATUS_FAILURE; } sai_object_type_t ot = objectTypeQuery(port_id); if (ot != SAI_OBJECT_TYPE_PORT) { SWSS_LOG_ERROR("expected object type PORT but object %s has type %s", sai_serialize_object_id(port_id).c_str(), sai_serialize_object_type(ot).c_str()); return SAI_STATUS_FAILURE; } std::string str_port_id = sai_serialize_object_id(port_id); auto &objectHash = m_objectHash.at(ot); auto it = objectHash.find(str_port_id); if (it == objectHash.end()) { SWSS_LOG_ERROR("port not found %s:%s", sai_serialize_object_type(ot).c_str(), str_port_id.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } // port was found SWSS_LOG_NOTICE("port %s found, for removal", sai_serialize_object_id(port_id).c_str()); // check port reference count on bridge port if (!check_port_reference_count(port_id)) { SWSS_LOG_ERROR("port %s reference count IS NOT ZERO, can't remove, remove dependencies first", sai_serialize_object_id(port_id).c_str()); return SAI_STATUS_FAILURE; } // obtain objects to examine std::vector<sai_object_id_t> queues; std::vector<sai_object_id_t> ipgs; std::vector<sai_object_id_t> sg; bool result = true; result &= get_port_queues(port_id, queues); result &= get_port_ipgs(port_id, ipgs); result &= get_port_sg(port_id, sg); if (!result) { SWSS_LOG_ERROR("failed to obtain required objects on port %s", sai_serialize_object_id(port_id).c_str()); return SAI_STATUS_FAILURE; } // check if all objects are in default state result &= check_object_default_state(port_id); result &= check_object_list_default_state(queues); result &= check_object_list_default_state(ipgs); result &= check_object_list_default_state(sg); if (!result) { SWSS_LOG_ERROR("one of objects is not in default state, can't remove port %s", sai_serialize_object_id(port_id).c_str()); return SAI_STATUS_FAILURE; } SWSS_LOG_NOTICE("all depending objects on port %s are in default state", sai_serialize_object_id(port_id).c_str()); dep.insert(dep.end(), queues.begin(), queues.end()); dep.insert(dep.end(), ipgs.begin(), ipgs.end()); dep.insert(dep.end(), sg.begin(), sg.end()); // BRIDGE PORT (and also VLAN MEMBER using that bridge port) must be // removed before removing port itself, since bridge port holds reference // to port being removed. // bridge ports and vlan members must be removed before port can be removed return SAI_STATUS_SUCCESS; } bool SwitchStateBase::get_object_list( _In_ sai_object_id_t object_id, _In_ sai_attr_id_t attr_id, _Out_ std::vector<sai_object_id_t>& objlist) { SWSS_LOG_ENTER(); objlist.clear(); sai_object_type_t object_type = objectTypeQuery(object_id); auto* meta = sai_metadata_get_attr_metadata(object_type, attr_id); if (meta == nullptr) { SWSS_LOG_THROW("failed to get metadata for OID %s and attrid: %d", sai_serialize_object_id(object_id).c_str(), attr_id); } if (meta->attrvaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_LIST) { SWSS_LOG_THROW("attr %s is not objlist attribute", meta->attridname); } sai_status_t status; sai_attribute_t attr; objlist.resize(MAX_OBJLIST_LEN); attr.id = attr_id; attr.value.objlist.count = MAX_OBJLIST_LEN; attr.value.objlist.list = objlist.data(); status = get(object_type, object_id, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to obtain %s for %s queues: %s", meta->attridname, sai_serialize_object_id(object_id).c_str(), sai_serialize_status(status).c_str()); objlist.clear(); return false; } objlist.resize(attr.value.objlist.count); SWSS_LOG_NOTICE("%s returned %zu objects for %s", meta->attridname, objlist.size(), sai_serialize_object_id(object_id).c_str()); return true; } bool SwitchStateBase::get_port_queues( _In_ sai_object_id_t port_id, _Out_ std::vector<sai_object_id_t>& queues) { SWSS_LOG_ENTER(); return get_object_list(port_id, SAI_PORT_ATTR_QOS_QUEUE_LIST, queues); } bool SwitchStateBase::get_port_ipgs( _In_ sai_object_id_t port_id, _Out_ std::vector<sai_object_id_t>& ipgs) { SWSS_LOG_ENTER(); return get_object_list(port_id, SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST, ipgs); } bool SwitchStateBase::get_port_sg( _In_ sai_object_id_t port_id, _Out_ std::vector<sai_object_id_t>& sg) { SWSS_LOG_ENTER(); // scheduler groups are organized in tree, but // SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST should return all scheduler groups in that tree return get_object_list(port_id, SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST, sg); } bool SwitchStateBase::check_object_default_state( _In_ sai_object_id_t object_id) { SWSS_LOG_ENTER(); sai_object_type_t object_type = objectTypeQuery(object_id); if (object_type == SAI_OBJECT_TYPE_NULL) { SWSS_LOG_ERROR("failed to get object type for oid: %s", sai_serialize_object_id(object_id).c_str()); return false; } auto* oti = sai_metadata_get_object_type_info(object_type); if (oti == nullptr) { SWSS_LOG_THROW("failed to get object type info for object type: %s", sai_serialize_object_type(object_type).c_str()); } // iterate over all attributes for (size_t i = 0; i < oti->attrmetadatalength; i++) { auto* meta = oti->attrmetadata[i]; // skip readonly, mandatory on create and non oid attributes if (meta->isreadonly) continue; if (!meta->isoidattribute) continue; if (meta->ismandatoryoncreate && meta->iscreateonly) continue; // those attributes must be skipped since those dependencies will be automatically broken if (meta->objecttype == SAI_OBJECT_TYPE_SCHEDULER_GROUP && meta->attrid == SAI_SCHEDULER_GROUP_ATTR_PORT_ID) continue; if (meta->objecttype == SAI_OBJECT_TYPE_SCHEDULER_GROUP && meta->attrid == SAI_SCHEDULER_GROUP_ATTR_PARENT_NODE) continue; if (meta->objecttype == SAI_OBJECT_TYPE_QUEUE && meta->attrid == SAI_QUEUE_ATTR_PORT) continue; if (meta->objecttype == SAI_OBJECT_TYPE_QUEUE && meta->attrid == SAI_QUEUE_ATTR_PARENT_SCHEDULER_NODE) continue; if (meta->objecttype == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP && meta->attrid == SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT) continue; // here we have only oid/object list attrs and we expect each of this // attribute will be in default state which for oid is usually NULL, // and for object list is empty sai_attribute_t attr; attr.id = meta->attrid; sai_status_t status; std::vector<sai_object_id_t> objlist; if (meta->attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID) { // ok } else if (meta->attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_LIST) { objlist.resize(MAX_OBJLIST_LEN); attr.value.objlist.count = MAX_OBJLIST_LEN; attr.value.objlist.list = objlist.data(); } else { // unable to check whether object is in default state, need fix SWSS_LOG_ERROR("unsupported oid attribute: %s, FIX ME!", meta->attridname); return false; } status = get(object_type, object_id, 1, &attr); switch (status) { case SAI_STATUS_NOT_IMPLEMENTED: case SAI_STATUS_NOT_SUPPORTED: continue; case SAI_STATUS_SUCCESS: break; default: SWSS_LOG_ERROR("unexpected status %s on %s obj %s", sai_serialize_status(status).c_str(), meta->attridname, sai_serialize_object_id(object_id).c_str()); return false; } if (meta->attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID) { if (attr.value.oid != SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("expected null object id on %s on %s, but got: %s", meta->attridname, sai_serialize_object_id(object_id).c_str(), sai_serialize_object_id(attr.value.oid).c_str()); return false; } } else if (meta->attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_LIST) { if (objlist.size()) { SWSS_LOG_ERROR("expected empty list on %s on %s, contents:", meta->attridname, sai_serialize_object_id(object_id).c_str()); for (auto oid: objlist) { SWSS_LOG_ERROR(" - oid: %s", sai_serialize_object_id(oid).c_str()); } return false; } } else { // unable to check whether object is in default state, need fix SWSS_LOG_ERROR("unsupported oid attribute: %s, FIX ME!", meta->attridname); return false; } } // XXX later there can be issue when we for example add extra queues to // the port those new queues should be removed by user first before // removing port, and currently we don't have a way to differentiate those // object is in default state return true; } bool SwitchStateBase::check_object_list_default_state( _Out_ const std::vector<sai_object_id_t>& objlist) { SWSS_LOG_ENTER(); return std::all_of(objlist.begin(), objlist.end(), [&](sai_object_id_t oid) { return check_object_default_state(oid); }); } std::string SwitchStateBase::dump_switch_database_for_warm_restart() const { SWSS_LOG_ENTER(); std::stringstream ss; const auto& objectHash = m_objectHash; // dump all objects and attributes to file size_t count = 0; for (auto kvp: objectHash) { auto singleTypeObjectMap = kvp.second; count += singleTypeObjectMap.size(); for (auto o: singleTypeObjectMap) { // if object don't have attributes, size can be zero if (o.second.size() == 0) { ss << sai_serialize_object_type(kvp.first) << " " << o.first << " NULL NULL" << std::endl; continue; } for (auto a: o.second) { ss << sai_serialize_object_type(kvp.first) << " "; ss << o.first.c_str(); ss << " "; ss << a.first.c_str(); ss << " "; ss << a.second->getAttrStrValue(); ss << std::endl; } } } if (m_switchConfig->m_useTapDevice) { /* * If user is using tap devices we also need to dump local fdb info * data and restore it on warm start. */ for (auto fi: m_fdb_info_set) { ss << SAI_VS_FDB_INFO << " " << fi.serialize() << std::endl; } SWSS_LOG_NOTICE("dumped %zu fdb infos for switch %s", m_fdb_info_set.size(), sai_serialize_object_id(m_switch_id).c_str()); } SWSS_LOG_NOTICE("dumped %zu objects from switch %s", count, sai_serialize_object_id(m_switch_id).c_str()); return ss.str(); } sai_object_type_t SwitchStateBase::objectTypeQuery( _In_ sai_object_id_t objectId) { SWSS_LOG_ENTER(); return RealObjectIdManager::objectTypeQuery(objectId); } sai_object_id_t SwitchStateBase::switchIdQuery( _In_ sai_object_id_t objectId) { SWSS_LOG_ENTER(); return RealObjectIdManager::switchIdQuery(objectId); } void SwitchStateBase::debugSetStats( _In_ sai_object_id_t oid, _In_ const std::map<sai_stat_id_t, uint64_t>& stats) { SWSS_LOG_ENTER(); auto key = sai_serialize_object_id(oid); for (auto& kvp: stats) { m_countersMap[key][kvp.first] = kvp.second; } } sai_status_t SwitchStateBase::initialize_voq_switch_objects( _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); bool voq_switch = false; int32_t voq_switch_id = -1; uint32_t voq_max_cores = 0; uint32_t sys_port_count = 0; sai_system_port_config_t *sys_port_cfg_list = NULL; for (uint32_t i = 0; i < attr_count; i++) { switch (attr_list[i].id) { case SAI_SWITCH_ATTR_TYPE: if (attr_list[i].value.u32 != SAI_SWITCH_TYPE_VOQ) { // Switch is not being set as VOQ type. SWSS_LOG_NOTICE("initialize_voq_switch_objects the value is %d", attr_list[i].value.u32); if (attr_list[i].value.u32 == SAI_SWITCH_TYPE_FABRIC) { SWSS_LOG_NOTICE("about to config fabric ports"); if (m_switchConfig->m_fabricLaneMap) { CHECK_STATUS(create_fabric_ports()); CHECK_STATUS(set_fabric_port_list()); } } return SAI_STATUS_SUCCESS; } else { voq_switch = true; } break; case SAI_SWITCH_ATTR_SWITCH_ID: voq_switch_id = (int32_t) attr_list[i].value.u32; if (voq_switch_id < 0) { SWSS_LOG_ERROR("Invalid VOQ switch id %d", voq_switch_id); return (int32_t)SAI_STATUS_INVALID_ATTR_VALUE_0 + (int32_t)i; } break; case SAI_SWITCH_ATTR_MAX_SYSTEM_CORES: voq_max_cores = attr_list[i].value.u32; if (voq_max_cores < 1) { SWSS_LOG_ERROR("Invalid VOQ max system cores %d", voq_max_cores); return (int32_t)SAI_STATUS_INVALID_ATTR_VALUE_0 + (int32_t)i; } break; case SAI_SWITCH_ATTR_SYSTEM_PORT_CONFIG_LIST: sys_port_count = attr_list[i].value.sysportconfiglist.count; sys_port_cfg_list = attr_list[i].value.sysportconfiglist.list; if (sys_port_count < 1 || !sys_port_cfg_list) { SWSS_LOG_ERROR("Invalid voq system port config info! sys port count %d, sys port list %p", sys_port_count, sys_port_cfg_list); return (int32_t)SAI_STATUS_INVALID_ATTR_VALUE_0 + (int32_t)i; } break; default: // Ignore other attributes. They are processed elsewhere. break; } } if (!voq_switch) { // No switch type attribute in the attribute list. return SAI_STATUS_SUCCESS; } CHECK_STATUS(create_system_ports(voq_switch_id, sys_port_count, sys_port_cfg_list)); CHECK_STATUS(create_voqs()); CHECK_STATUS(set_system_port_list()); if (m_switchConfig->m_fabricLaneMap) { CHECK_STATUS(create_fabric_ports()); CHECK_STATUS(set_fabric_port_list()); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::filter_available_lanes( _Inout_ std::vector<std::vector<uint32_t>> &lanes_vector) { SWSS_LOG_ENTER(); auto lanes = lanes_vector.begin(); while (lanes != lanes_vector.end()) { bool available_lane = false; for (auto lane: *lanes) { std::string ifname = m_switchConfig->m_laneMap->getInterfaceFromLaneNumber(lane); std::string path = std::string("/sys/class/net/") + ifname + "/operstate"; if (access(path.c_str(), F_OK) != 0) { SWSS_LOG_WARN("Port %s isn't available", ifname.c_str()); available_lane &= false; break; } else { available_lane = true; } } if (!available_lane) { lanes = lanes_vector.erase(lanes); } else { lanes++; } } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_voq_per_sysport( _In_ sai_object_id_t sys_port_id) { SWSS_LOG_ENTER(); sai_attribute_t attr; const uint32_t voq_count = 8; std::vector<sai_object_id_t> voqs; for (uint32_t i = 0; i < voq_count; ++i) { sai_object_id_t voq_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_QUEUE, &voq_id, m_switch_id, 0, NULL)); voqs.push_back(voq_id); attr.id = SAI_QUEUE_ATTR_TYPE; attr.value.s32 = SAI_QUEUE_TYPE_UNICAST_VOQ; CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, voq_id, &attr)); attr.id = SAI_QUEUE_ATTR_INDEX; attr.value.u8 = (uint8_t)i; CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, voq_id, &attr)); } attr.id = SAI_SYSTEM_PORT_ATTR_QOS_NUMBER_OF_VOQS; attr.value.u32 = voq_count; CHECK_STATUS(set(SAI_OBJECT_TYPE_SYSTEM_PORT, sys_port_id, &attr)); attr.id = SAI_SYSTEM_PORT_ATTR_QOS_VOQ_LIST; attr.value.objlist.count = voq_count; attr.value.objlist.list = voqs.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_SYSTEM_PORT, sys_port_id, &attr)); return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_voqs() { SWSS_LOG_ENTER(); for (auto &sys_port_id: m_system_port_list) { CHECK_STATUS(create_voq_per_sysport(sys_port_id)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_system_ports( _In_ int32_t voq_switch_id, _In_ uint32_t sys_port_count, _In_ const sai_system_port_config_t *sys_port_cfg_list) { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create system ports"); if (!sys_port_cfg_list) { return SAI_STATUS_FAILURE; } m_system_port_list.clear(); for (uint32_t i = 0; i < sys_port_count; i++) { SWSS_LOG_DEBUG("create system port index %u", i); sai_object_id_t system_port_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_SYSTEM_PORT, &system_port_id, m_switch_id, 0, NULL)); m_system_port_list.push_back(system_port_id); sai_attribute_t attr; attr.id = SAI_SYSTEM_PORT_ATTR_CONFIG_INFO; attr.value.sysportconfig = sys_port_cfg_list[i]; CHECK_STATUS(set(SAI_OBJECT_TYPE_SYSTEM_PORT, system_port_id, &attr)); attr.id = SAI_SYSTEM_PORT_ATTR_TYPE; attr.value.s32 = SAI_SYSTEM_PORT_TYPE_REMOTE; if ((int32_t)sys_port_cfg_list[i].attached_switch_id == voq_switch_id) { attr.value.s32 = SAI_SYSTEM_PORT_TYPE_LOCAL; // This is system port of local port. Set the oid of the local port corresponding to this system port auto map = m_switchConfig->m_corePortIndexMap; if (map) { auto& corePortIndexVector = map->getCorePortIndexVector(); size_t n_map = corePortIndexVector.size(); size_t idx; for (idx = 0; idx < n_map; idx++) { if (corePortIndexVector[idx][0] == sys_port_cfg_list[i].attached_core_index && corePortIndexVector[idx][1] == sys_port_cfg_list[i].attached_core_port_index && idx < m_port_list.size()) { // m_port_list entries are in the same order as lane maps. The core port index maps are in the // same order as the lane maps. So m_port_list at the index corresponding to the core port index map // will be the port corresponding to the system port with core port index matching core port index map sai_attribute_t lp_attr; lp_attr.id = SAI_SYSTEM_PORT_ATTR_PORT; lp_attr.value.oid = m_port_list.at(idx); CHECK_STATUS(set(SAI_OBJECT_TYPE_SYSTEM_PORT, system_port_id, &lp_attr)); break; } } if (idx >= n_map) { SWSS_LOG_ERROR("Core port index not found for system port %d for switch %s. Local port oid is not set!", sys_port_cfg_list[i].port_id, sai_serialize_object_id(m_switch_id).c_str()); } } else { SWSS_LOG_ERROR("Core port index map for switch %s is NULL. Local port oid is not set for system port %d!", sai_serialize_object_id(m_switch_id).c_str(), sys_port_cfg_list[i].port_id); } } CHECK_STATUS(set(SAI_OBJECT_TYPE_SYSTEM_PORT, system_port_id, &attr)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set_system_port_list() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set system port list"); // NOTE: this is static, but will be refreshed on read only get sai_attribute_t attr; uint32_t sys_port_count = (uint32_t)m_system_port_list.size(); attr.id = SAI_SWITCH_ATTR_SYSTEM_PORT_LIST; attr.value.objlist.count = sys_port_count; attr.value.objlist.list = m_system_port_list.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_NUMBER_OF_SYSTEM_PORTS; attr.value.u32 = sys_port_count; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::refresh_system_port_list( _In_ const sai_attr_metadata_t *meta) { SWSS_LOG_ENTER(); // Currently, system ports info are not changing. So no refresh is done // TODO In the future, when dynamic system port config (add/delete) is implemented, re-visit return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::create_fabric_ports() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("create fabric ports"); auto map = m_switchConfig->m_fabricLaneMap; if (!map) { SWSS_LOG_ERROR("fabric lane map for switch %s is NULL", sai_serialize_object_id(m_switch_id).c_str()); return SAI_STATUS_FAILURE; } auto& lanesVector = map->getLaneVector(); uint32_t fabric_port_count = (uint32_t)lanesVector.size(); m_fabric_port_list.clear(); for (uint32_t i = 0; i < fabric_port_count; i++) { SWSS_LOG_DEBUG("create fabric port index %u", i); sai_object_id_t fabric_port_id; CHECK_STATUS(create(SAI_OBJECT_TYPE_PORT, &fabric_port_id, m_switch_id, 0, NULL)); m_fabric_port_list.push_back(fabric_port_id); sai_attribute_t attr; attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED; attr.value.booldata = true; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, fabric_port_id, &attr)); std::vector<uint32_t> lanes = lanesVector.at(i); attr.id = SAI_PORT_ATTR_HW_LANE_LIST; attr.value.u32list.count = (uint32_t)lanes.size(); attr.value.u32list.list = lanes.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, fabric_port_id, &attr)); attr.id = SAI_PORT_ATTR_TYPE; attr.value.s32 = SAI_PORT_TYPE_FABRIC; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, fabric_port_id, &attr)); attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED_SWITCH_ID; attr.value.s32 = i; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, fabric_port_id, &attr)); attr.id = SAI_PORT_ATTR_FABRIC_ATTACHED_PORT_INDEX; attr.value.s32 = i; CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, fabric_port_id, &attr)); } return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::set_fabric_port_list() { SWSS_LOG_ENTER(); SWSS_LOG_INFO("set fabric port list"); sai_attribute_t attr; uint32_t fabric_port_count = (uint32_t)m_fabric_port_list.size(); attr.id = SAI_SWITCH_ATTR_FABRIC_PORT_LIST; attr.value.objlist.count = fabric_port_count; attr.value.objlist.list = m_fabric_port_list.data(); CHECK_STATUS(set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr)); attr.id = SAI_SWITCH_ATTR_NUMBER_OF_FABRIC_PORTS; attr.value.u32 = fabric_port_count; return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr); } sai_status_t SwitchStateBase::createVoqSystemNeighborEntry( _In_ const std::string &serializedObjectId, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); // For VOQ switch, encap index attribute should be set for local neighbors. For // remote neighbors check for presence of encap index supplied from upper layer. // And also validate isLocal and impose encap index flags in the attribute list // Determine whether this neighbor is local neighbor or remote neighbor by checking the // RIF id provided. If the port of the RIF is system port, the neighbor is remote neighbor bool is_system_neigh = false; sai_attribute_t attr; sai_neighbor_entry_t nbr_entry; sai_deserialize_neighbor_entry(serializedObjectId, nbr_entry); attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; CHECK_STATUS(get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, nbr_entry.rif_id, 1, &attr)); if (objectTypeQuery(attr.value.oid) == SAI_OBJECT_TYPE_SYSTEM_PORT) { is_system_neigh = true; } uint32_t encap_index = 0; bool impose_encap_index = false; bool is_local = true; for (uint32_t i = 0; i < attr_count; i++) { switch (attr_list[i].id) { case SAI_NEIGHBOR_ENTRY_ATTR_ENCAP_INDEX: encap_index = attr_list[i].value.u32; break; case SAI_NEIGHBOR_ENTRY_ATTR_ENCAP_IMPOSE_INDEX: impose_encap_index = attr_list[i].value.booldata; break; case SAI_NEIGHBOR_ENTRY_ATTR_IS_LOCAL: is_local = attr_list[i].value.booldata; break; default: break; } } if (impose_encap_index && encap_index == 0) { SWSS_LOG_ERROR("Impose invalid encap index %d for %s neigh %s", encap_index, (is_system_neigh ? "VOQ" : "local"), serializedObjectId.c_str()); return SAI_STATUS_FAILURE; } if (is_system_neigh && is_local) { SWSS_LOG_ERROR("VOQ neigh info mismatch for %s. RIF is remote. attr is_local is true", serializedObjectId.c_str()); return SAI_STATUS_FAILURE; } if (!is_local && encap_index == 0) { SWSS_LOG_ERROR("VOQ neigh info mismatch for %s. attr is_local is false. encap_index is 0", serializedObjectId.c_str()); return SAI_STATUS_FAILURE; } CHECK_STATUS(create_internal(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, serializedObjectId, switch_id, attr_count, attr_list)); if (impose_encap_index == false) { // Encap index is not imposed. Assign encap index. // The only requirement for the encap index is it must be locally // unique in asic. Lower 32 bits of the ip address is used as encap index encap_index = nbr_entry.ip_address.addr.ip4; attr.id = SAI_NEIGHBOR_ENTRY_ATTR_ENCAP_INDEX; attr.value.u32 = encap_index; CHECK_STATUS(set_internal(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, serializedObjectId, &attr)); } return SAI_STATUS_SUCCESS; } void SwitchStateBase::findObjects( _In_ sai_object_type_t object_type, _In_ const sai_attribute_t &expect, _Out_ std::vector<sai_object_id_t> &objects) { SWSS_LOG_ENTER(); objects.clear(); SaiAttrWrap expect_wrap(object_type, &expect); for (auto &obj : m_objectHash.at(object_type)) { auto attr_itr = obj.second.find(expect_wrap.getAttrMetadata()->attridname); if (attr_itr != obj.second.end() && attr_itr->second->getAttrStrValue() == expect_wrap.getAttrStrValue()) { sai_object_id_t object_id; sai_deserialize_object_id(obj.first, object_id); objects.push_back(object_id); } } } bool SwitchStateBase::dumpObject( _In_ const sai_object_id_t object_id, _Out_ std::vector<sai_attribute_t> &attrs) { SWSS_LOG_ENTER(); attrs.clear(); auto &objs = m_objectHash.at(objectTypeQuery(object_id)); auto obj = objs.find(sai_serialize_object_id(object_id)); if (obj == objs.end()) { return false; } for (auto &attr : obj->second) { attrs.push_back(*attr.second->getAttr()); } return true; } sai_status_t SwitchStateBase::queryTunnelPeerModeCapability( _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (enum_values_capability->count < 2) { return SAI_STATUS_BUFFER_OVERFLOW; } enum_values_capability->count = 2; enum_values_capability->list[0] = SAI_TUNNEL_PEER_MODE_P2MP; enum_values_capability->list[1] = SAI_TUNNEL_PEER_MODE_P2P; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryPortAutonegFecOverrideSupportCapability( _Out_ sai_attr_capability_t *attr_capability) { SWSS_LOG_ENTER(); attr_capability->create_implemented = false; attr_capability->set_implemented = false; attr_capability->get_implemented = false; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryVlanfloodTypeCapability( _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (enum_values_capability->count < 3) { return SAI_STATUS_BUFFER_OVERFLOW; } enum_values_capability->count = 3; enum_values_capability->list[0] = SAI_VLAN_FLOOD_CONTROL_TYPE_ALL; enum_values_capability->list[1] = SAI_VLAN_FLOOD_CONTROL_TYPE_NONE; enum_values_capability->list[2] = SAI_VLAN_FLOOD_CONTROL_TYPE_L2MC_GROUP; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryNextHopGroupTypeCapability( _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (enum_values_capability->count < 5) { return SAI_STATUS_BUFFER_OVERFLOW; } enum_values_capability->count = 5; enum_values_capability->list[0] = SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP; enum_values_capability->list[1] = SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_ORDERED_ECMP; enum_values_capability->list[2] = SAI_NEXT_HOP_GROUP_TYPE_FINE_GRAIN_ECMP; enum_values_capability->list[3] = SAI_NEXT_HOP_GROUP_TYPE_PROTECTION; enum_values_capability->list[4] = SAI_NEXT_HOP_GROUP_TYPE_CLASS_BASED; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryHashNativeHashFieldListCapability( _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (enum_values_capability->count < 18) { enum_values_capability->count = 18; return SAI_STATUS_BUFFER_OVERFLOW; } enum_values_capability->count = 18; enum_values_capability->list[0] = SAI_NATIVE_HASH_FIELD_IN_PORT; enum_values_capability->list[1] = SAI_NATIVE_HASH_FIELD_DST_MAC; enum_values_capability->list[2] = SAI_NATIVE_HASH_FIELD_SRC_MAC; enum_values_capability->list[3] = SAI_NATIVE_HASH_FIELD_ETHERTYPE; enum_values_capability->list[4] = SAI_NATIVE_HASH_FIELD_VLAN_ID; enum_values_capability->list[5] = SAI_NATIVE_HASH_FIELD_IP_PROTOCOL; enum_values_capability->list[6] = SAI_NATIVE_HASH_FIELD_DST_IP; enum_values_capability->list[7] = SAI_NATIVE_HASH_FIELD_SRC_IP; enum_values_capability->list[8] = SAI_NATIVE_HASH_FIELD_L4_DST_PORT; enum_values_capability->list[9] = SAI_NATIVE_HASH_FIELD_L4_SRC_PORT; enum_values_capability->list[10] = SAI_NATIVE_HASH_FIELD_INNER_DST_MAC; enum_values_capability->list[11] = SAI_NATIVE_HASH_FIELD_INNER_SRC_MAC; enum_values_capability->list[12] = SAI_NATIVE_HASH_FIELD_INNER_ETHERTYPE; enum_values_capability->list[13] = SAI_NATIVE_HASH_FIELD_INNER_IP_PROTOCOL; enum_values_capability->list[14] = SAI_NATIVE_HASH_FIELD_INNER_DST_IP; enum_values_capability->list[15] = SAI_NATIVE_HASH_FIELD_INNER_SRC_IP; enum_values_capability->list[16] = SAI_NATIVE_HASH_FIELD_INNER_L4_DST_PORT; enum_values_capability->list[17] = SAI_NATIVE_HASH_FIELD_INNER_L4_SRC_PORT; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::querySwitchHashAlgorithmCapability( _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (enum_values_capability->count < 7) { enum_values_capability->count = 7; return SAI_STATUS_BUFFER_OVERFLOW; } enum_values_capability->count = 7; enum_values_capability->list[0] = SAI_HASH_ALGORITHM_CRC; enum_values_capability->list[1] = SAI_HASH_ALGORITHM_XOR; enum_values_capability->list[2] = SAI_HASH_ALGORITHM_RANDOM; enum_values_capability->list[3] = SAI_HASH_ALGORITHM_CRC_32LO; enum_values_capability->list[4] = SAI_HASH_ALGORITHM_CRC_32HI; enum_values_capability->list[5] = SAI_HASH_ALGORITHM_CRC_CCITT; enum_values_capability->list[6] = SAI_HASH_ALGORITHM_CRC_XOR; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryAttrEnumValuesCapability( _In_ sai_object_id_t switch_id, _In_ sai_object_type_t object_type, _In_ sai_attr_id_t attr_id, _Inout_ sai_s32_list_t *enum_values_capability) { SWSS_LOG_ENTER(); if (object_type == SAI_OBJECT_TYPE_TUNNEL && attr_id == SAI_TUNNEL_ATTR_PEER_MODE) { return queryTunnelPeerModeCapability(enum_values_capability); } else if (object_type == SAI_OBJECT_TYPE_VLAN && (attr_id == SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE || attr_id == SAI_VLAN_ATTR_UNKNOWN_MULTICAST_FLOOD_CONTROL_TYPE || attr_id == SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE)) { return queryVlanfloodTypeCapability(enum_values_capability); } else if (object_type == SAI_OBJECT_TYPE_NEXT_HOP_GROUP && attr_id == SAI_NEXT_HOP_GROUP_ATTR_TYPE) { return queryNextHopGroupTypeCapability(enum_values_capability); } else if (object_type == SAI_OBJECT_TYPE_HASH && attr_id == SAI_HASH_ATTR_NATIVE_HASH_FIELD_LIST) { return queryHashNativeHashFieldListCapability(enum_values_capability); } else if (object_type == SAI_OBJECT_TYPE_SWITCH && (attr_id == SAI_SWITCH_ATTR_ECMP_DEFAULT_HASH_ALGORITHM || attr_id == SAI_SWITCH_ATTR_LAG_DEFAULT_HASH_ALGORITHM)) { return querySwitchHashAlgorithmCapability(enum_values_capability); } return SAI_STATUS_NOT_SUPPORTED; } sai_status_t SwitchStateBase::queryAttributeCapability( _In_ sai_object_id_t switch_id, _In_ sai_object_type_t object_type, _In_ sai_attr_id_t attr_id, _Out_ sai_attr_capability_t *attr_capability) { SWSS_LOG_ENTER(); if (object_type == SAI_OBJECT_TYPE_PORT && attr_id == SAI_PORT_ATTR_AUTO_NEG_FEC_MODE_OVERRIDE) { return queryPortAutonegFecOverrideSupportCapability(attr_capability); } attr_capability->create_implemented = true; attr_capability->set_implemented = true; attr_capability->get_implemented = true; return SAI_STATUS_SUCCESS; } sai_status_t SwitchStateBase::queryStatsCapability( _In_ sai_object_id_t switchId, _In_ sai_object_type_t objectType, _Inout_ sai_stat_capability_list_t *stats_capability) { SWSS_LOG_ENTER(); uint32_t i = 0; uint32_t stats_count = 0; if (objectType == SAI_OBJECT_TYPE_QUEUE) { stats_count = SAI_QUEUE_STAT_DELAY_WATERMARK_NS; if (stats_capability->count < stats_count ) { stats_capability->count = stats_count; return SAI_STATUS_BUFFER_OVERFLOW; } stats_capability->count = stats_count; for(i = 0; i < stats_capability->count; i++) { stats_capability->list[i].stat_modes = SAI_STATS_MODE_READ_AND_CLEAR | SAI_STATS_MODE_READ ; stats_capability->list[i].stat_enum = i; } return SAI_STATUS_SUCCESS; } else if (objectType == SAI_OBJECT_TYPE_PORT) { if (stats_capability->count < 91) { stats_capability->count = 91; return SAI_STATUS_BUFFER_OVERFLOW; } stats_capability->count = 91; stats_capability->list[0].stat_enum = SAI_PORT_STAT_IF_IN_OCTETS; stats_capability->list[1].stat_enum = SAI_PORT_STAT_IF_IN_UCAST_PKTS; stats_capability->list[2].stat_enum = SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS; stats_capability->list[3].stat_enum = SAI_PORT_STAT_IF_IN_DISCARDS; stats_capability->list[4].stat_enum = SAI_PORT_STAT_IF_IN_ERRORS; stats_capability->list[5].stat_enum = SAI_PORT_STAT_IF_IN_UNKNOWN_PROTOS; stats_capability->list[6].stat_enum = SAI_PORT_STAT_IF_IN_BROADCAST_PKTS; stats_capability->list[7].stat_enum = SAI_PORT_STAT_IF_IN_MULTICAST_PKTS; stats_capability->list[8].stat_enum = SAI_PORT_STAT_IF_IN_VLAN_DISCARDS; stats_capability->list[9].stat_enum = SAI_PORT_STAT_IF_OUT_OCTETS; stats_capability->list[10].stat_enum = SAI_PORT_STAT_IF_OUT_UCAST_PKTS; stats_capability->list[11].stat_enum = SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS; stats_capability->list[12].stat_enum = SAI_PORT_STAT_IF_OUT_DISCARDS; stats_capability->list[13].stat_enum = SAI_PORT_STAT_IF_OUT_ERRORS; stats_capability->list[14].stat_enum = SAI_PORT_STAT_IF_OUT_QLEN; stats_capability->list[15].stat_enum = SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS; stats_capability->list[16].stat_enum = SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS; stats_capability->list[17].stat_enum = SAI_PORT_STAT_ETHER_STATS_DROP_EVENTS; stats_capability->list[18].stat_enum = SAI_PORT_STAT_ETHER_STATS_MULTICAST_PKTS; stats_capability->list[19].stat_enum = SAI_PORT_STAT_ETHER_STATS_BROADCAST_PKTS; stats_capability->list[20].stat_enum = SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS; stats_capability->list[21].stat_enum = SAI_PORT_STAT_ETHER_STATS_FRAGMENTS; stats_capability->list[22].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_64_OCTETS; stats_capability->list[23].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_65_TO_127_OCTETS; stats_capability->list[24].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_128_TO_255_OCTETS; stats_capability->list[25].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_256_TO_511_OCTETS; stats_capability->list[26].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_512_TO_1023_OCTETS; stats_capability->list[27].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_1024_TO_1518_OCTETS; stats_capability->list[28].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_1519_TO_2047_OCTETS; stats_capability->list[29].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_2048_TO_4095_OCTETS; stats_capability->list[30].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_4096_TO_9216_OCTETS; stats_capability->list[31].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS_9217_TO_16383_OCTETS; stats_capability->list[32].stat_enum = SAI_PORT_STAT_ETHER_STATS_OVERSIZE_PKTS; stats_capability->list[33].stat_enum = SAI_PORT_STAT_ETHER_RX_OVERSIZE_PKTS; stats_capability->list[34].stat_enum = SAI_PORT_STAT_ETHER_TX_OVERSIZE_PKTS; stats_capability->list[35].stat_enum = SAI_PORT_STAT_ETHER_STATS_JABBERS; stats_capability->list[36].stat_enum = SAI_PORT_STAT_ETHER_STATS_OCTETS; stats_capability->list[37].stat_enum = SAI_PORT_STAT_ETHER_STATS_PKTS; stats_capability->list[38].stat_enum = SAI_PORT_STAT_ETHER_STATS_COLLISIONS; stats_capability->list[39].stat_enum = SAI_PORT_STAT_ETHER_STATS_CRC_ALIGN_ERRORS; stats_capability->list[40].stat_enum = SAI_PORT_STAT_ETHER_STATS_TX_NO_ERRORS; stats_capability->list[41].stat_enum = SAI_PORT_STAT_ETHER_STATS_RX_NO_ERRORS; stats_capability->list[42].stat_enum = SAI_PORT_STAT_GREEN_WRED_DROPPED_PACKETS; stats_capability->list[43].stat_enum = SAI_PORT_STAT_GREEN_WRED_DROPPED_BYTES; stats_capability->list[44].stat_enum = SAI_PORT_STAT_YELLOW_WRED_DROPPED_PACKETS; stats_capability->list[45].stat_enum = SAI_PORT_STAT_YELLOW_WRED_DROPPED_BYTES; stats_capability->list[46].stat_enum = SAI_PORT_STAT_RED_WRED_DROPPED_PACKETS; stats_capability->list[47].stat_enum = SAI_PORT_STAT_RED_WRED_DROPPED_BYTES; stats_capability->list[48].stat_enum = SAI_PORT_STAT_WRED_DROPPED_PACKETS; stats_capability->list[49].stat_enum = SAI_PORT_STAT_WRED_DROPPED_BYTES; stats_capability->list[50].stat_enum = SAI_PORT_STAT_ECN_MARKED_PACKETS; stats_capability->list[51].stat_enum = SAI_PORT_STAT_PFC_0_RX_PKTS; stats_capability->list[52].stat_enum = SAI_PORT_STAT_PFC_0_TX_PKTS; stats_capability->list[53].stat_enum = SAI_PORT_STAT_PFC_1_RX_PKTS; stats_capability->list[54].stat_enum = SAI_PORT_STAT_PFC_1_TX_PKTS; stats_capability->list[55].stat_enum = SAI_PORT_STAT_PFC_2_RX_PKTS; stats_capability->list[56].stat_enum = SAI_PORT_STAT_PFC_2_TX_PKTS; stats_capability->list[57].stat_enum = SAI_PORT_STAT_PFC_3_RX_PKTS; stats_capability->list[58].stat_enum = SAI_PORT_STAT_PFC_3_TX_PKTS; stats_capability->list[59].stat_enum = SAI_PORT_STAT_PFC_4_RX_PKTS; stats_capability->list[60].stat_enum = SAI_PORT_STAT_PFC_4_TX_PKTS; stats_capability->list[61].stat_enum = SAI_PORT_STAT_PFC_5_RX_PKTS; stats_capability->list[62].stat_enum = SAI_PORT_STAT_PFC_5_TX_PKTS; stats_capability->list[63].stat_enum = SAI_PORT_STAT_PFC_6_RX_PKTS; stats_capability->list[64].stat_enum = SAI_PORT_STAT_PFC_6_TX_PKTS; stats_capability->list[65].stat_enum = SAI_PORT_STAT_PFC_7_RX_PKTS; stats_capability->list[66].stat_enum = SAI_PORT_STAT_PFC_7_TX_PKTS; stats_capability->list[67].stat_enum = SAI_PORT_STAT_PFC_0_RX_PAUSE_DURATION_US; stats_capability->list[68].stat_enum = SAI_PORT_STAT_PFC_0_TX_PAUSE_DURATION_US; stats_capability->list[69].stat_enum = SAI_PORT_STAT_PFC_1_RX_PAUSE_DURATION_US; stats_capability->list[70].stat_enum = SAI_PORT_STAT_PFC_1_TX_PAUSE_DURATION_US; stats_capability->list[71].stat_enum = SAI_PORT_STAT_PFC_2_RX_PAUSE_DURATION_US; stats_capability->list[72].stat_enum = SAI_PORT_STAT_PFC_2_TX_PAUSE_DURATION_US; stats_capability->list[73].stat_enum = SAI_PORT_STAT_PFC_3_RX_PAUSE_DURATION_US; stats_capability->list[74].stat_enum = SAI_PORT_STAT_PFC_3_TX_PAUSE_DURATION_US; stats_capability->list[75].stat_enum = SAI_PORT_STAT_PFC_4_RX_PAUSE_DURATION_US; stats_capability->list[76].stat_enum = SAI_PORT_STAT_PFC_4_TX_PAUSE_DURATION_US; stats_capability->list[77].stat_enum = SAI_PORT_STAT_PFC_5_RX_PAUSE_DURATION_US; stats_capability->list[78].stat_enum = SAI_PORT_STAT_PFC_5_TX_PAUSE_DURATION_US; stats_capability->list[79].stat_enum = SAI_PORT_STAT_PFC_6_RX_PAUSE_DURATION_US; stats_capability->list[80].stat_enum = SAI_PORT_STAT_PFC_6_TX_PAUSE_DURATION_US; stats_capability->list[81].stat_enum = SAI_PORT_STAT_PFC_7_RX_PAUSE_DURATION_US; stats_capability->list[82].stat_enum = SAI_PORT_STAT_PFC_7_TX_PAUSE_DURATION_US; stats_capability->list[83].stat_enum = SAI_PORT_STAT_PFC_0_ON2OFF_RX_PKTS; stats_capability->list[84].stat_enum = SAI_PORT_STAT_PFC_1_ON2OFF_RX_PKTS; stats_capability->list[85].stat_enum = SAI_PORT_STAT_PFC_2_ON2OFF_RX_PKTS; stats_capability->list[86].stat_enum = SAI_PORT_STAT_PFC_3_ON2OFF_RX_PKTS; stats_capability->list[87].stat_enum = SAI_PORT_STAT_PFC_4_ON2OFF_RX_PKTS; stats_capability->list[88].stat_enum = SAI_PORT_STAT_PFC_5_ON2OFF_RX_PKTS; stats_capability->list[89].stat_enum = SAI_PORT_STAT_PFC_6_ON2OFF_RX_PKTS; stats_capability->list[90].stat_enum = SAI_PORT_STAT_PFC_7_ON2OFF_RX_PKTS; for(i = 0; i < stats_capability->count; i++) { stats_capability->list[i].stat_modes = SAI_STATS_MODE_READ_AND_CLEAR | SAI_STATS_MODE_READ ; } return SAI_STATUS_SUCCESS; } return SAI_STATUS_NOT_SUPPORTED; } sai_status_t SwitchStateBase::queryStatsStCapability( _In_ sai_object_id_t switchId, _In_ sai_object_type_t objectType, _Inout_ sai_stat_st_capability_list_t *stats_capability) { SWSS_LOG_ENTER(); // TODO: Fix me return SAI_STATUS_NOT_IMPLEMENTED; }