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; }