diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index ca3093f7239..13c9c79ee17 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -10,7 +10,7 @@ else DBGFLAGS = -g endif -orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp +orchagent_SOURCES = main.cpp orchdaemon.cpp orch.cpp routeorch.cpp neighorch.cpp intfsorch.cpp portsorch.cpp qosorch.cpp bufferorch.cpp orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) diff --git a/orchagent/bufferorch.cpp b/orchagent/bufferorch.cpp new file mode 100644 index 00000000000..2111e2327da --- /dev/null +++ b/orchagent/bufferorch.cpp @@ -0,0 +1,626 @@ +#include "sai.h" + +#include "bufferorch.h" +#include "logger.h" + +#include +#include + +extern sai_port_api_t *sai_port_api; +extern sai_queue_api_t *sai_queue_api; +extern sai_switch_api_t *sai_switch_api; +extern sai_buffer_api_t *sai_buffer_api; + +type_map BufferOrch::m_buffer_type_maps = { + {APP_BUFFER_POOL_TABLE_NAME, new object_map()}, + {APP_BUFFER_PROFILE_TABLE_NAME, new object_map()}, + {APP_BUFFER_QUEUE_TABLE_NAME, new object_map()}, + {APP_BUFFER_PG_TABLE_NAME, new object_map()}, + {APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, new object_map()}, + {APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, new object_map()} +}; + +BufferOrch::BufferOrch(DBConnector *db, vector &tableNames, PortsOrch *portsOrch) : + Orch(db, tableNames), m_portsOrch(portsOrch) +{ + SWSS_LOG_ENTER(); + initTableHandlers(); +}; + +void BufferOrch::initTableHandlers() +{ + SWSS_LOG_ENTER(); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_POOL_TABLE_NAME, &BufferOrch::processBufferPool)); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_PROFILE_TABLE_NAME, &BufferOrch::processBufferProfile)); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_QUEUE_TABLE_NAME, &BufferOrch::processQueue)); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_PG_TABLE_NAME, &BufferOrch::processPriorityGroup)); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, &BufferOrch::processIngressBufferProfileList)); + m_bufferHandlerMap.insert(buffer_handler_pair(APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, &BufferOrch::processEgressBufferProfileList)); +} + +task_process_status BufferOrch::processBufferPool(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object = SAI_NULL_OBJECT_ID; + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + string map_type_name = consumer.m_consumer->getTableName(); + string object_name = kfvKey(tuple); + string op = kfvOp(tuple); + + SWSS_LOG_DEBUG("object name:%s", object_name.c_str()); + if (map_type_name != APP_BUFFER_POOL_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", map_type_name.c_str(), APP_BUFFER_POOL_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + if (m_buffer_type_maps[map_type_name]->find(object_name) != m_buffer_type_maps[map_type_name]->end()) + { + sai_object = (*(m_buffer_type_maps[map_type_name]))[object_name]; + SWSS_LOG_DEBUG("found existing object:%s of type:%s", object_name.c_str(), map_type_name.c_str()); + } + SWSS_LOG_DEBUG("processing command:%s", op.c_str()); + if (op == SET_COMMAND) + { + std::vector attribs; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + SWSS_LOG_DEBUG("field:%s, value:%s", fvField(*i).c_str(), fvValue(*i).c_str()); + sai_attribute_t attr; + if (fvField(*i) == buffer_size_field_name) + { + attr.id = SAI_BUFFER_POOL_ATTR_SIZE; + attr.value.u32 = std::stoul(fvValue(*i)); + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_pool_type_field_name) + { + string type = fvValue(*i); + if (type == buffer_value_ingress) + { + attr.value.u32 = SAI_BUFFER_POOL_INGRESS; + } + else if (type == buffer_value_egress) + { + attr.value.u32 = SAI_BUFFER_POOL_EGRESS; + } + else + { + SWSS_LOG_ERROR("Unknown pool type specified:%s\n", type.c_str()); + return task_process_status::task_invalid_entry; + } + attr.id = SAI_BUFFER_POOL_ATTR_TYPE; + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_pool_mode_field_name) + { + string mode = fvValue(*i); + if (mode == buffer_pool_mode_dynamic_value) + { + attr.value.u32 = SAI_BUFFER_THRESHOLD_MODE_DYNAMIC; + } + else if (mode == buffer_pool_mode_static_value) + { + attr.value.u32 = SAI_BUFFER_THRESHOLD_MODE_STATIC; + } + else + { + SWSS_LOG_ERROR("Unknown pool mode specified:%s\n", mode.c_str()); + return task_process_status::task_invalid_entry; + } + attr.id = SAI_BUFFER_POOL_ATTR_TH_MODE; + attribs.push_back(attr); + } + else + { + SWSS_LOG_ERROR("Unknown pool field specified:%s, ignoring\n", fvField(*i).c_str()); + continue; + } + } + if (SAI_NULL_OBJECT_ID != sai_object) + { + SWSS_LOG_DEBUG("Modifying existing sai object:%llx ", sai_object); + sai_status = sai_buffer_api->set_buffer_pool_attr(sai_object, &attribs[0]); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to modify buffer pool, name:%s, sai object:%llx, status:%d", object_name.c_str(), sai_object, sai_status); + return task_process_status::task_failed; + } + SWSS_LOG_DEBUG("Modified existing pool:%llx, type:%s name:%s ", sai_object, map_type_name.c_str(), object_name.c_str()); + } + else + { + SWSS_LOG_DEBUG("Creating new sai object"); + sai_status = sai_buffer_api->create_buffer_pool(&sai_object, attribs.size(), attribs.data()); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create buffer pool, name:%s, status:%d", object_name.c_str(), sai_status); + return task_process_status::task_failed; + } + (*(m_buffer_type_maps[map_type_name]))[object_name] = sai_object; + SWSS_LOG_DEBUG("Created new pool:%llx, type:%s name:%s ", sai_object, map_type_name.c_str(), object_name.c_str()); + } + } + else if (op == DEL_COMMAND) + { + sai_status = sai_buffer_api->remove_buffer_pool(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove buffer pool, name:%s, sai object:%llx, status:%d", object_name.c_str(), sai_object, sai_status); + return task_process_status::task_failed; + } + auto it_to_delete = (m_buffer_type_maps[map_type_name])->find(object_name); + (m_buffer_type_maps[map_type_name])->erase(it_to_delete); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + return task_process_status::task_success; +} + +task_process_status BufferOrch::processBufferProfile(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object = SAI_NULL_OBJECT_ID; + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + string map_type_name = consumer.m_consumer->getTableName(); + string object_name = kfvKey(tuple); + string op = kfvOp(tuple); + + SWSS_LOG_DEBUG("object name:%s", object_name.c_str()); + if (map_type_name != APP_BUFFER_PROFILE_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", map_type_name.c_str(), APP_BUFFER_PROFILE_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + if (m_buffer_type_maps[map_type_name]->find(object_name) != m_buffer_type_maps[map_type_name]->end()) + { + sai_object = (*(m_buffer_type_maps[map_type_name]))[object_name]; + SWSS_LOG_DEBUG("found existing object:%s of type:%s", object_name.c_str(), map_type_name.c_str()); + } + SWSS_LOG_DEBUG("processing command:%s", op.c_str()); + if (op == SET_COMMAND) + { + std::vector attribs; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + SWSS_LOG_DEBUG("field:%s, value:%s", fvField(*i).c_str(), fvValue(*i).c_str()); + sai_attribute_t attr; + if (fvField(*i) == buffer_pool_field_name) + { + sai_object_id_t sai_pool; + ref_resolve_status resolve_result = resolveFieldRefValue(m_buffer_type_maps, buffer_pool_field_name, tuple, sai_pool); + if (ref_resolve_status::success != resolve_result) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid pool reference specified\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving pool reference failed\n"); + return task_process_status::task_failed; + } + attr.id = SAI_BUFFER_PROFILE_ATTR_POOL_ID; + attr.value.oid = sai_pool; + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_xon_field_name) + { + attr.value.u32 = std::stoul(fvValue(*i)); + attr.id = SAI_BUFFER_PROFILE_ATTR_XON_TH; + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_xoff_field_name) + { + attr.value.u32 = std::stoul(fvValue(*i)); + attr.id = SAI_BUFFER_PROFILE_ATTR_XOFF_TH; + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_size_field_name) + { + attr.id = SAI_BUFFER_PROFILE_ATTR_BUFFER_SIZE; + attr.value.u32 = std::stoul(fvValue(*i)); + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_dynamic_th_field_name) + { + attr.id = SAI_BUFFER_PROFILE_ATTR_SHARED_DYNAMIC_TH; + attr.value.u32 = std::stoul(fvValue(*i)); + attribs.push_back(attr); + } + else if (fvField(*i) == buffer_static_th_field_name) + { + attr.id = SAI_BUFFER_PROFILE_ATTR_SHARED_STATIC_TH; + attr.value.u32 = std::stoul(fvValue(*i)); + attribs.push_back(attr); + } + else + { + SWSS_LOG_ERROR("Unknown buffer profile field specified:%s, ignoring\n", fvField(*i).c_str()); + continue; + } + } + if (SAI_NULL_OBJECT_ID != sai_object) + { + SWSS_LOG_DEBUG("Modifying existing sai object:%llx ", sai_object); + sai_status = sai_buffer_api->set_buffer_profile_attr(sai_object, &attribs[0]); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to modify buffer profile, name:%s, sai object:%llx, status:%d", object_name.c_str(), sai_object, sai_status); + return task_process_status::task_failed; + } + } + else + { + SWSS_LOG_DEBUG("Creating new sai object"); + sai_status = sai_buffer_api->create_buffer_profile(&sai_object, attribs.size(), attribs.data()); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create buffer profile, name:%s, status:%d", object_name.c_str(), sai_status); + return task_process_status::task_failed; + } + (*(m_buffer_type_maps[map_type_name]))[object_name] = sai_object; + SWSS_LOG_DEBUG("Created new sai object:%llx, type:%s name:%s ", sai_object, map_type_name.c_str(), object_name.c_str()); + } + } + else if (op == DEL_COMMAND) + { + sai_status = sai_buffer_api->remove_buffer_profile(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove buffer profile, name:%s, sai object:%llx, status:%d", object_name.c_str(), sai_object, sai_status); + return task_process_status::task_failed; + } + auto it_to_delete = (m_buffer_type_maps[map_type_name])->find(object_name); + (m_buffer_type_maps[map_type_name])->erase(it_to_delete); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + return task_process_status::task_success; +} + +/* +Input sample "BUFFER_QUEUE_TABLE:Ethernet4,Ethernet45:10-15" +*/ +task_process_status BufferOrch::processQueue(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + sai_object_id_t sai_buffer_profile; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + vector tokens; + sai_uint32_t range_low, range_high; + + SWSS_LOG_DEBUG("Processing:%s", key.c_str()); + if (!tokenizeString(key, delimiter, tokens)) + { + return task_process_status::task_invalid_entry; + } + if (tokens.size() != 2) + { + SWSS_LOG_ERROR("malformed key:%s. Must contain 2 tokens\n", key.c_str()); + return task_process_status::task_invalid_entry; + } + if (consumer.m_consumer->getTableName() != APP_BUFFER_QUEUE_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_BUFFER_QUEUE_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + vector port_names; + if (!parseNameArray(tokens[0], port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + if (!parseIndexRange(tokens[1], range_low, range_high)) + { + return task_process_status::task_invalid_entry; + } + ref_resolve_status resolve_result = resolveFieldRefValue(m_buffer_type_maps, buffer_profile_field_name, tuple, sai_buffer_profile); + if (ref_resolve_status::success != resolve_result) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid queue buffer profile reference specified\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving queue profile reference failed\n"); + return task_process_status::task_failed; + } + sai_attribute_t attr; + attr.id = SAI_QUEUE_ATTR_BUFFER_PROFILE_ID; + attr.value.oid = sai_buffer_profile; + for (string port_name : port_names) + { + Port port; + SWSS_LOG_DEBUG("processing port:%s", port_name.c_str()); + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + for (size_t ind = range_low; ind <= range_high; ind++) + { + sai_object_id_t queue_id; + SWSS_LOG_DEBUG("processing queue:%d", ind); + if (!port.getQueue(ind, queue_id)) + { + SWSS_LOG_ERROR("Invalid queue index specified:%d", ind); + return task_process_status::task_invalid_entry; + } + SWSS_LOG_DEBUG("Applying buffer profile:0x%llx to queue index:%d, queue sai_id:0x%llx", sai_buffer_profile, ind, queue_id); + sai_status_t sai_status = sai_queue_api->set_queue_attribute(queue_id, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set queue's buffer profile attribute, status:%d", sai_status); + return task_process_status::task_failed; + } + } + } + return task_process_status::task_success; +} + +/* +Input sample "BUFFER_PG_TABLE:Ethernet4,Ethernet45:10-15" +*/ +task_process_status BufferOrch::processPriorityGroup(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + sai_object_id_t sai_buffer_profile; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + vector tokens; + sai_uint32_t range_low, range_high; + + SWSS_LOG_DEBUG("processing:%s", key.c_str()); + if (!tokenizeString(key, delimiter, tokens)) + { + return task_process_status::task_invalid_entry; + } + if (tokens.size() != 2) + { + SWSS_LOG_ERROR("malformed key:%s. Must contain 2 tokens\n", key.c_str()); + return task_process_status::task_invalid_entry; + } + if (consumer.m_consumer->getTableName() != APP_BUFFER_PG_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_BUFFER_PG_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + vector port_names; + if (!parseNameArray(tokens[0], port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + if (!parseIndexRange(tokens[1], range_low, range_high)) + { + SWSS_LOG_ERROR("Failed to obtain pg range values"); + return task_process_status::task_invalid_entry; + } + ref_resolve_status resolve_result = resolveFieldRefValue(m_buffer_type_maps, buffer_profile_field_name, tuple, sai_buffer_profile); + if (ref_resolve_status::success != resolve_result) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid pg profile reference specified\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving pg profile reference failed\n"); + return task_process_status::task_failed; + } + sai_attribute_t attr; + attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE; + attr.value.oid = sai_buffer_profile; + for (string port_name : port_names) + { + Port port; + SWSS_LOG_DEBUG("processing port:%s", port_name.c_str()); + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + for (size_t ind = range_low; ind <= range_high; ind++) + { + sai_object_id_t pg_id; + SWSS_LOG_DEBUG("processing pg:%d", ind); + if (!port.getPG(ind, pg_id)) + { + SWSS_LOG_ERROR("Invalid pg index specified:%d", ind); + return task_process_status::task_invalid_entry; + } + SWSS_LOG_DEBUG("Applying buffer profile:0x%llx to port:%s pg index:%d, pg sai_id:0x%llx", sai_buffer_profile, port_name.c_str(), ind, pg_id); + sai_status_t sai_status = sai_buffer_api->set_ingress_priority_group_attr(pg_id, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set port:%s pg:%d buffer profile attribute, status:%d", port_name.c_str(), ind, sai_status); + return task_process_status::task_failed; + } + } + } + return task_process_status::task_success; +} + +/* +Input sample:"[BUFFER_PROFILE_TABLE:i_port.profile0],[BUFFER_PROFILE_TABLE:i_port.profile1]" +*/ +task_process_status BufferOrch::processIngressBufferProfileList(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + Port port; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + + SWSS_LOG_DEBUG("processing:%s", key.c_str()); + if (consumer.m_consumer->getTableName() != APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME); + return task_process_status::task_invalid_entry; + } + vector port_names; + if (!parseNameArray(key, port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + vector profile_list; + ref_resolve_status resolve_status = resolveFieldRefArray(m_buffer_type_maps, buffer_profile_list_field_name, tuple, profile_list); + if (ref_resolve_status::success != resolve_status) + { + if(ref_resolve_status::not_resolved == resolve_status) + { + SWSS_LOG_ERROR("Missing or invalid ingress buffer profile reference specified for:%s\n", key.c_str()); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Failed resolving ingress buffer profile reference specified for:%s\n", key.c_str()); + return task_process_status::task_failed; + } + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_QOS_INGRESS_BUFFER_PROFILE_LIST; + attr.value.objlist.count = profile_list.size(); + attr.value.objlist.list = profile_list.data(); + for (string port_name : port_names) + { + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + sai_status_t sai_status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set ingress buffer profile list on port, status:%d, key:%s", sai_status, port_name.c_str()); + return task_process_status::task_failed; + } + } + return task_process_status::task_success; +} + +/* +Input sample:"[BUFFER_PROFILE_TABLE:e_port.profile0],[BUFFER_PROFILE_TABLE:e_port.profile1]" +*/ +task_process_status BufferOrch::processEgressBufferProfileList(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + Port port; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + SWSS_LOG_DEBUG("processing:%s", key.c_str()); + if (consumer.m_consumer->getTableName() != APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME); + return task_process_status::task_invalid_entry; + } + vector port_names; + if (!parseNameArray(key, port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + vector profile_list; + ref_resolve_status resolve_status = resolveFieldRefArray(m_buffer_type_maps, buffer_profile_list_field_name, tuple, profile_list); + if (ref_resolve_status::success != resolve_status) + { + if(ref_resolve_status::not_resolved == resolve_status) + { + SWSS_LOG_ERROR("Missing or invalid egress buffer profile reference specified for:%s\n", key.c_str()); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Failed resolving egress buffer profile reference specified for:%s\n", key.c_str()); + return task_process_status::task_failed; + } + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_QOS_EGRESS_BUFFER_PROFILE_LIST; + attr.value.objlist.count = profile_list.size(); + attr.value.objlist.list = profile_list.data(); + for (string port_name : port_names) + { + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + sai_status_t sai_status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set egress buffer profile list on port, status:%d, key:%s", sai_status, port_name.c_str()); + return task_process_status::task_failed; + } + } + return task_process_status::task_success; +} + +void BufferOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + if (consumer.m_toSync.empty()) + { + return; + } + if (!m_portsOrch->isInitDone()) + { + return; + } + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple tuple = it->second; + string map_type_name = consumer.m_consumer->getTableName(); + if (m_buffer_type_maps.find(map_type_name) == m_buffer_type_maps.end()) + { + SWSS_LOG_ERROR("Unrecognised qos table encountered:%s\n", map_type_name.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + if (m_bufferHandlerMap.find(map_type_name) == m_bufferHandlerMap.end()) + { + SWSS_LOG_ERROR("No handler for key:%s found.\n", map_type_name.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + task_process_status task_status = (this->*(m_bufferHandlerMap[map_type_name]))(consumer); + switch(task_status) + { + case task_process_status::task_success : + it = consumer.m_toSync.erase(it); + break; + case task_process_status::task_invalid_entry: + SWSS_LOG_ERROR("Invalid buffer task item was encountered, removing from queue."); + dumpTuple(consumer, tuple); + it = consumer.m_toSync.erase(it); + break; + case task_process_status::task_failed: + SWSS_LOG_ERROR("Processing buffer task item failed, exiting."); + dumpTuple(consumer, tuple); + return; + case task_process_status::task_need_retry: + SWSS_LOG_ERROR("Processing buffer task item failed, will retry."); + dumpTuple(consumer, tuple); + it++; + break; + default: + SWSS_LOG_ERROR("Unknown task status: %d", task_status); + dumpTuple(consumer, tuple); + it = consumer.m_toSync.erase(it); + break; + } + } +} + diff --git a/orchagent/bufferorch.h b/orchagent/bufferorch.h new file mode 100644 index 00000000000..4bf7992a3df --- /dev/null +++ b/orchagent/bufferorch.h @@ -0,0 +1,46 @@ +#ifndef SWSS_BUFFORCH_H +#define SWSS_BUFFORCH_H + +#include +#include "orch.h" +#include "portsorch.h" + +const std::string buffer_size_field_name = "size"; +const std::string buffer_pool_type_field_name = "type"; +const std::string buffer_pool_mode_field_name = "mode"; +const std::string buffer_pool_field_name = "pool"; +const std::string buffer_xon_field_name = "xon"; +const std::string buffer_xoff_field_name = "xoff"; +const std::string buffer_dynamic_th_field_name = "dynamic_th"; +const std::string buffer_static_th_field_name = "static_th"; +const std::string buffer_profile_field_name = "profile"; +const std::string buffer_value_ingress = "ingress"; +const std::string buffer_value_egress = "egress"; +const std::string buffer_pool_mode_dynamic_value = "dynamic"; +const std::string buffer_pool_mode_static_value = "static"; +const std::string buffer_profile_list_field_name = "profile_list"; + +class BufferOrch : public Orch +{ +public: + BufferOrch(DBConnector *db, vector &tableNames, PortsOrch *portsOrch); + static type_map m_buffer_type_maps; +private: + typedef task_process_status (BufferOrch::*buffer_table_handler)(Consumer& consumer); + typedef std::map buffer_table_handler_map; + typedef std::pair buffer_handler_pair; + + virtual void doTask(Consumer& consumer); + void initTableHandlers(); + task_process_status processBufferPool(Consumer &consumer); + task_process_status processBufferProfile(Consumer &consumer); + task_process_status processQueue(Consumer &consumer); + task_process_status processPriorityGroup(Consumer &consumer); + task_process_status processIngressBufferProfileList(Consumer &consumer); + task_process_status processEgressBufferProfileList(Consumer &consumer); +private: + PortsOrch *m_portsOrch; + buffer_table_handler_map m_bufferHandlerMap; +}; +#endif /* SWSS_BUFFORCH_H */ + diff --git a/orchagent/main.cpp b/orchagent/main.cpp index 808436192e6..5459fba1d1a 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -31,6 +31,12 @@ sai_next_hop_api_t* sai_next_hop_api; sai_next_hop_group_api_t* sai_next_hop_group_api; sai_route_api_t* sai_route_api; sai_lag_api_t* sai_lag_api; +sai_queue_api_t* sai_queue_api; +sai_scheduler_api_t* sai_scheduler_api; +sai_scheduler_group_api_t* sai_scheduler_group_api; +sai_wred_api_t* sai_wred_api; +sai_qos_map_api_t* sai_qos_map_api; +sai_buffer_api_t* sai_buffer_api; map gProfileMap; sai_object_id_t gVirtualRouterId; @@ -84,6 +90,12 @@ void initSaiApi() sai_api_query(SAI_API_NEXT_HOP_GROUP, (void **)&sai_next_hop_group_api); sai_api_query(SAI_API_ROUTE, (void **)&sai_route_api); sai_api_query(SAI_API_LAG, (void **)&sai_lag_api); + sai_api_query(SAI_API_QUEUE, (void **)&sai_queue_api); + sai_api_query(SAI_API_SCHEDULER, (void **)&sai_scheduler_api); + sai_api_query(SAI_API_WRED, (void **)&sai_wred_api); + sai_api_query(SAI_API_QOS_MAPS, (void **)&sai_qos_map_api); + sai_api_query(SAI_API_BUFFERS, (void **)&sai_buffer_api); + sai_api_query(SAI_API_SCHEDULER_GROUP, (void **)&sai_scheduler_group_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_NOTICE); sai_log_set(SAI_API_VIRTUAL_ROUTER, SAI_LOG_NOTICE); @@ -96,6 +108,12 @@ void initSaiApi() sai_log_set(SAI_API_NEXT_HOP_GROUP, SAI_LOG_NOTICE); sai_log_set(SAI_API_ROUTE, SAI_LOG_NOTICE); sai_log_set(SAI_API_LAG, SAI_LOG_NOTICE); + sai_log_set(SAI_API_QUEUE, SAI_LOG_NOTICE); + sai_log_set(SAI_API_SCHEDULER, SAI_LOG_NOTICE); + sai_log_set(SAI_API_WRED, SAI_LOG_NOTICE); + sai_log_set(SAI_API_QOS_MAPS, SAI_LOG_NOTICE); + sai_log_set(SAI_API_BUFFERS, SAI_LOG_NOTICE); + sai_log_set(SAI_API_SCHEDULER_GROUP, SAI_LOG_NOTICE); } void initDiagShell() diff --git a/orchagent/orch.cpp b/orchagent/orch.cpp index 56bcb23d432..beb3d324e11 100644 --- a/orchagent/orch.cpp +++ b/orchagent/orch.cpp @@ -1,6 +1,9 @@ #include "orch.h" #include "logger.h" +#include +#include + using namespace swss; Orch::Orch(DBConnector *db, string tableName) : @@ -13,7 +16,8 @@ Orch::Orch(DBConnector *db, string tableName) : Orch::Orch(DBConnector *db, vector &tableNames) : m_db(db) { - for(auto it : tableNames) { + for(auto it : tableNames) + { Consumer consumer(new ConsumerTable(m_db, it)); m_consumerMap.insert(ConsumerMapPair(it, consumer)); } @@ -22,9 +26,8 @@ Orch::Orch(DBConnector *db, vector &tableNames) : Orch::~Orch() { delete(m_db); - for(auto &it : m_consumerMap) { + for(auto &it : m_consumerMap) delete it.second.m_consumer; - } } std::vector Orch::getSelectables() @@ -46,12 +49,21 @@ bool Orch::hasSelectable(ConsumerTable *selectable) const return false; } +void Orch::dumpTuple(Consumer &consumer, KeyOpFieldsValuesTuple &tuple) +{ + string debug_msg = "Table: " + consumer.m_consumer->getTableName() + " key: " + kfvKey(tuple) + " op: " + kfvOp(tuple); + for (auto i : kfvFieldsValues(tuple)) + debug_msg += " " + fvField(i) + ": " + fvValue(i); + SWSS_LOG_DEBUG("%s\n", debug_msg.c_str()); +} + bool Orch::execute(string tableName) { SWSS_LOG_ENTER(); auto consumer_it = m_consumerMap.find(tableName); - if(consumer_it == m_consumerMap.end()) { + if(consumer_it == m_consumerMap.end()) + { SWSS_LOG_ERROR("Unrecognized tableName:%s\n", tableName.c_str()); return false; } @@ -63,15 +75,10 @@ bool Orch::execute(string tableName) string key = kfvKey(new_data); string op = kfvOp(new_data); -#ifdef DEBUG - string debug = "Table : " + consumer.m_consumer.getTableName() + " key : " + kfvKey(new_data) + " op : " + kfvOp(new_data); - for (auto i : kfvFieldsValues(new_data)) - debug += " " + fvField(i) + " : " + fvValue(i); - SWSS_LOG_DEBUG("%s\n", debug.c_str()); -#endif + dumpTuple(consumer, new_data); /* If a new task comes or if a DEL task comes, we directly put it into consumer.m_toSync map */ - if ( consumer.m_toSync.find(key) == consumer.m_toSync.end() || op == DEL_COMMAND) + if(consumer.m_toSync.find(key) == consumer.m_toSync.end() || op == DEL_COMMAND) { consumer.m_toSync[key] = new_data; } @@ -93,7 +100,7 @@ bool Orch::execute(string tableName) while (iu != existing_values.end()) { string ofield = fvField(*iu); - if (field == ofield) + if(field == ofield) iu = existing_values.erase(iu); else iu++; @@ -103,17 +110,227 @@ bool Orch::execute(string tableName) consumer.m_toSync[key] = KeyOpFieldsValuesTuple(key, op, existing_values); } - if (!consumer.m_toSync.empty()) + if(!consumer.m_toSync.empty()) doTask(consumer); return true; } +bool Orch::tokenizeString(string str, const string &separator, vector &tokens) +{ + SWSS_LOG_ENTER(); + if(0 == separator.size()) + { + SWSS_LOG_ERROR("Invalid separator passed in:%s\n", separator.c_str()); + return false; + } + if(string::npos == str.find(separator)) + { + SWSS_LOG_DEBUG("Single token:'%s'", str.c_str()); + tokens.push_back(str); + return true; + } + istringstream ss(str); + string tmp; + while (getline(ss, tmp, separator[0])) + { + SWSS_LOG_DEBUG("extracted token:%s", tmp.c_str()); + tokens.push_back(tmp); + } + return true; +} + +/* +- Validates reference has proper format which is [table_name:object_name] +- validates table_name exists +- validates object with object_name exists +*/ +bool Orch::parseReference(type_map &type_maps, string &ref_in, string &type_name, string &object_name) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_DEBUG("input:%s", ref_in.c_str()); + if(ref_in.size() < 3) + { + SWSS_LOG_ERROR("invalid reference received:%s\n", ref_in.c_str()); + return false; + } + if((ref_in[0] != ref_start) && (ref_in[ref_in.size()-1] != ref_end)) + { + SWSS_LOG_ERROR("malformed reference:%s. Must be surrounded by [ ]\n", ref_in.c_str()); + return false; + } + string ref_content = ref_in.substr(1, ref_in.size() - 2); + vector tokens; + if(!tokenizeString(ref_content, delimiter, tokens)) + { + return false; + } + if(tokens.size() != 2) + { + SWSS_LOG_ERROR("malformed reference:%s. Must contain 2 tokens\n", ref_content.c_str()); + return false; + } + auto type_it = type_maps.find(tokens[0]); + if(type_it == type_maps.end()) + { + SWSS_LOG_ERROR("not recognized type:%s\n", tokens[0].c_str()); + return false; + } + auto obj_map = type_maps[tokens[0]]; + auto obj_it = obj_map->find(tokens[1]); + if(obj_it == obj_map->end()) + { + SWSS_LOG_ERROR("map:%s does not contain object with name:%s\n", tokens[0].c_str(), tokens[1].c_str()); + return false; + } + type_name = tokens[0]; + object_name = tokens[1]; + SWSS_LOG_DEBUG("parsed: type_name:%s, object_name:%s", type_name.c_str(), object_name.c_str()); + return true; +} + +ref_resolve_status Orch::resolveFieldRefValue( + type_map &type_maps, + const string &field_name, + KeyOpFieldsValuesTuple &tuple, + sai_object_id_t &sai_object) +{ + SWSS_LOG_ENTER(); + size_t count = 0; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + if(fvField(*i) == field_name) + { + SWSS_LOG_DEBUG("field:%s, value:%s", fvField(*i).c_str(), fvValue(*i).c_str()); + if(count > 1) + { + SWSS_LOG_ERROR("Singleton field with name:%s must have only 1 instance, actual count:%d\n", field_name.c_str(), count); + return ref_resolve_status::multiple_instances; + } + string ref_type_name, object_name; + if(!parseReference(type_maps, fvValue(*i), ref_type_name, object_name)) + { + return ref_resolve_status::not_resolved; + } + sai_object = (*(type_maps[ref_type_name]))[object_name]; + count++; + } + } + if(0 == count) + { + SWSS_LOG_NOTICE("field with name:%s not found\n", field_name.c_str()); + return ref_resolve_status::field_not_found; + } + return ref_resolve_status::success; +} + void Orch::doTask() { for(auto &it : m_consumerMap) { - if (!it.second.m_toSync.empty()) + if(!it.second.m_toSync.empty()) doTask(it.second); } } + +// example: [BUFFER_PROFILE_TABLE:e_port.profile0],[BUFFER_PROFILE_TABLE:e_port.profile1] +ref_resolve_status Orch::resolveFieldRefArray( + type_map &type_maps, + const string &field_name, + KeyOpFieldsValuesTuple &tuple, + vector &sai_object_arr) +{ + SWSS_LOG_ENTER(); + size_t count = 0; + sai_object_arr.clear(); + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + if(fvField(*i) == field_name) + { + if(count > 1) + { + SWSS_LOG_ERROR("Singleton field with name:%s must have only 1 instance, actual count:%d\n", field_name.c_str(), count); + return ref_resolve_status::multiple_instances; + } + string ref_type_name, object_name; + string list = fvValue(*i); + vector list_items; + if(list.find(list_item_delimiter) != string::npos) + { + if(!tokenizeString(list, list_item_delimiter, list_items)) + { + SWSS_LOG_ERROR("Failed to tokenize buffer profile list:%s\n", list.c_str()); + return ref_resolve_status::failure; + } + } + else + { + list_items.push_back(list); + } + for (size_t ind = 0; ind < list_items.size(); ind++) + { + if(!parseReference(type_maps, list_items[ind], ref_type_name, object_name)) + { + SWSS_LOG_ERROR("Failed to parse profile reference:%s\n", list_items[ind].c_str()); + return ref_resolve_status::not_resolved; + } + sai_object_id_t sai_obj = (*(type_maps[ref_type_name]))[object_name]; + SWSS_LOG_DEBUG("Resolved to sai_object:0x%llx, type:%s, name:%s", sai_obj, ref_type_name.c_str(), object_name.c_str()); + sai_object_arr.push_back(sai_obj); + } + count++; + } + } + if(0 == count) + { + SWSS_LOG_NOTICE("field with name:%s not found\n", field_name.c_str()); + return ref_resolve_status::field_not_found; + } + return ref_resolve_status::success; +} + +bool Orch::parseNameArray(const string &input, vector &port_names) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_DEBUG("input:%s", input.c_str()); + if(input.find(comma) == string::npos) + { + port_names.push_back(input); + return true; + } + return tokenizeString(input, list_item_delimiter, port_names); +} + +bool Orch::parseIndexRange(const string &input, sai_uint32_t &range_low, sai_uint32_t &range_high) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_DEBUG("input:%s", input.c_str()); + if(input.find(range_specifier) != string::npos) + { + vector range_values; + if(!tokenizeString(input, range_specifier, range_values)) + { + SWSS_LOG_ERROR("Failed to parse index in:%s\n", input.c_str()); + return false; + } + if(range_values.size() != 2) + { + SWSS_LOG_ERROR("malformed index range in:%s. Must contain 2 tokens\n", input.c_str()); + return false; + } + range_low = std::stoul(range_values[0]); + range_high = std::stoul(range_values[1]); + if(range_low >= range_high) + { + SWSS_LOG_ERROR("malformed index range in:%s. left value must be less than righ value.\n", input.c_str()); + return false; + } + } + else + { + range_low = range_high = std::stoul(input); + } + SWSS_LOG_DEBUG("resulting range:%d-%d", range_low, range_high); + return true; +} + diff --git a/orchagent/orch.h b/orchagent/orch.h index 1fc9553cb26..85ae562a258 100644 --- a/orchagent/orch.h +++ b/orchagent/orch.h @@ -15,6 +15,19 @@ extern "C" { using namespace std; using namespace swss; +const char ref_start = '['; +const char ref_end = ']'; +const std::string delimiter = ":"; +const std::string list_item_delimiter = ","; +const std::string comma = ","; +const std::string range_specifier = "-"; + +typedef std::map object_map; +typedef std::pair object_map_pair; + +typedef std::map type_map; +typedef std::pair type_map_pair; + typedef map SyncMap; struct Consumer { Consumer(ConsumerTable* consumer) :m_consumer(consumer) { } @@ -25,6 +38,23 @@ struct Consumer { typedef std::pair ConsumerMapPair; typedef map ConsumerMap; +typedef enum +{ + success, + field_not_found, + multiple_instances, + not_resolved, + failure +} ref_resolve_status; + +typedef enum +{ + task_success, + task_invalid_entry, + task_failed, + task_need_retry +} task_process_status; + class Orch { public: @@ -38,16 +68,31 @@ class Orch bool execute(string tableName); /* Iterate all consumers in m_consumerMap and run doTask(Consumer) */ void doTask(); -protected: - /* Run doTask against a specific consumer */ - virtual void doTask(Consumer &consumer) = 0; -private: - DBConnector *m_db; + void dumpTuple(Consumer &consumer, KeyOpFieldsValuesTuple &tuple); protected: ConsumerMap m_consumerMap; + /* Run doTask against a specific consumer */ + virtual void doTask(Consumer &consumer) = 0; + ref_resolve_status resolveFieldRefValue( + type_map &type_maps, + const string &field_name, + KeyOpFieldsValuesTuple &tuple, + sai_object_id_t &sai_object); + bool parseIndexRange(const string &input, sai_uint32_t &range_low, sai_uint32_t &range_high); + bool parseNameArray(const string &input, vector &port_names); + bool parseReference(type_map &type_maps, string &ref, string &table_name, string &object_name); + bool tokenizeString(string str, const string &separator, vector &tokens); + ref_resolve_status resolveFieldRefArray( + type_map &type_maps, + const string &field_name, + KeyOpFieldsValuesTuple &tuple, + vector &sai_object_arr); + +private: + DBConnector *m_db; }; #endif /* SWSS_ORCH_H */ diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index f7a817c7c37..1c22bed8ecc 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -28,7 +28,6 @@ OrchDaemon::~OrchDaemon() bool OrchDaemon::init() { SWSS_LOG_ENTER(); - m_applDb = new DBConnector(APPL_DB, "localhost", 6379, 0); vector ports_tables = { @@ -42,8 +41,28 @@ bool OrchDaemon::init() NeighOrch *neigh_orch = new NeighOrch(m_applDb, APP_NEIGH_TABLE_NAME, ports_orch); RouteOrch *route_orch = new RouteOrch(m_applDb, APP_ROUTE_TABLE_NAME, ports_orch, neigh_orch); - m_orchList = { ports_orch, intfs_orch, neigh_orch, route_orch }; + std::vector qos_tables = { + APP_TC_TO_QUEUE_MAP_TABLE_NAME, + APP_SCHEDULER_TABLE_NAME, + APP_DSCP_TO_TC_MAP_TABLE_NAME, + APP_QUEUE_TABLE_NAME, + APP_PORT_QOS_MAP_TABLE_NAME, + APP_WRED_PROFILE_TABLE_NAME + }; + QosOrch *qos_orch = new QosOrch(m_applDb, qos_tables, ports_orch); + + std::vector buffer_tables = { + APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME + }; + BufferOrch *buffer_orch = new BufferOrch(m_applDb, buffer_tables, ports_orch); + m_select = new Select(); + m_orchList = { ports_orch, intfs_orch, neigh_orch, route_orch, qos_orch, buffer_orch }; return true; } @@ -63,6 +82,7 @@ void OrchDaemon::start() int fd, ret; ret = m_select->select(&s, &fd, 1); + if (ret == Select::ERROR) { SWSS_LOG_NOTICE("Error: %s!\n", strerror(errno)); diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index dcb0a2f3f08..1b11819b879 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -10,6 +10,8 @@ #include "intfsorch.h" #include "neighorch.h" #include "routeorch.h" +#include "qosorch.h" +#include "bufferorch.h" using namespace swss; @@ -26,7 +28,6 @@ class OrchDaemon DBConnector *m_asicDb; std::vector m_orchList; - Select *m_select; Orch *getOrchByConsumer(ConsumerTable *c); diff --git a/orchagent/port.h b/orchagent/port.h index fab4aa39c06..eead44b05da 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -28,6 +28,9 @@ class Port Port(std::string alias, Type type) : m_alias(alias), m_type(type) {}; + bool getQueue(size_t queue_ind, sai_object_id_t &queue_id); + bool getPG(size_t pg_ind, sai_object_id_t &pg); + inline bool operator<(const Port &o) const { return m_alias< o.m_alias; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 242f8e420cd..9be49e1a573 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -15,6 +15,80 @@ extern sai_vlan_api_t *sai_vlan_api; extern sai_lag_api_t *sai_lag_api; extern sai_hostif_api_t* sai_hostif_api; +namespace swss { + +bool Port::getQueue(size_t queue_ind, sai_object_id_t &queue_id) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_QUEUES; + attr.value.u32 = 0; + sai_status_t status = sai_port_api->get_port_attribute(m_port_id, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get number of queues for port:%s status:%d\n", m_alias.c_str(), status); + return false; + } + + size_t no_of_queues = attr.value.u32; + if (no_of_queues <= queue_ind) { + SWSS_LOG_ERROR("queue index:%d exceeds range:%d\n", queue_ind, no_of_queues); + return false; + } + attr.id = SAI_PORT_ATTR_QOS_QUEUE_LIST; + attr.value.objlist.count = no_of_queues; + attr.value.objlist.list = new sai_object_id_t[no_of_queues]; + + /* Get queue list */ + status = sai_port_api->get_port_attribute(m_port_id, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("fail to call sai_port_api->get_port_attribute: port:%s, status:%d", m_alias.c_str(), status); + delete[] attr.value.objlist.list; + return false; + } + queue_id = attr.value.objlist.list[queue_ind]; + delete[] attr.value.objlist.list; + return true; +} + +bool Port::getPG(size_t pg_ind, sai_object_id_t &pg) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_NUMBER_OF_PRIORITY_GROUPS; + attr.value.u32 = 0; + sai_status_t status = sai_port_api->get_port_attribute(m_port_id, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get number of queues for port:%s, status:%d\n", m_alias.c_str(), status); + return false; + } + + size_t no_of_pgs = attr.value.u32; + if (no_of_pgs <= pg_ind) { + SWSS_LOG_ERROR("pg index:%d exceeds range:%d\n", pg_ind, no_of_pgs); + return false; + } + attr.id = SAI_PORT_ATTR_PRIORITY_GROUP_LIST; + attr.value.objlist.count = no_of_pgs; + attr.value.objlist.list = new sai_object_id_t[no_of_pgs]; + + /* Get pg list */ + status = sai_port_api->get_port_attribute(m_port_id, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("fail to call sai_port_api->get_port_attribute: port:%s, status:%d", m_alias.c_str(), status); + delete[] attr.value.objlist.list; + return false; + } + pg = attr.value.objlist.list[pg_ind]; + delete[] attr.value.objlist.list; + return true; +} + +} /* namespace swss */ + PortsOrch::PortsOrch(DBConnector *db, vector tableNames) : Orch(db, tableNames) { @@ -507,8 +581,6 @@ void PortsOrch::doLagTask(Consumer &consumer) void PortsOrch::doTask(Consumer &consumer) { - SWSS_LOG_ENTER(); - if (consumer.m_toSync.empty()) return; diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp new file mode 100644 index 00000000000..f4a21843065 --- /dev/null +++ b/orchagent/qosorch.cpp @@ -0,0 +1,968 @@ +#include "sai.h" + +#include "qosorch.h" +#include "logger.h" + +#include +#include + +extern sai_port_api_t *sai_port_api; +extern sai_queue_api_t *sai_queue_api; +extern sai_scheduler_api_t *sai_scheduler_api; +extern sai_wred_api_t *sai_wred_api; +extern sai_qos_map_api_t *sai_qos_map_api; +extern sai_scheduler_group_api_t *sai_scheduler_group_api; +extern sai_switch_api_t *sai_switch_api; + +type_map QosOrch::m_qos_type_maps = { + {APP_DSCP_TO_TC_MAP_TABLE_NAME, new object_map()}, + {APP_TC_TO_QUEUE_MAP_TABLE_NAME, new object_map()}, + {APP_SCHEDULER_TABLE_NAME, new object_map()}, + {APP_WRED_PROFILE_TABLE_NAME, new object_map()}, + {APP_PORT_QOS_MAP_TABLE_NAME, new object_map()}, + {APP_QUEUE_TABLE_NAME, new object_map()} +}; + +task_process_status QosMapHandler::processWorkItem(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + sai_object_id_t sai_object = SAI_NULL_OBJECT_ID; + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + string qos_object_name = kfvKey(tuple); + string qos_map_type_name = consumer.m_consumer->getTableName(); + string op = kfvOp(tuple); + + if (!isValidTable(qos_map_type_name)) + { + return task_process_status::task_invalid_entry; + } + + if (QosOrch::getTypeMap()[qos_map_type_name]->find(qos_object_name) != QosOrch::getTypeMap()[qos_map_type_name]->end()) + { + sai_object = (*(QosOrch::getTypeMap()[qos_map_type_name]))[qos_object_name]; + } + if (op == SET_COMMAND) + { + std::vector attributes; + if (!convertFieldValuesToAttributes(tuple, attributes)) + { + return task_process_status::task_invalid_entry; + } + if (SAI_NULL_OBJECT_ID != sai_object) + { + if (!modifyQosMap(sai_object, attributes)) + { + SWSS_LOG_ERROR("Failed to set settings to existing dscp_to_tc map. db name:%s sai object:%llx", + qos_object_name.c_str(), sai_object); + freeAttribResources(attributes); + return task_process_status::task_failed; + } + } + else { + sai_object = addQosMap(attributes); + if (sai_object == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Failed to create dscp_to_tc map. db name:%s", qos_object_name.c_str()); + freeAttribResources(attributes); + return task_process_status::task_failed; + } + (*(QosOrch::getTypeMap()[qos_map_type_name]))[qos_object_name] = sai_object; + } + freeAttribResources(attributes); + } + else if (op == DEL_COMMAND) + { + if (SAI_NULL_OBJECT_ID == sai_object) + { + SWSS_LOG_ERROR("Object with name:%s not found.\n", qos_object_name.c_str()); + return task_process_status::task_invalid_entry; + } + if (!removeQosMap(sai_object)) + { + SWSS_LOG_ERROR("Failed to remove dscp_to_tc map. db name:%s sai object:%llx", qos_object_name.c_str(), sai_object); + return task_process_status::task_failed; + } + auto it_to_delete = (QosOrch::getTypeMap()[qos_map_type_name])->find(qos_object_name); + (QosOrch::getTypeMap()[qos_map_type_name])->erase(it_to_delete); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + return task_process_status::task_success; +} + +void DscpToTcMapHandler::freeAttribResources(std::vector &attributes) +{ + SWSS_LOG_ENTER(); + delete[] attributes[0].value.qosmap.list; +} + +bool DscpToTcMapHandler::isValidTable(string &tableName) +{ + SWSS_LOG_ENTER(); + if (tableName != APP_DSCP_TO_TC_MAP_TABLE_NAME) + { + SWSS_LOG_ERROR("invalid table type passed in %s, expected:%s\n", tableName.c_str(), APP_DSCP_TO_TC_MAP_TABLE_NAME); + return false; + } + return true; +} +bool DscpToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_attribute_t list_attr; + sai_qos_map_list_t dscp_map_list; + dscp_map_list.count = kfvFieldsValues(tuple).size(); + dscp_map_list.list = new sai_qos_map_t[dscp_map_list.count]; + uint32_t ind = 0; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++) + { + dscp_map_list.list[ind].key.dscp = std::stoi(fvField(*i)); + dscp_map_list.list[ind].value.tc = std::stoi(fvValue(*i)); + SWSS_LOG_DEBUG("key.dscp:%d, value.tc:%d", dscp_map_list.list[ind].key.dscp, dscp_map_list.list[ind].value.tc); + } + list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + list_attr.value.qosmap.count = dscp_map_list.count; + list_attr.value.qosmap.list = dscp_map_list.list; + attributes.push_back(list_attr); + return true; +} +bool DscpToTcMapHandler::modifyQosMap(sai_object_id_t sai_object, std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status = sai_qos_map_api->set_qos_map_attribute(sai_object, &attributes[0]); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to modify dscp_to_tc map. status:%d", sai_status); + return false; + } + return true; +} +sai_object_id_t DscpToTcMapHandler::addQosMap(std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object; + sai_attribute_t qos_map_attrs[2]; + qos_map_attrs[0].id = SAI_QOS_MAP_ATTR_TYPE; + qos_map_attrs[0].value.u32 = SAI_QOS_MAP_DSCP_TO_TC; + qos_map_attrs[1].id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + qos_map_attrs[1].value.qosmap.count = attributes[0].value.qosmap.count; + qos_map_attrs[1].value.qosmap.list = attributes[0].value.qosmap.list; + sai_status = sai_qos_map_api->create_qos_map(&sai_object, 2, qos_map_attrs); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create dscp_to_tc map. status:%d", sai_status); + return SAI_NULL_OBJECT_ID; + } + SWSS_LOG_DEBUG("created QosMap object:%llx", sai_object); + return sai_object; +} +bool DscpToTcMapHandler::removeQosMap(sai_object_id_t sai_object) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_DEBUG("Removing QosMap object:%llx", sai_object); + sai_status_t sai_status = sai_qos_map_api->remove_qos_map(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove dscp_to_tc map. status:%d", sai_status); + return false; + } + return true; +} +task_process_status QosOrch::handleDscpToTcTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + DscpToTcMapHandler dscp_tc_handler; + return dscp_tc_handler.processWorkItem(consumer); +} + +void TcToQueueMapHandler::freeAttribResources(std::vector &attributes) +{ + SWSS_LOG_ENTER(); + delete[] attributes[0].value.qosmap.list; +} + +bool TcToQueueMapHandler::isValidTable(string &tableName) +{ + if (tableName != APP_TC_TO_QUEUE_MAP_TABLE_NAME) + { + SWSS_LOG_ERROR("invalid table type passed in %s, expected:%s\n", tableName.c_str(), APP_TC_TO_QUEUE_MAP_TABLE_NAME); + return false; + } + return true; +} +bool TcToQueueMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_attribute_t list_attr; + sai_qos_map_list_t tc_map_list; + tc_map_list.count = kfvFieldsValues(tuple).size(); + tc_map_list.list = new sai_qos_map_t[tc_map_list.count]; + uint32_t ind = 0; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++) + { + tc_map_list.list[ind].key.tc = std::stoi(fvField(*i)); + tc_map_list.list[ind].value.queue_index = std::stoi(fvValue(*i)); + } + list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + list_attr.value.qosmap.count = tc_map_list.count; + list_attr.value.qosmap.list = tc_map_list.list; + attributes.push_back(list_attr); + return true; +} + +bool TcToQueueMapHandler::modifyQosMap(sai_object_id_t sai_object, std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status = sai_qos_map_api->set_qos_map_attribute(sai_object, &attributes[0]); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to moify tc_to_queue map. status:%d", sai_status); + return false; + } + return true; +} + +sai_object_id_t TcToQueueMapHandler::addQosMap(std::vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object; + sai_attribute_t qos_map_attrs[2]; + qos_map_attrs[0].id = SAI_QOS_MAP_ATTR_TYPE; + qos_map_attrs[0].value.s32 = SAI_QOS_MAP_TC_TO_QUEUE; + qos_map_attrs[1].id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + qos_map_attrs[1].value.qosmap.count = attributes[0].value.qosmap.count; + qos_map_attrs[1].value.qosmap.list = attributes[0].value.qosmap.list; + sai_status = sai_qos_map_api->create_qos_map(&sai_object, 2, qos_map_attrs); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + return SAI_NULL_OBJECT_ID; + } + return sai_object; +} + +bool TcToQueueMapHandler::removeQosMap(sai_object_id_t sai_object) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status = sai_qos_map_api->remove_qos_map(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove tc_to_queue mapstatus%d", sai_status); + return false; + } + return true; +} + +task_process_status QosOrch::handleTcToQueueTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + TcToQueueMapHandler tc_queue_handler; + return tc_queue_handler.processWorkItem(consumer); +} + +void WredMapHandler::freeAttribResources(std::vector &attributes) +{ + SWSS_LOG_ENTER(); +} + +bool WredMapHandler::isValidTable(string &tableName) +{ + SWSS_LOG_ENTER(); + if (tableName != APP_WRED_PROFILE_TABLE_NAME) + { + SWSS_LOG_ERROR("invalid table type passed in %s, expected:%s\n", tableName.c_str(), APP_WRED_PROFILE_TABLE_NAME); + return false; + } + return true; +} +bool WredMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attribs) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + if (fvField(*i) == yellow_max_threshold_field_name) + { + attr.id = SAI_WRED_ATTR_YELLOW_ENABLE; + attr.value.booldata = true; + attribs.push_back(attr); + + attr.id = SAI_WRED_ATTR_YELLOW_MAX_THRESHOLD; + attr.value.s32 = std::stoi(fvValue(*i)); + attribs.push_back(attr); + + // set min threshold to the same value as MAX + attr.id = SAI_WRED_ATTR_YELLOW_MIN_THRESHOLD; + attr.value.s32 = std::stoi(fvValue(*i)); + attribs.push_back(attr); + } + else if (fvField(*i) == green_max_threshold_field_name) + { + attr.id = SAI_WRED_ATTR_GREEN_ENABLE; + attr.value.booldata = true; + attribs.push_back(attr); + + attr.id = SAI_WRED_ATTR_GREEN_MAX_THRESHOLD; + attr.value.s32 = std::stoi(fvValue(*i)); + attribs.push_back(attr); + + // set min threshold to the same value as MAX + attr.id = SAI_WRED_ATTR_GREEN_MIN_THRESHOLD; + attr.value.s32 = std::stoi(fvValue(*i)); + attribs.push_back(attr); + } + else { + SWSS_LOG_ERROR("Unkonwn wred profile field:%s", fvField(*i).c_str()); + return false; + } + } + return true; +} + +bool WredMapHandler::modifyQosMap(sai_object_id_t sai_object, std::vector &attribs) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + for (auto attr : attribs) + { + sai_status = sai_wred_api->set_wred_attribute(sai_object, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set wred profile attribute, id:%d, status:%d", attr.id, sai_status); + return false; + } + } + return true; +} + +sai_object_id_t WredMapHandler::addQosMap(std::vector &attribs_in) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object; + sai_attribute_t attr; + std::vector attrs; + + attr.id = SAI_WRED_ATTR_GREEN_DROP_PROBABILITY; + attr.value.s32 = 100; + attrs.push_back(attr); + + attr.id = SAI_WRED_ATTR_YELLOW_DROP_PROBABILITY; + attr.value.s32 = 100; + attrs.push_back(attr); + + attr.id = SAI_WRED_ATTR_ECN_MARK_ENABLE; + attr.value.booldata = true; + attrs.push_back(attr); + + for(auto attrib : attribs_in) + { + attrs.push_back(attrib); + } + sai_status = sai_wred_api->create_wred_profile(&sai_object, attrs.size(), attrs.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create wred profile: %d", sai_status); + return false; + } + return sai_object; +} +bool WredMapHandler::removeQosMap(sai_object_id_t sai_object) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_status = sai_wred_api->remove_wred_profile(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove scheduler profile, status:%d", sai_status); + return false; + } + return true; +} + +task_process_status QosOrch::handleWredProfileTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + WredMapHandler wred_handler; + return wred_handler.processWorkItem(consumer); +} + +QosOrch::QosOrch(DBConnector *db, vector &tableNames, PortsOrch *portsOrch) : + Orch(db, tableNames), m_portsOrch(portsOrch) +{ + SWSS_LOG_ENTER(); + initTableHandlers(); +}; + +type_map& QosOrch::getTypeMap() +{ + SWSS_LOG_ENTER(); + return m_qos_type_maps; +} + +void QosOrch::initTableHandlers() +{ + SWSS_LOG_ENTER(); + m_qos_handler_map.insert(qos_handler_pair(APP_DSCP_TO_TC_MAP_TABLE_NAME, &QosOrch::handleDscpToTcTable)); + m_qos_handler_map.insert(qos_handler_pair(APP_TC_TO_QUEUE_MAP_TABLE_NAME, &QosOrch::handleTcToQueueTable)); + m_qos_handler_map.insert(qos_handler_pair(APP_SCHEDULER_TABLE_NAME, &QosOrch::handleSchedulerTable)); + m_qos_handler_map.insert(qos_handler_pair(APP_QUEUE_TABLE_NAME, &QosOrch::handleQueueTable)); + m_qos_handler_map.insert(qos_handler_pair(APP_PORT_QOS_MAP_TABLE_NAME, &QosOrch::handlePortQosMapTable)); + m_qos_handler_map.insert(qos_handler_pair(APP_WRED_PROFILE_TABLE_NAME, &QosOrch::handleWredProfileTable)); +} + +task_process_status QosOrch::handleSchedulerTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object = SAI_NULL_OBJECT_ID; + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + string qos_map_type_name = consumer.m_consumer->getTableName(); + string qos_object_name = kfvKey(tuple); + string op = kfvOp(tuple); + + if (qos_map_type_name != APP_SCHEDULER_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", qos_map_type_name.c_str(), APP_SCHEDULER_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + if (m_qos_type_maps[qos_map_type_name]->find(qos_object_name) != m_qos_type_maps[qos_map_type_name]->end()) + { + sai_object = (*(m_qos_type_maps[qos_map_type_name]))[qos_object_name]; + if (sai_object == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Error sai_object must exist for key %s\n", qos_object_name.c_str()); + return task_process_status::task_invalid_entry; + } + } + if (op == SET_COMMAND) + { + std::vector sai_attr_list; + sai_attribute_t attr; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++) + { + if (fvField(*i) == scheduler_algo_type_field_name) + { + attr.id = SAI_SCHEDULER_ATTR_SCHEDULING_ALGORITHM; + if (fvValue(*i) == scheduler_algo_DWRR) + { + attr.value.s32 = SAI_SCHEDULING_DWRR; + } + else if (fvValue(*i) == scheduler_algo_WRR) + { + attr.value.s32 = SAI_SCHEDULING_WRR; + } + else if (fvValue(*i) == scheduler_algo_STRICT) + { + attr.value.s32 = SAI_SCHEDULING_STRICT; + } + else { + SWSS_LOG_ERROR("Unknown scheduler type value:%s", fvField(*i).c_str()); + return task_process_status::task_invalid_entry; + } + sai_attr_list.push_back(attr); + } + else if (fvField(*i) == scheduler_weight_field_name) + { + attr.id = SAI_SCHEDULER_ATTR_SCHEDULING_WEIGHT; + attr.value.s32 = std::stoi(fvValue(*i)); + sai_attr_list.push_back(attr); + } + else if (fvField(*i) == scheduler_priority_field_name) + { + // TODO: The meaning is to be able to adjus priority of the given scheduler group. + // However currently SAI model does not provide such ability. + } + else { + SWSS_LOG_ERROR("Unknown field:%s", fvField(*i).c_str()); + return task_process_status::task_invalid_entry; + } + if (SAI_NULL_OBJECT_ID != sai_object) + { + for (auto attr : sai_attr_list) + { + sai_status = sai_scheduler_api->set_scheduler_attribute(sai_object, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("fail to set scheduler attribute, id:%d", attr.id); + return task_process_status::task_failed; + } + } + } + else { + sai_status = sai_scheduler_api->create_scheduler_profile(&sai_object, sai_attr_list.size(), sai_attr_list.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("fail to call sai_scheduler_api->create_scheduler_profile: %d", sai_status); + return task_process_status::task_failed; + } + (*(m_qos_type_maps[qos_map_type_name]))[qos_object_name] = sai_object; + } + } + } + else if (op == DEL_COMMAND) + { + if (SAI_NULL_OBJECT_ID == sai_object) + { + SWSS_LOG_ERROR("Object with name:%s not found.\n", qos_object_name.c_str()); + return task_process_status::task_invalid_entry; + } + sai_status = sai_scheduler_api->remove_scheduler_profile(sai_object); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to remove scheduler profile. db name:%s sai object:%llx", qos_object_name.c_str(), sai_object); + return task_process_status::task_failed; + } + auto it_to_delete = (m_qos_type_maps[qos_map_type_name])->find(qos_object_name); + (m_qos_type_maps[qos_map_type_name])->erase(it_to_delete); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + return task_process_status::task_success; +} + + +bool QosOrch::applySchedulerToQueueSchedulerGroup(Port &port, size_t queue_ind, sai_object_id_t scheduler_profile_id) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t sai_status; + sai_object_id_t queue_id; + vector groups; + vector child_groups; + uint32_t groups_count = 0; + + if (!port.getQueue(queue_ind, queue_id)) + { + SWSS_LOG_ERROR("Invalid queue index specified:%d", queue_ind); + return false; + } + + /* Get max child groups count */ + attr.id = SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_CHILDS_PER_SCHEDULER_GROUP; + sai_status = sai_switch_api->get_switch_attribute(1, &attr); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to get number of childs per scheduler group for port:%s", port.m_alias.c_str()); + return false; + } + child_groups.resize(attr.value.u32); + + /* Get max sched groups count */ + attr.id = SAI_PORT_ATTR_QOS_NUMBER_OF_SCHEDULER_GROUPS; + sai_status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to get number of scheduler groups for port:%s", port.m_alias.c_str()); + return false; + } + + /* Get total groups list on the port */ + groups_count = attr.value.u32; + groups.resize(groups_count); + + attr.id = SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST; + attr.value.objlist.list = groups.data(); + attr.value.objlist.count = groups_count; + sai_status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to get scheduler group list for port:%s", port.m_alias.c_str()); + return false; + } + + /* Lookup groups to which queue belongs */ + for (uint32_t ii = 0; ii < groups_count ; ii++) + { + uint32_t child_count = 0; + + attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_COUNT;//Number of queues/groups childs added to scheduler group + sai_status = sai_scheduler_group_api->get_scheduler_group_attribute(groups[ii], 1, &attr); + child_count = attr.value.u32; + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to get child count for scheduler group:0x%llx of port:%s", groups[ii], port.m_alias.c_str()); + return false; + } + + attr.id = SAI_SCHEDULER_GROUP_ATTR_CHILD_LIST; + attr.value.objlist.list = child_groups.data(); + attr.value.objlist.count = child_count; + sai_status = sai_scheduler_group_api->get_scheduler_group_attribute(groups[ii], 1, &attr); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to get child list for scheduler group:0x%llx of port:%s", groups[ii], port.m_alias.c_str()); + return false; + } + + for (uint32_t jj = 0; jj < child_count; jj++) + { + if (child_groups[jj] != queue_id) + { + continue; + } + + attr.id = SAI_SCHEDULER_GROUP_ATTR_SCHEDULER_PROFILE_ID; + attr.value.oid = scheduler_profile_id; + sai_status = sai_scheduler_group_api->set_scheduler_group_attribute(groups[ii], &attr); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed applying scheduler profile:0x%llx to scheduler group:0x%llx, port:%s", scheduler_profile_id, groups[ii], port.m_alias.c_str()); + return false; + } + SWSS_LOG_DEBUG("port:%s, scheduler_profile_id:0x%llx applied to scheduler group:0x%llx", port.m_alias.c_str(), scheduler_profile_id, groups[ii]); + return true; + } + } + return false; +} + +bool QosOrch::applyWredProfileToQueue(Port &port, size_t queue_ind, sai_object_id_t sai_wred_profile) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t sai_status; + sai_object_id_t queue_id; + + if (!port.getQueue(queue_ind, queue_id)) + { + SWSS_LOG_ERROR("Invalid queue index specified:%d", queue_ind); + return false; + } + attr.id = SAI_QUEUE_ATTR_WRED_PROFILE_ID; + attr.value.oid = sai_wred_profile; + sai_status = sai_queue_api->set_queue_attribute(queue_id, &attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set queue attribute:%d", sai_status); + return false; + } + return true; +} + +task_process_status QosOrch::handleQueueTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + Port port; + bool result; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + size_t queue_ind = 0; + vector tokens; + + sai_uint32_t range_low, range_high; + vector port_names; + + ref_resolve_status resolve_result; + // sample "QUEUE_TABLE:ETHERNET4:1" + if (!tokenizeString(key, delimiter, tokens)) + { + SWSS_LOG_ERROR("Failed to tokenize string:%s\n", key.c_str()); + return task_process_status::task_invalid_entry; + } + if (tokens.size() != 2) + { + SWSS_LOG_ERROR("malformed key:%s. Must contain 2 tokens\n", key.c_str()); + return task_process_status::task_invalid_entry; + } + if (consumer.m_consumer->getTableName() != APP_QUEUE_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_QUEUE_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + if (!parseNameArray(tokens[0], port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + if (!parseIndexRange(tokens[1], range_low, range_high)) + { + SWSS_LOG_ERROR("Failed to parse range:%s", tokens[1].c_str()); + return task_process_status::task_invalid_entry; + } + for (string port_name : port_names) + { + Port port; + SWSS_LOG_DEBUG("processing port:%s", port_name.c_str()); + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + SWSS_LOG_DEBUG("processing range:%d-%d", range_low, range_high); + for (size_t ind = range_low; ind <= range_high; ind++) + { + queue_ind = ind; + SWSS_LOG_DEBUG("processing queue:%d", queue_ind); + sai_object_id_t sai_scheduler_profile; + resolve_result = resolveFieldRefValue(m_qos_type_maps, scheduler_field_name, tuple, sai_scheduler_profile); + if (ref_resolve_status::success == resolve_result) + { + if (op == SET_COMMAND) + { + result = applySchedulerToQueueSchedulerGroup(port, queue_ind, sai_scheduler_profile); + } + else if (op == DEL_COMMAND) + { + // NOTE: The map is un-bound from the port. But the map itself still exists. + result = applySchedulerToQueueSchedulerGroup(port, queue_ind, SAI_NULL_OBJECT_ID); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + if (!result) + { + SWSS_LOG_ERROR("Failed setting field:%s to port:%s, queue:%d, line:%d\n", scheduler_field_name.c_str(), port.m_alias.c_str(), queue_ind, __LINE__); + return task_process_status::task_failed; + } + SWSS_LOG_DEBUG("Applied scheduler to port:%s", port_name.c_str()); + } + else if (resolve_result != ref_resolve_status::field_not_found) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid scheduler reference\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving scheduler reference failed\n"); + return task_process_status::task_failed; + } + + sai_object_id_t sai_wred_profile; + resolve_result = resolveFieldRefValue(m_qos_type_maps, wred_profile_field_name, tuple, sai_wred_profile); + if (ref_resolve_status::success == resolve_result) + { + if (op == SET_COMMAND) + { + result = applyWredProfileToQueue(port, queue_ind, sai_wred_profile); + } + else if (op == DEL_COMMAND) + { + // NOTE: The map is un-bound from the port. But the map itself still exists. + result = applyWredProfileToQueue(port, queue_ind, SAI_NULL_OBJECT_ID); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + if (!result) + { + SWSS_LOG_ERROR("Failed setting field:%s to port:%s, queue:%d, line:%d\n", wred_profile_field_name.c_str(), port.m_alias.c_str(), queue_ind, __LINE__); + return task_process_status::task_failed; + } + SWSS_LOG_DEBUG("Applied wred profile to port:%s", port_name.c_str()); + } + else if (resolve_result != ref_resolve_status::field_not_found) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid wred reference\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving wred reference failed\n"); + return task_process_status::task_failed; + } + } + } + SWSS_LOG_DEBUG("finished"); + return task_process_status::task_success; +} + +bool QosOrch::applyMapToPort(Port &port, sai_attr_id_t attr_id, sai_object_id_t map) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t sai_status; + attr.id = attr_id; + attr.value.oid = map; + if (SAI_STATUS_SUCCESS != (sai_status = sai_port_api->set_port_attribute(port.m_port_id, &attr))) + { + SWSS_LOG_ERROR("Failed setting sai object:%llx for port:%s, status:%s\n", map, port.m_alias.c_str(), sai_status); + return false; + } + return true; +} + +task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + KeyOpFieldsValuesTuple tuple = it->second; + Port port; + string key = kfvKey(tuple); + string op = kfvOp(tuple); + bool result = true; + sai_object_id_t sai_object; + sai_port_attr_t port_attr; + vector port_names; + //"PORT_QOS_MAP_TABLE:ETHERNET4 + if (consumer.m_consumer->getTableName() != APP_PORT_QOS_MAP_TABLE_NAME) + { + SWSS_LOG_ERROR("Key with invalid table type passed in %s, expected:%s\n", key.c_str(), APP_PORT_QOS_MAP_TABLE_NAME); + return task_process_status::task_invalid_entry; + } + if (!parseNameArray(key, port_names)) + { + SWSS_LOG_ERROR("Failed to obtain port names"); + return task_process_status::task_invalid_entry; + } + + for (string port_name : port_names) + { + Port port; + SWSS_LOG_DEBUG("processing port:%s", port_name.c_str()); + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found\n", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + + port_attr = SAI_PORT_ATTR_QOS_DSCP_TO_TC_MAP; + ref_resolve_status resolve_result = resolveFieldRefValue(m_qos_type_maps, dscp_to_tc_field_name, tuple, sai_object); + if (ref_resolve_status::success == resolve_result) + { + if (op == SET_COMMAND) + { + result = applyMapToPort(port, port_attr, sai_object); + } + else if (op == DEL_COMMAND) + { + // NOTE: The map is un-bound from the port. But the map itself still exists. + result = applyMapToPort(port, port_attr, SAI_NULL_OBJECT_ID); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + if (!result) + { + SWSS_LOG_ERROR("Failed setting field:%s to port:%s, line:%d\n", dscp_to_tc_field_name.c_str(), port.m_alias.c_str(), __LINE__); + return task_process_status::task_failed; + } + SWSS_LOG_DEBUG("Applied field:%s to port:%s, line:%d\n", dscp_to_tc_field_name.c_str(), port.m_alias.c_str(), __LINE__); + } + else if (resolve_result != ref_resolve_status::field_not_found) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid dscp_to_tc reference\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving dscp_to_tc reference failed\n"); + return task_process_status::task_failed; + } + + port_attr = SAI_PORT_ATTR_QOS_TC_TO_QUEUE_MAP; + resolve_result = resolveFieldRefValue(m_qos_type_maps, tc_to_queue_field_name, tuple, sai_object); + if (ref_resolve_status::success == resolve_result) + { + if (op == SET_COMMAND) + { + result = applyMapToPort(port, port_attr, sai_object); + } + else if (op == DEL_COMMAND) + { + // NOTE: The map is un-bound from the port. But the map itself still exists. + result = applyMapToPort(port, port_attr, SAI_NULL_OBJECT_ID); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str()); + return task_process_status::task_invalid_entry; + } + if (!result) + { + SWSS_LOG_ERROR("Failed setting field:%s to port:%s, line:%d\n", tc_to_queue_field_name.c_str(), port.m_alias.c_str(), __LINE__); + return task_process_status::task_failed; + } + SWSS_LOG_DEBUG("Applied field:%s to port:%s, line:%d\n", tc_to_queue_field_name.c_str(), port.m_alias.c_str(), __LINE__); + } + else if (resolve_result != ref_resolve_status::field_not_found) + { + if(ref_resolve_status::not_resolved == resolve_result) + { + SWSS_LOG_ERROR("Missing or invalid tc_to_queue reference\n"); + return task_process_status::task_need_retry; + } + SWSS_LOG_ERROR("Resolving tc_to_queue reference failed\n"); + return task_process_status::task_failed; + } + } + return task_process_status::task_success; +} + +void QosOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + if (consumer.m_toSync.empty()) + { + return; + } + if (!m_portsOrch->isInitDone()) + { + return; + } + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple tuple = it->second; + // + // make sure table is recognized, and we have handler for it + // + string qos_map_type_name = consumer.m_consumer->getTableName(); + if (m_qos_type_maps.find(qos_map_type_name) == m_qos_type_maps.end()) + { + SWSS_LOG_ERROR("Unrecognised qos table encountered:%s\n", qos_map_type_name.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + if (m_qos_handler_map.find(qos_map_type_name) == m_qos_handler_map.end()) + { + SWSS_LOG_ERROR("No handler for key:%s found.\n", qos_map_type_name.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + task_process_status task_status = (this->*(m_qos_handler_map[qos_map_type_name]))(consumer); + switch(task_status) + { + case task_process_status::task_success : + dumpTuple(consumer, tuple); + it = consumer.m_toSync.erase(it); + SWSS_LOG_DEBUG("Successfully processed item, removing from queue."); + break; + case task_process_status::task_invalid_entry : + SWSS_LOG_ERROR("Invalid QOS task item was encountered, removing from queue."); + dumpTuple(consumer, tuple); + it = consumer.m_toSync.erase(it); + break; + case task_process_status::task_failed : + SWSS_LOG_ERROR("Processing QOS task item failed, exiting."); + dumpTuple(consumer, tuple); + return; + case task_process_status::task_need_retry : + SWSS_LOG_ERROR("Processing QOS task item failed, will retry."); + dumpTuple(consumer, tuple); + it++; + break; + default: + SWSS_LOG_ERROR("Invdalid resolve result."); + break; + } + } +} diff --git a/orchagent/qosorch.h b/orchagent/qosorch.h new file mode 100644 index 00000000000..5ce4320f07f --- /dev/null +++ b/orchagent/qosorch.h @@ -0,0 +1,96 @@ +#ifndef SWSS_QOSORCH_H +#define SWSS_QOSORCH_H + +#include +#include "orch.h" +#include "portsorch.h" + +const std::string tc_to_queue_field_name = "tc_to_queue_map"; +const std::string dscp_to_tc_field_name = "dscp_to_tc_map"; +const std::string scheduler_field_name = "scheduler"; +const std::string wred_profile_field_name = "wred_profile"; +const std::string yellow_max_threshold_field_name = "yellow_max_threshold"; +const std::string green_max_threshold_field_name = "green_max_threshold"; + +const std::string scheduler_algo_type_field_name = "type"; +const std::string scheduler_algo_DWRR = "DWRR"; +const std::string scheduler_algo_WRR = "WRR"; +const std::string scheduler_algo_STRICT = "STRICT"; +const std::string scheduler_weight_field_name = "weight"; +const std::string scheduler_priority_field_name = "priority"; + +class QosMapHandler +{ +public: + task_process_status processWorkItem(Consumer& consumer); + virtual bool isValidTable(string &tableName) = 0; + virtual bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes) = 0; + virtual void freeAttribResources(std::vector &attributes) = 0; + virtual bool modifyQosMap(sai_object_id_t, std::vector &attributes) = 0; + virtual sai_object_id_t addQosMap(std::vector &attributes) = 0; + virtual bool removeQosMap(sai_object_id_t sai_object) = 0; +}; + +class DscpToTcMapHandler : public QosMapHandler +{ +public: + bool isValidTable(string &tableName); + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes); + void freeAttribResources(std::vector &attributes); + bool modifyQosMap(sai_object_id_t, std::vector &attributes); + sai_object_id_t addQosMap(std::vector &attributes); + bool removeQosMap(sai_object_id_t sai_object); +}; + +class TcToQueueMapHandler : public QosMapHandler +{ +public: + bool isValidTable(string &tableName); + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes); + void freeAttribResources(std::vector &attributes); + bool modifyQosMap(sai_object_id_t, std::vector &attributes); + sai_object_id_t addQosMap(std::vector &attributes); + bool removeQosMap(sai_object_id_t sai_object); +}; + +class WredMapHandler : public QosMapHandler +{ +public: + bool isValidTable(string &tableName); + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, std::vector &attributes); + void freeAttribResources(std::vector &attributes); + bool modifyQosMap(sai_object_id_t, std::vector &attributes); + sai_object_id_t addQosMap(std::vector &attributes); + bool removeQosMap(sai_object_id_t sai_object); +}; + +class QosOrch : public Orch +{ +public: + QosOrch(DBConnector *db, vector &tableNames, PortsOrch *portsOrch); + + static type_map& getTypeMap(); + static type_map m_qos_type_maps; +private: + virtual void doTask(Consumer& consumer); + + typedef task_process_status (QosOrch::*qos_table_handler)(Consumer& consumer); + typedef std::map qos_table_handler_map; + typedef std::pair qos_handler_pair; + + void initTableHandlers(); + task_process_status handleDscpToTcTable(Consumer& consumer); + task_process_status handleTcToQueueTable(Consumer& consumer); + task_process_status handleSchedulerTable(Consumer& consumer); + task_process_status handleQueueTable(Consumer& consumer); + bool applyWredProfileToQueue(Port &port, size_t queue_ind, sai_object_id_t sai_wred_profile); + bool applySchedulerToQueueSchedulerGroup(Port &port, size_t queue_ind, sai_object_id_t scheduler_profile_id); + task_process_status handlePortQosMapTable(Consumer& consumer); + bool applyMapToPort(Port &port, sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map); + task_process_status handleWredProfileTable(Consumer& consumer); + +private: + PortsOrch *m_portsOrch; + qos_table_handler_map m_qos_handler_map; +}; +#endif /* SWSS_QOSORCH_H */ diff --git a/swssconfig/sample/buffer.config.json b/swssconfig/sample/buffer.config.json new file mode 100644 index 00000000000..e87d872d710 --- /dev/null +++ b/swssconfig/sample/buffer.config.json @@ -0,0 +1,158 @@ +[ + { + "BUFFER_POOL_TABLE:i_pool0": { + "size": "6422592", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:i_pool1": { + "size": "3014688", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:e_pool0": { + "size": "8254464", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:e_pool1": { + "size": "7304064", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:i_port.profile0": { + "pool":"[BUFFER_POOL_TABLE:i_pool0]", + "xon":"0", + "xoff":"0", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:i_port.profile1": { + "pool":"[BUFFER_POOL_TABLE:i_pool1]", + "xon":"0", + "xoff":"0", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:e_port.profile0": { + "pool":"[BUFFER_POOL_TABLE:e_pool0]", + "xon":"0", + "xoff":"0", + "size":"4096", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:e_port.profile1": { + "pool":"[BUFFER_POOL_TABLE:e_pool1]", + "xon":"0", + "xoff":"0", + "size":"1126", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:i_port.pg01.profile": { + "pool":"[BUFFER_POOL_TABLE:i_pool0]", + "xon":"0", + "xoff":"0", + "size":"0", + "dynamic_th":"3" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:i_port.pg34.profile": { + "pool":"[BUFFER_POOL_TABLE:i_pool1]", + "xon":"371", + "xoff":"371", + "size":"67430", + "dynamic_th":"1" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:tc01.profile": { + "pool":"[BUFFER_POOL_TABLE:e_pool0]", + "size":"0", + "dynamic_th":"1" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:tc34.profile": { + "pool":"[BUFFER_POOL_TABLE:e_pool1]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_INGRESS_PROFILE_LIST:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32": { + "profile_list" : "[BUFFER_PROFILE_TABLE:i_port.profile0],[BUFFER_PROFILE_TABLE:i_port.profile1]" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_EGRESS_PROFILE_LIST:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32": { + "profile_list" : "[BUFFER_PROFILE_TABLE:e_port.profile0],[BUFFER_PROFILE_TABLE:e_port.profile1]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:0": { + "profile" : "[BUFFER_PROFILE_TABLE:i_port.pg01.profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:1": { + "profile" : "[BUFFER_PROFILE_TABLE:i_port.pg01.profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:i_port.pg34.profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:0-1": { + "profile" : "[BUFFER_PROFILE_TABLE:tc01.profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:3": { + "profile" : "[BUFFER_PROFILE_TABLE:tc34.profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:Ethernet0,Ethernet72,Ethernet88,Ethernet108,Ethernet48,Ethernet28,Ethernet8,Ethernet20,Ethernet120,Ethernet40,Ethernet68,Ethernet76,Ethernet52,Ethernet84,Ethernet96,Ethernet124,Ethernet100,Ethernet112,Ethernet44,Ethernet116,Ethernet4,Ethernet92,Ethernet60,Ethernet64,Ethernet12,Ethernet80,Ethernet104,Ethernet56,Ethernet32:4": { + "profile" : "[BUFFER_PROFILE_TABLE:tc34.profile]" + }, + "OP": "SET" + } +] diff --git a/swssconfig/sample/qos.config.json b/swssconfig/sample/qos.config.json new file mode 100644 index 00000000000..690c25bb9c3 --- /dev/null +++ b/swssconfig/sample/qos.config.json @@ -0,0 +1,54 @@ +[ + { + "TC_TO_QUEUE_MAP_TABLE:AZURE": { + "5": "1", + "6": "1" + }, + "OP": "SET" + }, + { + "DSCP_TO_TC_MAP_TABLE:AZURE": { + "7":"5", + "6":"5", + "3":"3", + "8":"7", + "9":"8" + }, + "OP": "SET" + }, + { + "PORT_QOS_MAP_TABLE:Ethernet4": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP_TABLE:AZURE]", + "tc_to_queue_map": "[TC_TO_QUEUE_MAP_TABLE:AZURE]" + }, + "OP": "SET" + }, + { + "SCHEDULER_TABLE:SCAVENGER" : { + "type":"DWRR", + "weight": "35" + }, + "OP": "SET" + }, + { + "SCHEDULER_TABLE:BEST_EFFORT" : { + "type":"DWRR", + "weight": "44" + }, + "OP": "SET" + }, + { + "WRED_PROFILE_TABLE:AZURE" : { + "yellow_max_threshold":"200", + "green_max_threshold": "100" + }, + "OP": "SET" + }, + { + "QUEUE_TABLE:Ethernet4:1" : { + "scheduler" : "[SCHEDULER_TABLE:BEST_EFFORT]", + "wred_profile" : "[WRED_PROFILE_TABLE:AZURE]" + }, + "OP": "SET" + } +]