From 70b651ea28b34137395b29eec1910614f228eaed Mon Sep 17 00:00:00 2001 From: Stepan Blyschak Date: Mon, 16 Dec 2024 17:39:10 +0000 Subject: [PATCH] [BufferOrch] Use SAI bulk API to configure port, PG and queue Signed-off-by: Stepan Blyschak --- orchagent/bufferorch.cpp | 457 ++++++++++++++++++++++++++--- orchagent/bufferorch.h | 83 ++++++ tests/mock_tests/bufferorch_ut.cpp | 45 +++ 3 files changed, 546 insertions(+), 39 deletions(-) diff --git a/orchagent/bufferorch.cpp b/orchagent/bufferorch.cpp index fb38cfe447..0924419bfb 100644 --- a/orchagent/bufferorch.cpp +++ b/orchagent/bufferorch.cpp @@ -72,6 +72,11 @@ void BufferOrch::initTableHandlers() 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)); + + m_bufferFlushHandlerMap.insert(buffer_flush_handler_pair(APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, &BufferOrch::processIngressBufferProfileListBulk)); + m_bufferFlushHandlerMap.insert(buffer_flush_handler_pair(APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, &BufferOrch::processEgressBufferProfileListBulk)); + m_bufferFlushHandlerMap.insert(buffer_flush_handler_pair(APP_BUFFER_PG_TABLE_NAME, &BufferOrch::processPriorityGroupBulk)); + m_bufferFlushHandlerMap.insert(buffer_flush_handler_pair(APP_BUFFER_QUEUE_TABLE_NAME, &BufferOrch::processQueueBulk)); } void BufferOrch::initBufferReadyLists(DBConnector *applDb, DBConnector *confDb) @@ -861,6 +866,10 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) } } + m_queueBulk.emplace_back(); + auto& task = m_queueBulk.back(); + task.kofvs = tuple; + if (op == SET_COMMAND) { ref_resolve_status resolve_result = resolveFieldRefValue(m_buffer_type_maps, buffer_profile_field_name, @@ -940,6 +949,13 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) SWSS_LOG_ERROR("Port with alias:%s not found", port_name.c_str()); return task_process_status::task_invalid_entry; } + + task.ports.emplace_back(); + auto& portContext = task.ports.back(); + portContext.port_name = port_name; + portContext.local_port = local_port; + portContext.local_port_name = local_port_name; + for (size_t ind = range_low; ind <= range_high; ind++) { SWSS_LOG_DEBUG("processing queue:%zd", ind); @@ -971,10 +987,51 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) queue_id = port.m_queue_ids[ind]; } + portContext.queues.emplace_back(); + auto& queueContext = portContext.queues.back(); + if (need_update_sai) { SWSS_LOG_DEBUG("Applying buffer profile:0x%" PRIx64 " to queue index:%zd, queue sai_id:0x%" PRIx64, sai_buffer_profile, ind, queue_id); - sai_status_t sai_status = sai_queue_api->set_queue_attribute(queue_id, &attr); + } + + queueContext.queue_id = queue_id; + queueContext.attr = SaiAttrWrapper(SAI_OBJECT_TYPE_QUEUE, attr); + queueContext.counter_was_added = counter_was_added; + queueContext.counter_needs_to_add = counter_needs_to_add; + queueContext.index = ind; + queueContext.update_sai = need_update_sai; + } + } + + return task_process_status::task_success; +} + +task_process_status BufferOrch::processQueuePost(const QueueTask& task) +{ + SWSS_LOG_ENTER(); + + const auto& key = kfvKey(task.kofvs); + const auto& op = kfvOp(task.kofvs); + const auto tokens = tokenize(key, delimiter); + Port port; + + for (const auto& portContext: task.ports) + { + const auto& port_name = portContext.port_name; + if (!gPortsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + for (const auto& queueContext: portContext.queues) + { + const auto ind = queueContext.index; + + if (queueContext.update_sai) + { + const auto sai_status = queueContext.status; + if (sai_status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set queue's buffer profile attribute, status:%d", sai_status); @@ -991,14 +1048,14 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) { auto flexCounterOrch = gDirectory.get(); auto queues = tokens[1]; - if (!counter_was_added && counter_needs_to_add && + if (!queueContext.counter_was_added && queueContext.counter_needs_to_add && (flexCounterOrch->getQueueCountersState() || flexCounterOrch->getQueueWatermarkCountersState())) { SWSS_LOG_INFO("Creating counters for %s %zd", port_name.c_str(), ind); gPortsOrch->createPortBufferQueueCounters(port, queues); } - else if (counter_was_added && !counter_needs_to_add && - (flexCounterOrch->getQueueCountersState() || flexCounterOrch->getQueueWatermarkCountersState())) + else if (queueContext.counter_was_added && !queueContext.counter_needs_to_add && + (flexCounterOrch->getQueueCountersState() || flexCounterOrch->getQueueWatermarkCountersState())) { SWSS_LOG_INFO("Removing counters for %s %zd", port_name.c_str(), ind); gPortsOrch->removePortBufferQueueCounters(port, queues); @@ -1054,17 +1111,23 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) // should be applied to a physical port before the physical port is brought up to // carry traffic. Here, we alert to application through syslog when such a wrong // set order is detected. - for (const auto &port_name : port_names) + for (const auto &portContext : task.ports) { + const auto& port_name = portContext.port_name; + const auto& local_port_name = portContext.local_port_name; + const auto local_port = portContext.local_port; + if(local_port == true) { - if (gPortsOrch->isPortAdminUp(local_port_name)) { + if (gPortsOrch->isPortAdminUp(local_port_name)) + { SWSS_LOG_WARN("Queue profile '%s' applied after port %s is up", key.c_str(), port_name.c_str()); } } else { - if (gPortsOrch->isPortAdminUp(port_name)) { + if (gPortsOrch->isPortAdminUp(port_name)) + { SWSS_LOG_WARN("Queue profile '%s' applied after port %s is up", key.c_str(), port_name.c_str()); } } @@ -1074,6 +1137,64 @@ task_process_status BufferOrch::processQueue(KeyOpFieldsValuesTuple &tuple) return task_process_status::task_success; } +void BufferOrch::processQueueBulk(Consumer& consumer) +{ + std::vector oids; + std::vector attrs; + std::vector statuses; + + for (const auto& task: m_queueBulk) + { + for (const auto& port: task.ports) + for (const auto& queue: port.queues) + { + if (queue.update_sai) + { + oids.push_back(queue.queue_id); + attrs.push_back(queue.attr.getSaiAttr()); + statuses.push_back(SAI_STATUS_NOT_EXECUTED); + } + } + } + + const auto objectCount = static_cast(oids.size()); + + if (objectCount > 0) + { + SWSS_LOG_TIMER("Set %u queues buffer profile", objectCount); + + sai_queue_api->set_queues_attribute(objectCount, oids.data(), attrs.data(), + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statuses.data()); + } + + size_t i = 0; + for (auto& task: m_queueBulk) + { + for (auto& port: task.ports) + { + for (auto& queue: port.queues) + { + if (queue.update_sai) + { + queue.status = statuses[i]; + i++; + } + } + } + } + + for (const auto& task: m_queueBulk) + { + auto task_status = processQueuePost(task); + if (task_status == task_process_status::task_need_retry) + { + consumer.m_toSync.emplace(kfvKey(task.kofvs), task.kofvs); + } + } + + m_queueBulk.clear(); +} + /* Input sample "BUFFER_PG|Ethernet4,Ethernet45|10-15" */ @@ -1105,6 +1226,10 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup return task_process_status::task_invalid_entry; } + m_priorityGroupBulk.emplace_back(); + auto& task = m_priorityGroupBulk.back(); + task.kofvs = tuple; + if (op == SET_COMMAND) { ref_resolve_status resolve_result = resolveFieldRefValue(m_buffer_type_maps, buffer_profile_field_name, @@ -1169,6 +1294,11 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup SWSS_LOG_ERROR("Port with alias:%s not found", port_name.c_str()); return task_process_status::task_invalid_entry; } + + task.ports.emplace_back(); + auto& portContext = task.ports.back(); + portContext.port_name = port_name; + for (size_t ind = range_low; ind <= range_high; ind++) { SWSS_LOG_DEBUG("processing pg:%zd", ind); @@ -1179,38 +1309,79 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup } else { + portContext.pgs.emplace_back(); + auto& pgContext = portContext.pgs.back(); + + sai_object_id_t pg_id = port.m_priority_group_ids[ind]; + if (need_update_sai) { - sai_object_id_t pg_id; - pg_id = port.m_priority_group_ids[ind]; SWSS_LOG_DEBUG("Applying buffer profile:0x%" PRIx64 " to port:%s pg index:%zd, pg sai_id:0x%" PRIx64, sai_buffer_profile, port_name.c_str(), ind, pg_id); - sai_status_t sai_status = sai_buffer_api->set_ingress_priority_group_attribute(pg_id, &attr); - if (sai_status != SAI_STATUS_SUCCESS) + } + + pgContext.pg_id = pg_id; + pgContext.attr = SaiAttrWrapper(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, attr); + pgContext.counter_was_added = counter_was_added; + pgContext.counter_needs_to_add = counter_needs_to_add; + pgContext.index = ind; + pgContext.update_sai = need_update_sai; + } + } + } + + return task_process_status::task_success; +} + +task_process_status BufferOrch::processPriorityGroupPost(const PriorityGroupTask& task) +{ + SWSS_LOG_ENTER(); + + const auto& key = kfvKey(task.kofvs); + const auto& op = kfvOp(task.kofvs); + const auto tokens = tokenize(key, delimiter); + Port port; + + for (const auto& portContext: task.ports) + { + const auto& port_name = portContext.port_name; + if (!gPortsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Port with alias:%s not found", port_name.c_str()); + return task_process_status::task_invalid_entry; + } + for (const auto& pg: portContext.pgs) + { + const auto ind = pg.index; + + if (pg.update_sai) + { + const auto sai_status = pg.status; + + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set port:%s pg:%zd buffer profile attribute, status:%d", port_name.c_str(), ind, sai_status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_BUFFER, sai_status); + if (handle_status != task_process_status::task_success) { - SWSS_LOG_ERROR("Failed to set port:%s pg:%zd buffer profile attribute, status:%d", port_name.c_str(), ind, sai_status); - task_process_status handle_status = handleSaiSetStatus(SAI_API_BUFFER, sai_status); - if (handle_status != task_process_status::task_success) - { - return handle_status; - } + return handle_status; + } + } + // create or remove a port PG counter for the PG buffer + else + { + auto flexCounterOrch = gDirectory.get(); + auto pgs = tokens[1]; + if (!pg.counter_was_added && pg.counter_needs_to_add && + (flexCounterOrch->getPgCountersState() || flexCounterOrch->getPgWatermarkCountersState())) + { + SWSS_LOG_INFO("Creating counters for priority group %s %zd", port_name.c_str(), ind); + gPortsOrch->createPortBufferPgCounters(port, pgs); } - // create or remove a port PG counter for the PG buffer - else + else if (pg.counter_was_added && !pg.counter_needs_to_add && + (flexCounterOrch->getPgCountersState() || flexCounterOrch->getPgWatermarkCountersState())) { - auto flexCounterOrch = gDirectory.get(); - auto pgs = tokens[1]; - if (!counter_was_added && counter_needs_to_add && - (flexCounterOrch->getPgCountersState() || flexCounterOrch->getPgWatermarkCountersState())) - { - SWSS_LOG_INFO("Creating counters for priority group %s %zd", port_name.c_str(), ind); - gPortsOrch->createPortBufferPgCounters(port, pgs); - } - else if (counter_was_added && !counter_needs_to_add && - (flexCounterOrch->getPgCountersState() || flexCounterOrch->getPgWatermarkCountersState())) - { - SWSS_LOG_INFO("Removing counters for priority group %s %zd", port_name.c_str(), ind); - gPortsOrch->removePortBufferPgCounters(port, pgs); - } + SWSS_LOG_INFO("Removing counters for priority group %s %zd", port_name.c_str(), ind); + gPortsOrch->removePortBufferPgCounters(port, pgs); } } } @@ -1246,7 +1417,6 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup } /* save the last command (set or delete) */ pg_port_flags[port_name][ind] = op; - } } @@ -1263,9 +1433,11 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup // should be applied to a physical port before the physical port is brought up to // carry traffic. Here, we alert to application through syslog when such a wrong // set order is detected. - for (const auto &port_name : port_names) + for (const auto &portContext : task.ports) { - if (gPortsOrch->isPortAdminUp(port_name)) { + const auto& port_name = portContext.port_name; + if (gPortsOrch->isPortAdminUp(port_name)) + { SWSS_LOG_WARN("PG profile '%s' applied after port %s is up", key.c_str(), port_name.c_str()); } } @@ -1274,6 +1446,65 @@ task_process_status BufferOrch::processPriorityGroup(KeyOpFieldsValuesTuple &tup return task_process_status::task_success; } +void BufferOrch::processPriorityGroupBulk(Consumer& consumer) +{ + std::vector oids; + std::vector attrs; + std::vector statuses; + + for (const auto& task: m_priorityGroupBulk) + { + for (const auto& port: task.ports) + for (const auto& pg: port.pgs) + { + if (pg.update_sai) + { + oids.push_back(pg.pg_id); + attrs.push_back(pg.attr.getSaiAttr()); + statuses.push_back(SAI_STATUS_NOT_EXECUTED); + } + } + } + + const auto objectCount = static_cast(oids.size()); + + if (objectCount > 0) + { + SWSS_LOG_TIMER("Set %u ingress priority groups buffer profile", objectCount); + + sai_buffer_api->set_ingress_priority_groups_attribute(objectCount, oids.data(), attrs.data(), + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statuses.data()); + } + + size_t i = 0; + for (auto& task: m_priorityGroupBulk) + { + for (auto& port: task.ports) + { + for (auto& pg: port.pgs) + { + if (pg.update_sai) + { + pg.status = statuses[i]; + i++; + } + } + } + } + + for (const auto& task: m_priorityGroupBulk) + { + auto task_status = processPriorityGroupPost(task); + if (task_status == task_process_status::task_need_retry) + { + consumer.m_toSync.emplace(kfvKey(task.kofvs), task.kofvs); + } + } + + m_priorityGroupBulk.clear(); +} + + /* Input sample:"i_port.profile0,i_port.profile1" */ @@ -1333,6 +1564,9 @@ task_process_status BufferOrch::processIngressBufferProfileList(KeyOpFieldsValue SWSS_LOG_ERROR("Unknown command %s when handling BUFFER_PORT_INGRESS_PROFILE_LIST_TABLE key %s", op.c_str(), key.c_str()); } + PortBufferProfileListTask task; + task.kofvs = tuple; + for (string port_name : port_names) { if (!gPortsOrch->getPort(port_name, port)) @@ -1340,7 +1574,21 @@ task_process_status BufferOrch::processIngressBufferProfileList(KeyOpFieldsValue SWSS_LOG_ERROR("Port with alias:%s not found", 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); + + task.ports.emplace_back(PortBufferProfileListTask::PortContext{port_name, port.m_port_id, SaiAttrWrapper{SAI_OBJECT_TYPE_PORT, attr}, SAI_STATUS_NOT_EXECUTED}); + } + + m_portIngressBufferProfileListBulk.push_back(task); + + return task_process_status::task_success; +} + +task_process_status BufferOrch::processIngressBufferProfileListPost(const PortBufferProfileListTask& task) +{ + for (const auto& portContext: task.ports) + { + const auto& port_name = portContext.port_name; + sai_status_t sai_status = portContext.status; 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()); @@ -1355,6 +1603,54 @@ task_process_status BufferOrch::processIngressBufferProfileList(KeyOpFieldsValue return task_process_status::task_success; } +void BufferOrch::processIngressBufferProfileListBulk(Consumer& consumer) +{ + std::vector oids; + std::vector attrs; + std::vector statuses; + + for (const auto& task: m_portIngressBufferProfileListBulk) + { + for (const auto& port: task.ports) + { + oids.push_back(port.port_oid); + attrs.push_back(port.attr.getSaiAttr()); + statuses.push_back(SAI_STATUS_NOT_EXECUTED); + } + } + + const auto objectCount = static_cast(oids.size()); + + if (objectCount > 0) + { + SWSS_LOG_TIMER("Set %u ports ingress buffer profile list", objectCount); + + sai_port_api->set_ports_attribute(objectCount, oids.data(), attrs.data(), + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statuses.data()); + } + + size_t i = 0; + for (auto& task: m_portIngressBufferProfileListBulk) + { + for (auto& port: task.ports) + { + port.status = statuses[i]; + i++; + } + } + + for (const auto& task: m_portIngressBufferProfileListBulk) + { + auto task_status = processIngressBufferProfileListPost(task); + if (task_status == task_process_status::task_need_retry) + { + consumer.m_toSync.emplace(kfvKey(task.kofvs), task.kofvs); + } + } + + m_portIngressBufferProfileListBulk.clear(); +} + /* Input sample:"e_port.profile0,e_port.profile1" */ @@ -1412,6 +1708,9 @@ task_process_status BufferOrch::processEgressBufferProfileList(KeyOpFieldsValues SWSS_LOG_ERROR("Unknown command %s when handling BUFFER_PORT_EGRESS_PROFILE_LIST_TABLE key %s", op.c_str(), key.c_str()); } + PortBufferProfileListTask task; + task.kofvs = tuple; + for (string port_name : port_names) { if (!gPortsOrch->getPort(port_name, port)) @@ -1419,7 +1718,21 @@ task_process_status BufferOrch::processEgressBufferProfileList(KeyOpFieldsValues SWSS_LOG_ERROR("Port with alias:%s not found", 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); + + task.ports.emplace_back(PortBufferProfileListTask::PortContext{port_name, port.m_port_id, SaiAttrWrapper{SAI_OBJECT_TYPE_PORT, attr}, SAI_STATUS_NOT_EXECUTED}); + } + + m_portBufferProfileListBulk.push_back(task); + + return task_process_status::task_success; +} + +task_process_status BufferOrch::processEgressBufferProfileListPost(const PortBufferProfileListTask& task) +{ + for (const auto& portContext: task.ports) + { + const auto& port_name = portContext.port_name; + sai_status_t sai_status = portContext.status; 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()); @@ -1434,6 +1747,54 @@ task_process_status BufferOrch::processEgressBufferProfileList(KeyOpFieldsValues return task_process_status::task_success; } +void BufferOrch::processEgressBufferProfileListBulk(Consumer& consumer) +{ + std::vector oids; + std::vector attrs; + std::vector statuses; + + for (const auto& task: m_portBufferProfileListBulk) + { + for (const auto& port: task.ports) + { + oids.push_back(port.port_oid); + attrs.push_back(port.attr.getSaiAttr()); + statuses.push_back(SAI_STATUS_NOT_EXECUTED); + } + } + + const auto objectCount = static_cast(oids.size()); + + if (objectCount > 0) + { + SWSS_LOG_TIMER("Set %u ports egress buffer profile list", objectCount); + + sai_port_api->set_ports_attribute(objectCount, oids.data(), attrs.data(), + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statuses.data()); + } + + size_t i = 0; + for (auto& task: m_portBufferProfileListBulk) + { + for (auto& port: task.ports) + { + port.status = statuses[i]; + i++; + } + } + + for (const auto& task: m_portBufferProfileListBulk) + { + auto task_status = processEgressBufferProfileListPost(task); + if (task_status == task_process_status::task_need_retry) + { + consumer.m_toSync.emplace(kfvKey(task.kofvs), task.kofvs); + } + } + + m_portBufferProfileListBulk.clear(); +} + void BufferOrch::doTask() { // The hidden dependency tree: @@ -1451,6 +1812,8 @@ void BufferOrch::doTask() SWSS_LOG_DEBUG("Handling buffer task"); + const auto start = std::chrono::high_resolution_clock::now(); + auto pool_consumer = getExecutor((APP_BUFFER_POOL_TABLE_NAME)); pool_consumer->drain(); @@ -1466,6 +1829,16 @@ void BufferOrch::doTask() continue; consumer->drain(); } + + const auto end = std::chrono::high_resolution_clock::now(); + + if (WarmStart::isWarmStart()) + { + using second_t = std::chrono::duration>; + + const auto duration = std::chrono::duration_cast(end - start).count(); + SWSS_LOG_NOTICE("Buffers configuration took %lf sec", duration); + } } void BufferOrch::doTask(Consumer &consumer) @@ -1486,11 +1859,12 @@ void BufferOrch::doTask(Consumer &consumer) return; } + auto map_type_name = consumer.getTableName(); + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { /* Make sure the handler is initialized for the task */ - auto map_type_name = consumer.getTableName(); if (m_bufferHandlerMap.find(map_type_name) == m_bufferHandlerMap.end()) { SWSS_LOG_ERROR("No handler for key:%s found.", map_type_name.c_str()); @@ -1523,4 +1897,9 @@ void BufferOrch::doTask(Consumer &consumer) break; } } + + if (m_bufferFlushHandlerMap.find(map_type_name) != m_bufferFlushHandlerMap.end()) + { + (this->*(m_bufferFlushHandlerMap[map_type_name]))(consumer); + } } diff --git a/orchagent/bufferorch.h b/orchagent/bufferorch.h index 3d255b87dd..d5e76ef0c4 100644 --- a/orchagent/bufferorch.h +++ b/orchagent/bufferorch.h @@ -7,6 +7,7 @@ #include "orch.h" #include "portsorch.h" #include "redisapi.h" +#include "saiattr.h" #define BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "BUFFER_POOL_WATERMARK_STAT_COUNTER" #define BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" @@ -30,6 +31,68 @@ const string buffer_value_both = "both"; const string buffer_profile_list_field_name = "profile_list"; const string buffer_headroom_type_field_name= "headroom_type"; +struct PortBufferProfileListTask +{ + struct PortContext + { + std::string port_name; + sai_object_id_t port_oid = SAI_NULL_OBJECT_ID; + SaiAttrWrapper attr = {}; + sai_status_t status = SAI_STATUS_NOT_EXECUTED; + }; + + KeyOpFieldsValuesTuple kofvs; + std::vector ports; +}; + +struct PriorityGroupTask +{ + struct PgContext + { + size_t index; + bool update_sai = true; + bool counter_was_added = false; + bool counter_needs_to_add = false; + sai_object_id_t pg_id = SAI_NULL_OBJECT_ID; + SaiAttrWrapper attr = {}; + sai_status_t status = SAI_STATUS_NOT_EXECUTED; + }; + + struct PortContext + { + std::string port_name; + std::vector pgs; + }; + + KeyOpFieldsValuesTuple kofvs; + std::vector ports; +}; + +struct QueueTask +{ + struct QueueContext + { + size_t index; + bool update_sai = true; + bool counter_was_added = false; + bool counter_needs_to_add = false; + sai_object_id_t queue_id = SAI_NULL_OBJECT_ID; + SaiAttrWrapper attr = {}; + sai_status_t status = SAI_STATUS_NOT_EXECUTED; + }; + + struct PortContext + { + std::string port_name; + bool local_port = false; + std::string local_port_name; + std::vector queues; + }; + + KeyOpFieldsValuesTuple kofvs; + std::vector ports; +}; + class BufferOrch : public Orch { public: @@ -45,6 +108,10 @@ class BufferOrch : public Orch typedef map buffer_table_handler_map; typedef pair buffer_handler_pair; + typedef void (BufferOrch::*buffer_table_flush_handler)(Consumer& consumer); + typedef map buffer_table_flush_handler_map; + typedef pair buffer_flush_handler_pair; + void doTask() override; virtual void doTask(Consumer& consumer); void clearBufferPoolWatermarkCounterIdList(const sai_object_id_t object_id); @@ -61,7 +128,18 @@ class BufferOrch : public Orch task_process_status processIngressBufferProfileList(KeyOpFieldsValuesTuple &tuple); task_process_status processEgressBufferProfileList(KeyOpFieldsValuesTuple &tuple); + void processQueueBulk(Consumer& consumer); + void processPriorityGroupBulk(Consumer& consumer); + void processIngressBufferProfileListBulk(Consumer& consumer); + void processEgressBufferProfileListBulk(Consumer& consumer); + + task_process_status processQueuePost(const QueueTask& task); + task_process_status processPriorityGroupPost(const PriorityGroupTask& task); + task_process_status processIngressBufferProfileListPost(const PortBufferProfileListTask& task); + task_process_status processEgressBufferProfileListPost(const PortBufferProfileListTask& task); + buffer_table_handler_map m_bufferHandlerMap; + buffer_table_flush_handler_map m_bufferFlushHandlerMap; std::unordered_map m_ready_list; std::unordered_map> m_port_ready_list_ref; @@ -71,6 +149,11 @@ class BufferOrch : public Orch bool m_isBufferPoolWatermarkCounterIdListGenerated = false; set m_partiallyAppliedQueues; + + std::vector m_portBufferProfileListBulk; + std::vector m_portIngressBufferProfileListBulk; + std::vector m_priorityGroupBulk; + std::vector m_queueBulk; }; #endif /* SWSS_BUFFORCH_H */ diff --git a/tests/mock_tests/bufferorch_ut.cpp b/tests/mock_tests/bufferorch_ut.cpp index f92d5e1f6d..100315f726 100644 --- a/tests/mock_tests/bufferorch_ut.cpp +++ b/tests/mock_tests/bufferorch_ut.cpp @@ -120,22 +120,67 @@ namespace bufferorch_test return pold_sai_queue_api->set_queue_attribute(queue_id, attr); } + sai_status_t _ut_stub_sai_set_ports_attribute( + uint32_t object_count, + const sai_object_id_t *object_id, + const sai_attribute_t *attr_list, + sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses) + { + for (size_t i = 0; i < object_count; i++) + { + object_statuses[i] = _ut_stub_sai_set_port_attribute(object_id[i], attr_list + i); + } + return SAI_STATUS_SUCCESS; + } + + sai_status_t _ut_stub_sai_set_ingress_priority_groups_attribute( + uint32_t object_count, + const sai_object_id_t *object_id, + const sai_attribute_t *attr_list, + sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses) + { + for (size_t i = 0; i < object_count; i++) + { + object_statuses[i] = _ut_stub_sai_set_ingress_priority_group_attribute(object_id[i], attr_list + i); + } + return SAI_STATUS_SUCCESS; + } + + sai_status_t _ut_stub_sai_set_queues_attribute( + uint32_t object_count, + const sai_object_id_t *object_id, + const sai_attribute_t *attr_list, + sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses) + { + for (size_t i = 0; i < object_count; i++) + { + object_statuses[i] = _ut_stub_sai_set_queue_attribute(object_id[i], attr_list + i); + } + return SAI_STATUS_SUCCESS; + } + void _hook_sai_apis() { ut_sai_port_api = *sai_port_api; pold_sai_port_api = sai_port_api; ut_sai_port_api.set_port_attribute = _ut_stub_sai_set_port_attribute; + ut_sai_port_api.set_ports_attribute = _ut_stub_sai_set_ports_attribute; sai_port_api = &ut_sai_port_api; ut_sai_buffer_api = *sai_buffer_api; pold_sai_buffer_api = sai_buffer_api; ut_sai_buffer_api.set_ingress_priority_group_attribute = _ut_stub_sai_set_ingress_priority_group_attribute; + ut_sai_buffer_api.set_ingress_priority_groups_attribute = _ut_stub_sai_set_ingress_priority_groups_attribute; ut_sai_buffer_api.set_buffer_profile_attribute = _ut_stub_sai_set_buffer_profile_attribute; sai_buffer_api = &ut_sai_buffer_api; ut_sai_queue_api = *sai_queue_api; pold_sai_queue_api = sai_queue_api; ut_sai_queue_api.set_queue_attribute = _ut_stub_sai_set_queue_attribute; + ut_sai_queue_api.set_queues_attribute = _ut_stub_sai_set_queues_attribute; sai_queue_api = &ut_sai_queue_api; }