vslib/SwitchBCM56971B0.cpp (320 lines of code) (raw):
#include "SwitchBCM56971B0.h"
#include "swss/logger.h"
#include "meta/sai_serialize.h"
using namespace saivs;
SwitchBCM56971B0::SwitchBCM56971B0(
_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
}
SwitchBCM56971B0::SwitchBCM56971B0(
_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 SwitchBCM56971B0::create_qos_queues_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
sai_attribute_t attr;
// 10 in and 10 out queues per port
const uint32_t port_qos_queues_count = 20;
std::vector<sai_object_id_t> queues;
for (uint32_t i = 0; i < port_qos_queues_count; ++i)
{
sai_object_id_t queue_id;
CHECK_STATUS(create(SAI_OBJECT_TYPE_QUEUE, &queue_id, m_switch_id, 0, NULL));
queues.push_back(queue_id);
attr.id = SAI_QUEUE_ATTR_TYPE;
attr.value.s32 = (i < port_qos_queues_count / 2) ? SAI_QUEUE_TYPE_UNICAST : SAI_QUEUE_TYPE_MULTICAST;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &attr));
attr.id = SAI_QUEUE_ATTR_INDEX;
attr.value.u8 = (uint8_t)i;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &attr));
attr.id = SAI_QUEUE_ATTR_PORT;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &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 SwitchBCM56971B0::create_cpu_qos_queues(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
sai_attribute_t attr;
// CPU queues are of type multicast queues
const uint32_t port_qos_queues_count = 32;
std::vector<sai_object_id_t> queues;
for (uint32_t i = 0; i < port_qos_queues_count; ++i)
{
sai_object_id_t queue_id;
CHECK_STATUS(create(SAI_OBJECT_TYPE_QUEUE, &queue_id, m_switch_id, 0, NULL));
queues.push_back(queue_id);
attr.id = SAI_QUEUE_ATTR_TYPE;
attr.value.s32 = SAI_QUEUE_TYPE_MULTICAST;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &attr));
attr.id = SAI_QUEUE_ATTR_INDEX;
attr.value.u8 = (uint8_t)i;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &attr));
attr.id = SAI_QUEUE_ATTR_PORT;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue_id, &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 SwitchBCM56971B0::create_qos_queues()
{
SWSS_LOG_ENTER();
// XXX queues size may change when we will modify queue or ports
SWSS_LOG_INFO("create qos queues");
for (auto &port_id: m_port_list)
{
CHECK_STATUS(create_qos_queues_per_port(port_id));
}
CHECK_STATUS(create_cpu_qos_queues(m_cpu_port_id));
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchBCM56971B0::create_port_serdes()
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("create port serdes for all ports");
for (auto &port_id: m_port_list)
{
CHECK_STATUS(create_port_serdes_per_port(port_id));
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchBCM56971B0::create_port_serdes_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
sai_object_id_t port_serdes_id;
sai_attribute_t attr;
// create port serdes fir specific port
attr.id = SAI_PORT_SERDES_ATTR_PORT_ID;
attr.value.oid = port_id;
CHECK_STATUS(create(SAI_OBJECT_TYPE_PORT_SERDES, &port_serdes_id, m_switch_id, 1, &attr));
// set port serdes read only value
attr.id = SAI_PORT_ATTR_PORT_SERDES_ID;
attr.value.oid = port_serdes_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_PORT, port_id, &attr));
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchBCM56971B0::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;
// in this implementation we have 20 queues per port
// (10 in and 10 out), which will be assigned to schedulers
uint32_t queues_count = 20;
queues.resize(queues_count);
attrq.id = SAI_PORT_ATTR_QOS_QUEUE_LIST;
attrq.value.objlist.count = queues_count;
attrq.value.objlist.list = queues.data();
// NOTE it will do recalculate
CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attrq));
// in this platform we have 11
// schedulers groups: 0 1 2 3 4 5 6 7 8 9 a
// tree index
// 0 = 1 2 3 4 5 6 7 8 9 a
// 1..a - have both QUEUES, each one 2
uint32_t queue_index = 0;
// scheduler group 0 (10 groups)
{
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 = 10;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, sg_0, &attr));
uint32_t list_count = 10;
std::vector<sai_object_id_t> list;
for (int i = 1; i <= 0xa; i++)
{
list.push_back(sgs.at(i));
}
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 (size_t i = 0; i < list.size(); ++i)
{
sai_object_id_t childs[2];
// 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
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST;
attr.value.objlist.count = 2;
attr.value.objlist.list = childs;
queue_index++;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, list.at(i), &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT;
attr.value.u32 = 2;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, list.at(i), &attr));
attr.id = SAI_SCHEDULER_GROUP_ATTR_PORT_ID;
attr.value.oid = port_id;
CHECK_STATUS(set(SAI_OBJECT_TYPE_SCHEDULER_GROUP, list.at(i), &attr));
}
}
return SAI_STATUS_SUCCESS;
}
sai_status_t SwitchBCM56971B0::create_scheduler_groups_per_port(
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();
uint32_t port_sgs_count = 11; // brcm default
// NOTE: this is only static data, to keep track of this
// we would need to create actual objects and keep them
// in respected objects, we need to move in to that
// solution when we will start using different "profiles"
// currently this is good enough
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 SwitchBCM56971B0::set_maximum_number_of_childs_per_scheduler_group()
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("create switch src mac address");
sai_attribute_t attr;
attr.id = SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_CHILDS_PER_SCHEDULER_GROUP;
attr.value.u32 = 16;
return set(SAI_OBJECT_TYPE_SWITCH, m_switch_id, &attr);
}
sai_status_t SwitchBCM56971B0::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);
auto m_type = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BRIDGE_PORT, SAI_BRIDGE_PORT_ATTR_TYPE);
/*
* First get all port's that belong to this bridge id.
*/
attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID;
CHECK_STATUS(get(SAI_OBJECT_TYPE_SWITCH, m_switch_id, 1, &attr));
/*
* Create bridge ports for regular ports.
*/
sai_object_id_t default_1q_bridge_id = attr.value.oid;
std::map<sai_object_id_t, SwitchState::AttrHash> bridge_port_list_on_bridge_id;
// update default bridge port id's for bridge port if attr type is missing
for (const auto &bp: all_bridge_ports)
{
auto it = bp.second.find(m_type->attridname);
if (it == bp.second.end())
continue;
if (it->second->getAttr()->value.s32 != SAI_BRIDGE_PORT_TYPE_PORT)
continue;
it = bp.second.find(m_bridge_id->attridname);
if (it != bp.second.end())
continue;
// this bridge port is type PORT, and it's missing BRIDGE_ID attr
SWSS_LOG_NOTICE("setting default bridge id (%s) on bridge port %s",
sai_serialize_object_id(default_1q_bridge_id).c_str(),
bp.first.c_str());
attr.id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID;
attr.value.oid = default_1q_bridge_id;
sai_object_id_t bridge_port;
sai_deserialize_object_id(bp.first, bridge_port);
CHECK_STATUS(set(SAI_OBJECT_TYPE_BRIDGE_PORT, bridge_port, &attr));
}
// will contain 1q router bridge port, which we want to skip?
for (const auto &bp: all_bridge_ports)
{
auto it = bp.second.find(m_bridge_id->attridname);
if (it == bp.second.end())
{
// fine on router 1q
SWSS_LOG_NOTICE("not found %s on bridge port: %s", m_bridge_id->attridname, bp.first.c_str());
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());
}
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 SwitchBCM56971B0::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;
size_t port_qos_queues_count = list.size();
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));
}
attr.id = SAI_QUEUE_ATTR_TYPE;
if (get(SAI_OBJECT_TYPE_QUEUE, queue, 1, &attr) != SAI_STATUS_SUCCESS)
{
attr.value.s32 = (index < port_qos_queues_count / 2) ? SAI_QUEUE_TYPE_UNICAST : SAI_QUEUE_TYPE_MULTICAST;
CHECK_STATUS(set(SAI_OBJECT_TYPE_QUEUE, queue, &attr));
}
index++;
}
}
return SAI_STATUS_SUCCESS;
}