vslib/SwitchMLNX2700.cpp (304 lines of code) (raw):
#include "SwitchMLNX2700.h"
#include "swss/logger.h"
#include "meta/sai_serialize.h"
using namespace saivs;
SwitchMLNX2700::SwitchMLNX2700(
_In_ sai_object_id_t switch_id,
_In_ std::shared_ptr<RealObjectIdManager> manager,
_In_ std::shared_ptr<SwitchConfig> config):
SwitchStateBase(switch_id, manager, config)
{
SWSS_LOG_ENTER();
// empty
}
SwitchMLNX2700::SwitchMLNX2700(
_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):
SwitchStateBase(switch_id, manager, config, warmBootState)
{
SWSS_LOG_ENTER();
// empty
}
sai_status_t SwitchMLNX2700::create_qos_queues_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
// 8 in and 8 out queues per port
const uint32_t port_qos_queues_count = 16;
std::vector<sai_object_id_t> queues;
for (uint32_t i = 0; i < port_qos_queues_count; ++i)
{
sai_object_id_t queue_id;
sai_attribute_t attr[3];
attr[0].id = SAI_QUEUE_ATTR_INDEX;
attr[0].value.u8 = (uint8_t)i;
attr[1].id = SAI_QUEUE_ATTR_PORT;
attr[1].value.oid = port_id;
attr[2].id = SAI_QUEUE_ATTR_TYPE;
attr[2].value.s32 = (i < port_qos_queues_count / 2) ? SAI_QUEUE_TYPE_UNICAST : SAI_QUEUE_TYPE_MULTICAST;
// TODO add type
CHECK_STATUS(create(SAI_OBJECT_TYPE_QUEUE, &queue_id, m_switch_id, 3, attr));
queues.push_back(queue_id);
}
sai_attribute_t attr;
attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_QUEUES;
attr.value.u32 = port_qos_queues_count;
CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr));
attr.id = SAI_PORT_ATTR_QOS_QUEUE_LIST;
attr.value.objlist.count = port_qos_queues_count;
attr.value.objlist.list = queues.data();
CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr));
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::create_qos_queues()
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("create qos queues");
std::vector<sai_object_id_t> copy = m_port_list;
copy.push_back(m_cpu_port_id);
for (auto &port_id: copy)
{
create_qos_queues_per_port(port_id);
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::create_scheduler_group_tree(
_In_ const std::vector<sai_object_id_t>& sgs,
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
sai_attribute_t attrq;
std::vector<sai_object_id_t> queues;
// we have 16 queues per port, and 16 queues (8 in, 8 out)
uint32_t queues_count = 16;
queues.resize(queues_count);
attrq.id = SAI_PORT_ATTR_QOS_QUEUE_LIST;
attrq.value.objlist.count = queues_count;
attrq.value.objlist.list = queues.data();
CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attrq));
// schedulers groups indexes on list: 0 1 2 3 4 5 6 7 8 9 a b c d e f
// tree level (2 levels)
// 0 = 9 8 a b d e f
// 1 =
// 2.. - have both QUEUES, each one 2
// scheduler group 0 (8 childs)
{
sai_object_id_t sg_0 = sgs.at(0);
sai_attribute_t attr;
attr.id = SAI_SCHEDULER_GROUP_ATTR_PORT_ID;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg_0, &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT;
attr.value.u32 = 8;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg_0, &attr));
uint32_t list_count = 8;
std::vector<sai_object_id_t> list;
list.push_back(sgs.at(0x8));
list.push_back(sgs.at(0x9));
list.push_back(sgs.at(0xa));
list.push_back(sgs.at(0xb));
list.push_back(sgs.at(0xc));
list.push_back(sgs.at(0xd));
list.push_back(sgs.at(0xe));
list.push_back(sgs.at(0xf));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST;
attr.value.objlist.count = list_count;
attr.value.objlist.list = list.data();
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg_0, &attr));
}
for (int i = 1; i < 8; ++i)
{
// 1..7 schedulers are empty
sai_object_id_t sg = sgs.at(i);
sai_attribute_t attr;
attr.id = SAI_SCHEDULER_GROUP_ATTR_PORT_ID;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT;
attr.value.u32 = 0;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST;
attr.value.objlist.count = 0;
attr.value.objlist.list = NULL;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
}
// 8..f have for 2 queues
int queue_index = 0;
for (int i = 8; i < 0x10; ++i)
{
sai_object_id_t sg = sgs.at(i);
sai_object_id_t childs[2];
sai_attribute_t attr;
// for each scheduler set 2 queues
childs[0] = queues[queue_index]; // first half are in queues
childs[1] = queues[queue_index + queues_count/2]; // second half are out queues
queue_index++;
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST;
attr.value.objlist.count = 2;
attr.value.objlist.list = childs;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT;
attr.value.u32 = 2;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_PORT_ID;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg, &attr));
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::create_scheduler_groups_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
uint32_t port_sgs_count = 16; // mlnx default
sai_attribute_t attr;
attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_SCHEDULER_GROUPS;
attr.value.u32 = port_sgs_count;
CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr));
// scheduler groups per port
std::vector<sai_object_id_t> sgs;
for (uint32_t i = 0; i < port_sgs_count; ++i)
{
sai_object_id_t sg_id;
CHECK_STATUS(create(SAI_OBJECT_TYPE_SCHEDULER_GROUP, &sg_id, m_switch_id, 0, NULL));
sgs.push_back(sg_id);
}
attr.id = SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST;
attr.value.objlist.count = port_sgs_count;
attr.value.objlist.list = sgs.data();
CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr));
CHECK_STATUS(create_scheduler_group_tree(sgs, port_id));
// SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT // sched_groups + count
// scheduler group are organized in tree and on the bottom there are queues
// order matters in returning api
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::set_maximum_number_of_childs_per_scheduler_group()
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("set maximum number of childs per SG");
sai_attribute_t attr;
attr.id = SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_CHILDS_PER_SCHEDULER_GROUP;
attr.value.u32 = 8;
return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr);
}
sai_status_t SwitchMLNX2700::refresh_bridge_port_list(
_In_ const sai_attr_metadata_t *meta,
_In_ sai_object_id_t bridge_id)
{
SWSS_LOG_ENTER();
// XXX possible issues with vxlan and lag.
auto &all_bridge_ports = m_objectHash.at(SAI_OBJECT_TYPE_BRIDGE_PORT);
sai_attribute_t attr;
auto me_port_list = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE, SAI_BRIDGE_ATTR_PORT_LIST);
auto m_port_id = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE_PORT, SAI_BRIDGE_PORT_ATTR_PORT_ID);
auto m_bridge_id = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE_PORT, SAI_BRIDGE_PORT_ATTR_BRIDGE_ID);
/*
* First get all port's that belong to this bridge id.
*/
std::map<sai_object_id_t, SwitchState::AttrHash> bridge_port_list_on_bridge_id;
for (const auto &bp: all_bridge_ports)
{
auto it = bp.second.find(m_bridge_id->attridname);
if (it == bp.second.end())
{
continue;
}
if (bridge_id == it->second->getAttr()->value.oid)
{
/*
* This bridge port belongs to currently processing bridge ID.
*/
sai_object_id_t bridge_port;
sai_deserialize_object_id(bp.first, bridge_port);
bridge_port_list_on_bridge_id[bridge_port] = bp.second;
}
}
/*
* Now sort those bridge port id's by port id to be consistent.
*/
std::vector<sai_object_id_t> bridge_port_list;
for (const auto &p: m_port_list)
{
for (const auto &bp: bridge_port_list_on_bridge_id)
{
auto it = bp.second.find(m_port_id->attridname);
if (it == bp.second.end())
{
SWSS_LOG_THROW("bridge port is missing %s, not supported yet, FIXME", m_port_id->attridname);
}
if (p == it->second->getAttr()->value.oid)
{
bridge_port_list.push_back(bp.first);
}
}
}
if (bridge_port_list_on_bridge_id.size() != bridge_port_list.size())
{
SWSS_LOG_THROW("filter by port id failed size on lists is different: %zu vs %zu",
bridge_port_list_on_bridge_id.size(),
bridge_port_list.size());
}
/* default 1q router at the end */
bridge_port_list.push_back(m_default_bridge_port_1q_router);
/*
SAI_BRIDGE_PORT_ATTR_BRIDGE_ID: oid:0x100100000039
SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE: SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW
SAI_BRIDGE_PORT_ATTR_PORT_ID: oid:0x1010000000001
SAI_BRIDGE_PORT_ATTR_TYPE: SAI_BRIDGE_PORT_TYPE_PORT
*/
uint32_t bridge_port_list_count = (uint32_t)bridge_port_list.size();
SWSS_LOG_NOTICE("recalculated %s: %u", me_port_list->attridname, bridge_port_list_count);
attr.id = SAI_BRIDGE_ATTR_PORT_LIST;
attr.value.objlist.count = bridge_port_list_count;
attr.value.objlist.list = bridge_port_list.data();
return set(SAI_OBJECT_TYPE_BRIDGE, bridge_id, &attr);
}
sai_status_t SwitchMLNX2700::warm_update_queues()
{
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 queues list on current port
attr.id = SAI_PORT_ATTR_QOS_QUEUE_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 queue: list)
{
attr.id = SAI_QUEUE_ATTR_PORT;
if (get(SAI_OBJECT_TYPE_QUEUE, queue, 1, &attr) != SAI_STATUS_SUCCESS)
{
attr.value.oid = port;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue, &attr));
}
attr.id = SAI_QUEUE_ATTR_INDEX;
if (get(SAI_OBJECT_TYPE_QUEUE, queue, 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_QUEUE, queue, &attr));
}
// TODO add type
index++;
}
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::queryVlanfloodTypeCapability(
_Inout_ sai_s32_list_t *enum_values_capability)
{
SWSS_LOG_ENTER();
if (enum_values_capability->count < 4)
{
return SAI_STATUS_BUFFER_OVERFLOW;
}
enum_values_capability->count = 4;
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;
enum_values_capability->list[3] = SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED;
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::queryTunnelPeerModeCapability(
_Inout_ sai_s32_list_t *enum_values_capability)
{
SWSS_LOG_ENTER();
if (enum_values_capability->count < 1)
{
return SAI_STATUS_BUFFER_OVERFLOW;
}
enum_values_capability->count = 1;
enum_values_capability->list[0] = SAI_TUNNEL_PEER_MODE_P2MP;
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::queryPortAutonegFecOverrideSupportCapability(
_Out_ sai_attr_capability_t *attr_capability)
{
SWSS_LOG_ENTER();
attr_capability->create_implemented = true;
attr_capability->set_implemented = true;
attr_capability->get_implemented = true;
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::create_port_serdes()
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("currently not used");
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchMLNX2700::create_port_serdes_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("currently not used");
return SAI_STATUS_SUCCESS;
}