From 9e3c9b9face60f3ed4a65a45cf642f3a104eae4d Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:37:57 +0900 Subject: [PATCH 1/6] Optimize counter polling interval by making it more accurate (#1457) (#1534) What I did Optimize the counter-polling performance in terms of polling interval accuracy Enable bulk counter-polling to run at a smaller chunk size There is one counter-polling thread for each counter group. All such threads can compete for the critical sections at the vendor SAI level, which means a counter-polling thread can wait for a critical section if another thread has been in it, which introduces latency for the waiting counter group. An example is the competition between the PFC watchdog and the port counter groups. The port counter group contains many counters and is polled in a bulk mode which takes a relatively longer time. The PFC watchdog counter group contains only a few counters but is polled at a short interval. Sometimes, PFC watchdog counters need to wait before polling, which makes the polling interval inaccurate and prevents the PFC storm from being detected in time. To resolve this issue, we can reduce the chunk size of the port counter group. The port counter group polls the counters of all ports in a single bulk operation by default. By using a smaller chunk size, it polls the counters in several bulk operations with each polling counter of a subset (whose size <= chunk size) of all ports. By doing so, the port counter group stays in the critical section for a shorter time and the PFC watchdog is more likely to be scheduled to poll counters and detect the PFC storm in time. Collect the time stamp immediately after vendor SAI API returns. Currently, many counter groups require a Lua plugin to execute based on polling interval, to calculate rates, detect certain events, etc. Eg. For PFC watchdog counter group to PFC storm. In this case, the polling interval is calculated based on the difference of time stamps between the current and last poll to avoid deviation due to scheduling latency. However, the timestamp is collected in the Lua plugin which is several steps after the SAI API returns and is executed in a different context (redis-server). Both introduce even larger deviations. To overcome this, we collect the timestamp immediately after the SAI API returns. --- unittest/syncd/TestFlexCounter.cpp | 209 +++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/unittest/syncd/TestFlexCounter.cpp b/unittest/syncd/TestFlexCounter.cpp index f68b15cf54..84e3c517ad 100644 --- a/unittest/syncd/TestFlexCounter.cpp +++ b/unittest/syncd/TestFlexCounter.cpp @@ -298,6 +298,17 @@ void testAddRemoveCounter( } } + if (bulkChunkSizeAfterPort) + { + fc.addCounterPlugin(bulkChunkSizeValues); + if (immediatelyRemoveBulkChunkSizePerCounter) + { + bulkChunkSizeValues.clear(); + bulkChunkSizeValues.emplace_back(BULK_CHUNK_SIZE_PER_PREFIX_FIELD, ""); + fc.addCounterPlugin(bulkChunkSizeValues); + } + } + EXPECT_EQ(fc.isEmpty(), false); swss::DBConnector db("COUNTERS_DB", 0); @@ -1806,6 +1817,204 @@ TEST(FlexCounter, bulkChunksize) EXPECT_TRUE(allObjectIds.empty()); } +TEST(FlexCounter, bulkChunksize) +{ + /* + * Test logic + * 1. Generate counter values and store them whenever the bulk get stat is called after initialization + * 2. Convert stored counter values to string when the verify function is called + * and verify whether the database content aligns with the stored values + * 3. Verify whether values of all counter IDs of all objects have been generated + * 4. Verify whether the bulk chunk size is correct + */ + sai->mock_getStatsExt = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, sai_stats_mode_t, uint64_t *counters) { + return SAI_STATUS_SUCCESS; + }; + sai->mock_getStats = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, uint64_t *counters) { + return SAI_STATUS_SUCCESS; + }; + sai->mock_queryStatsCapability = [&](sai_object_id_t switch_id, sai_object_type_t object_type, sai_stat_capability_list_t *stats_capability) { + // For now, just return failure to make test simple, will write a singe test to cover querySupportedCounters + return SAI_STATUS_FAILURE; + }; + + // Map of number from {oid: {counter_id: counter value}} + std::map> counterValuesMap; + // Map of string from {oid: {counter_id: counter value}} + std::map> expectedValuesMap; + + std::set allCounterIds = { + "SAI_PORT_STAT_IF_IN_OCTETS", + "SAI_PORT_STAT_IF_IN_UCAST_PKTS", + "SAI_PORT_STAT_IF_OUT_QLEN", + "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", + "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES" + }; + std::set allObjectIds; + auto generateExpectedValues = [&]() + { + std::set allCounterValueSet; + for (const auto &oidRef : counterValuesMap) + { + auto &expected = expectedValuesMap[toOid(oidRef.first)]; + std::set localAllCounterIds = allCounterIds; + for (const auto &counters : oidRef.second) + { + // No duplicate counter value + EXPECT_EQ(allCounterValueSet.find(counters.second), allCounterValueSet.end()); + allCounterValueSet.insert(counters.second); + + // For each object, no unexpected counter ID + const auto &counterId = sai_serialize_port_stat((sai_port_stat_t)counters.first); + EXPECT_TRUE(localAllCounterIds.find(counterId) != localAllCounterIds.end()); + localAllCounterIds.erase(counterId); + + expected[counterId] = to_string(counters.second); + } + + // For each object, all expected counters are generated + EXPECT_TRUE(localAllCounterIds.empty()); + } + }; + + std::vector> counterRecord; + std::vector> valueRecord; + sai_uint64_t counterSeed = 0; + uint32_t unifiedBulkChunkSize = 0; + sai->mock_bulkGetStats = [&](sai_object_id_t, + sai_object_type_t, + uint32_t object_count, + const sai_object_key_t *object_keys, + uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, + sai_stats_mode_t mode, + sai_status_t *object_status, + uint64_t *counters) + { + EXPECT_TRUE(mode == SAI_STATS_MODE_BULK_READ); + std::vector record; + std::vector value; + if (number_of_counters >= 5 && object_count == 1) + { + allObjectIds.insert(toOid(object_keys[0].key.object_id)); + // This call is to check whether bulk counter polling is supported during initialization + return SAI_STATUS_SUCCESS; + } + for (uint32_t i = 0; i < object_count; i++) + { + object_status[i] = SAI_STATUS_SUCCESS; + auto &counterMap = counterValuesMap[object_keys[i].key.object_id]; + for (uint32_t j = 0; j < number_of_counters; j++) + { + const auto &searchRef = counterMap.find(counter_ids[j]); + if (searchRef == counterMap.end()) + { + counterMap[counter_ids[j]] = ++counterSeed; + } + counters[i * number_of_counters + j] = counterMap[counter_ids[j]]; + record.emplace_back(counter_ids[j]); + value.emplace_back(counterSeed); + if (unifiedBulkChunkSize > 0) + { + if (object_count != unifiedBulkChunkSize) + { + EXPECT_EQ(object_count, unifiedBulkChunkSize); + } + continue; + } + switch (counter_ids[j]) + { + case SAI_PORT_STAT_IF_IN_OCTETS: + case SAI_PORT_STAT_IF_IN_UCAST_PKTS: + // default chunk size 2, object number 6, object count 6 / 2 = 3 + EXPECT_EQ(object_count, 3); + break; + case SAI_PORT_STAT_IF_OUT_QLEN: + // queue length chunk size 0, object number 6, object count 6 + EXPECT_EQ(object_count, 6); + break; + case SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES: + case SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES: + // FEC chunk size 2, object number 6, object count 6 / 3 = 2 + EXPECT_EQ(object_count, 2); + default: + break; + } + } + } + return SAI_STATUS_SUCCESS; + }; + + auto counterVerifyFunc = [&] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector&) + { + std::string value; + if (expectedValuesMap.empty()) + { + generateExpectedValues(); + } + auto const &searchRef = expectedValuesMap.find(key); + ASSERT_TRUE(searchRef != expectedValuesMap.end()); + auto &oidCounters = searchRef->second; + + for (auto const &counter : counterIdNames) + { + countersTable.hget(key, counter, value); + EXPECT_EQ(value, oidCounters[counter]); + oidCounters.erase(counter); + } + + EXPECT_TRUE(oidCounters.empty()); + expectedValuesMap.erase(searchRef); + + allObjectIds.erase(key); + }; + + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2"); + EXPECT_TRUE(allObjectIds.empty()); + + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", + false, + PORT_PLUGIN_FIELD); + EXPECT_TRUE(allObjectIds.empty()); + + unifiedBulkChunkSize = 3; + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", + true, + "", + true); + EXPECT_TRUE(allObjectIds.empty()); +} + TEST(FlexCounter, counterIdChange) { sai->mock_queryStatsCapability = [](sai_object_id_t, sai_object_type_t, sai_stat_capability_list_t *capability) { From 0b3b7911ea272436ea8530747cb472cba75f2c4b Mon Sep 17 00:00:00 2001 From: Kumaresh Perumal Date: Thu, 3 Apr 2025 09:05:46 -0700 Subject: [PATCH 2/6] =?UTF-8?q?Revert=20"Optimize=20counter=20polling=20in?= =?UTF-8?q?terval=20by=20making=20it=20more=20accurate=20(#1457)=20?= =?UTF-8?q?=E2=80=A6"=20(#1570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "Optimize counter polling interval by making it more accurate --- lib/RedisRemoteSaiInterface.cpp | 2 - syncd/FlexCounter.cpp | 176 ++++++----------------- syncd/FlexCounter.h | 13 +- tests/aspell.en.pws | 1 - unittest/syncd/TestFlexCounter.cpp | 224 +---------------------------- 5 files changed, 48 insertions(+), 368 deletions(-) diff --git a/lib/RedisRemoteSaiInterface.cpp b/lib/RedisRemoteSaiInterface.cpp index b47e7de640..a4372026f1 100644 --- a/lib/RedisRemoteSaiInterface.cpp +++ b/lib/RedisRemoteSaiInterface.cpp @@ -575,8 +575,6 @@ sai_status_t RedisRemoteSaiInterface::notifyCounterGroupOperations( std::string key((const char*)flexCounterGroupParam->counter_group_name.list, flexCounterGroupParam->counter_group_name.count); emplaceStrings(POLL_INTERVAL_FIELD, flexCounterGroupParam->poll_interval, entries); - emplaceStrings(BULK_CHUNK_SIZE_FIELD, flexCounterGroupParam->bulk_chunk_size, entries); - emplaceStrings(BULK_CHUNK_SIZE_PER_PREFIX_FIELD, flexCounterGroupParam->bulk_chunk_size_per_prefix, entries); emplaceStrings(STATS_MODE_FIELD, flexCounterGroupParam->stats_mode, entries); emplaceStrings(flexCounterGroupParam->plugin_name, flexCounterGroupParam->plugins, entries); emplaceStrings(FLEX_COUNTER_STATUS_FIELD, flexCounterGroupParam->operation, entries); diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index 40978ff8fe..91dc8a3993 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -97,9 +97,8 @@ const std::map, std::string> FlexCoun {{SAI_OBJECT_TYPE_SWITCH, SWITCH_COUNTER_ID_LIST}, COUNTER_TYPE_SWITCH}, }; -BaseCounterContext::BaseCounterContext(const std::string &name, const std::string &instance): -m_name(name), -m_instanceId(instance) +BaseCounterContext::BaseCounterContext(const std::string &name): +m_name(name) { SWSS_LOG_ENTER(); } @@ -130,20 +129,6 @@ void BaseCounterContext::setNoDoubleCheckBulkCapability( no_double_check_bulk_capability = noDoubleCheckBulkCapability; } -void BaseCounterContext::setBulkChunkSize( - _In_ uint32_t bulkChunkSize) -{ - SWSS_LOG_ENTER(); - default_bulk_chunk_size = bulkChunkSize; -} - -void BaseCounterContext::setBulkChunkSizePerPrefix( - _In_ const std::string& bulkChunkSizePerPrefix) -{ - SWSS_LOG_ENTER(); - m_bulkChunkSizePerPrefix = bulkChunkSizePerPrefix; -} - template struct CounterIds @@ -544,11 +529,10 @@ class CounterContext : public BaseCounterContext CounterContext( _In_ const std::string &name, - _In_ const std::string &instance, _In_ sai_object_type_t object_type, _In_ sairedis::SaiInterface *vendor_sai, _In_ sai_stats_mode_t &stats_mode): - BaseCounterContext(name, instance), m_objectType(object_type), m_vendorSai(vendor_sai), m_groupStatsMode(stats_mode) + BaseCounterContext(name), m_objectType(object_type), m_vendorSai(vendor_sai), m_groupStatsMode(stats_mode) { SWSS_LOG_ENTER(); } @@ -646,10 +630,10 @@ class CounterContext : public BaseCounterContext } m_objectIdsMap.emplace(vid, counter_data); } - else if (m_counterChunkSizeMapFromPrefix.empty()) + else { std::sort(supportedIds.begin(), supportedIds.end()); - auto bulkContext = getBulkStatsContext(supportedIds, "default", default_bulk_chunk_size); + auto bulkContext = getBulkStatsContext(supportedIds); addBulkStatsContext(vid, rid, supportedIds, *bulkContext.get()); } else @@ -1188,9 +1172,6 @@ class CounterContext : public BaseCounterContext { return; } - - SWSS_LOG_DEBUG("Before running plugin %s %s", m_instanceId.c_str(), m_name.c_str()); - std::vector idStrings; idStrings.reserve(m_objectIdsMap.size()); std::transform(m_objectIdsMap.begin(), @@ -1209,8 +1190,6 @@ class CounterContext : public BaseCounterContext std::for_each(m_plugins.begin(), m_plugins.end(), [&] (auto &sha) { runRedisScript(counters_db, sha, idStrings, argv); }); - - SWSS_LOG_DEBUG("After running plugin %s %s", m_instanceId.c_str(), m_name.c_str()); } bool hasObject() const override @@ -1313,11 +1292,19 @@ class CounterContext : public BaseCounterContext { SWSS_LOG_ENTER(); auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR; - uint32_t bulk_chunk_size = ctx.default_bulk_chunk_size; - uint32_t size = static_cast(ctx.object_keys.size()); - if (bulk_chunk_size > size || bulk_chunk_size == 0) + sai_status_t status = m_vendorSai->bulkGetStats( + SAI_NULL_OBJECT_ID, + m_objectType, + static_cast(ctx.object_keys.size()), + ctx.object_keys.data(), + static_cast(ctx.counter_ids.size()), + reinterpret_cast(ctx.counter_ids.data()), + statsMode, + ctx.object_statuses.data(), + ctx.counters.data()); + if (SAI_STATUS_SUCCESS != status) { - bulk_chunk_size = size; + SWSS_LOG_WARN("Failed to bulk get stats for %s: %u", m_name.c_str(), status); } uint32_t current = 0; @@ -1384,9 +1371,7 @@ class CounterContext : public BaseCounterContext } auto getBulkStatsContext( - _In_ const std::vector& counterIds, - _In_ const std::string& name, - _In_ uint32_t bulk_chunk_size=0) + _In_ const std::vector& counterIds) { SWSS_LOG_ENTER(); auto iter = m_bulkContexts.find(counterIds); @@ -1395,23 +1380,10 @@ class CounterContext : public BaseCounterContext return iter->second; } - SWSS_LOG_NOTICE("Create bulk stat context %s %s %s", m_instanceId.c_str(), m_name.c_str(), name.c_str()); auto ret = m_bulkContexts.emplace(counterIds, std::make_shared()); - ret.first->second.get()->name = name; - ret.first->second.get()->default_bulk_chunk_size = bulk_chunk_size; - ret.first->second.get()->counter_ids = counterIds; return ret.first->second; } - void setBulkStatsContext( - _In_ const std::vector& counterIds, - _In_ const std::shared_ptr ptr) - { - SWSS_LOG_ENTER(); - m_bulkContexts.emplace(counterIds, ptr); - ptr.get()->counter_ids = counterIds; - } - void addBulkStatsContext( _In_ sai_object_id_t vid, _In_ sai_object_id_t rid, @@ -1431,6 +1403,10 @@ class CounterContext : public BaseCounterContext sai_object_key_t object_key; object_key.key.object_id = rid; ctx.object_keys.push_back(object_key); + if (ctx.counter_ids.empty()) + { + ctx.counter_ids = counterIds; + } ctx.object_statuses.push_back(SAI_STATUS_SUCCESS); ctx.counters.resize(counterIds.size() * ctx.object_keys.size()); } @@ -1468,7 +1444,6 @@ class CounterContext : public BaseCounterContext _In_ sai_object_id_t vid) { SWSS_LOG_ENTER(); - std::set> bulkContextsToBeRemoved; bool found = false; for (auto iter = m_bulkContexts.begin(); iter != m_bulkContexts.end(); iter++) { @@ -1484,9 +1459,7 @@ class CounterContext : public BaseCounterContext ctx.object_vids_set.erase(vid); if (ctx.object_vids.empty()) { - // It can change the order of the map to erase an element in a loop iterating the map - // which can cause some elements to be skipped or iterated for multiple times - bulkContextsToBeRemoved.insert(iter->first); + m_bulkContexts.erase(iter); } else { @@ -1496,20 +1469,7 @@ class CounterContext : public BaseCounterContext ctx.counters.resize(ctx.counter_ids.size() * ctx.object_keys.size()); ctx.object_statuses.pop_back(); } - if (m_counterChunkSizeMapFromPrefix.empty()) - { - break; - } - else - { - // There can be more than one bulk context containing the VID when the per counter ID bulk chunk size is configured - continue; - } - } - - for (auto iter : bulkContextsToBeRemoved) - { - m_bulkContexts.erase(iter); + break; } return found; @@ -1522,7 +1482,6 @@ class CounterContext : public BaseCounterContext { SWSS_LOG_ENTER(); BulkContextType ctx; - ctx.counter_ids = counter_ids; addBulkStatsContext(vid, rid, counter_ids, ctx); auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR; sai_status_t status = m_vendorSai->bulkGetStats( @@ -1667,11 +1626,10 @@ class AttrContext : public CounterContext typedef CounterContext Base; AttrContext( _In_ const std::string &name, - _In_ const std::string &instance, _In_ sai_object_type_t object_type, _In_ sairedis::SaiInterface *vendor_sai, _In_ sai_stats_mode_t &stats_mode): - CounterContext(name, instance, object_type, vendor_sai, stats_mode) + CounterContext(name, object_type, vendor_sai, stats_mode) { SWSS_LOG_ENTER(); } @@ -2627,10 +2585,9 @@ class DashMeterCounterContext : public BaseCounterContext public: DashMeterCounterContext( _In_ const std::string &name, - _In_ const std::string &instance, _In_ sairedis::SaiInterface *vendor_sai, _In_ std::string dbCounters): - BaseCounterContext(name, instance), m_dbCounters(dbCounters), m_vendorSai(vendor_sai) + BaseCounterContext(name), m_dbCounters(dbCounters), m_vendorSai(vendor_sai) { SWSS_LOG_ENTER(); } @@ -3131,8 +3088,6 @@ void FlexCounter::addCounterPlugin( SWSS_LOG_ENTER(); m_isDiscarded = false; - uint32_t bulkChunkSize = 0; - std::string bulkChunkSizePerPrefix; for (auto& fvt: values) { @@ -3145,34 +3100,6 @@ void FlexCounter::addCounterPlugin( { setPollInterval(stoi(value)); } - else if (field == BULK_CHUNK_SIZE_FIELD) - { - if (value != "NULL") - { - try - { - bulkChunkSize = stoi(value); - } - catch (...) - { - SWSS_LOG_ERROR("Invalid bulk chunk size %s", value.c_str()); - } - } - for (auto &context : m_counterContext) - { - SWSS_LOG_NOTICE("Set counter context %s %s bulk size %u", m_instanceId.c_str(), COUNTER_TYPE_PORT.c_str(), bulkChunkSize); - context.second->setBulkChunkSize(bulkChunkSize); - } - } - else if (field == BULK_CHUNK_SIZE_PER_PREFIX_FIELD) - { - bulkChunkSizePerPrefix = value; - for (auto &context : m_counterContext) - { - SWSS_LOG_NOTICE("Set counter context %s %s bulk chunk prefix map %s", m_instanceId.c_str(), COUNTER_TYPE_PORT.c_str(), bulkChunkSizePerPrefix.c_str()); - context.second->setBulkChunkSizePerPrefix(bulkChunkSizePerPrefix); - } - } else if (field == FLEX_COUNTER_STATUS_FIELD) { setStatus(value); @@ -3195,18 +3122,6 @@ void FlexCounter::addCounterPlugin( SWSS_LOG_NOTICE("Do not double check bulk capability counter context %s %s", m_instanceId.c_str(), counterTypeRef->second.c_str()); } - - if (bulkChunkSize > 0) - { - getCounterContext(counterTypeRef->second)->setBulkChunkSize(bulkChunkSize); - SWSS_LOG_NOTICE("Create counter context %s %s with bulk size %u", m_instanceId.c_str(), counterTypeRef->second.c_str(), bulkChunkSize); - } - - if (!bulkChunkSizePerPrefix.empty()) - { - getCounterContext(counterTypeRef->second)->setBulkChunkSizePerPrefix(bulkChunkSizePerPrefix); - SWSS_LOG_NOTICE("Create counter context %s %s with bulk prefix map %s", m_instanceId.c_str(), counterTypeRef->second.c_str(), bulkChunkSizePerPrefix.c_str()); - } } else { @@ -3266,13 +3181,12 @@ bool FlexCounter::allPluginsEmpty() const } std::shared_ptr FlexCounter::createCounterContext( - _In_ const std::string& context_name, - _In_ const std::string& instance) + _In_ const std::string& context_name) { SWSS_LOG_ENTER(); if (context_name == COUNTER_TYPE_PORT) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; return context; } @@ -3284,7 +3198,7 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_PORT_DEBUG) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; context->use_sai_stats_capa_query = false; context->use_sai_stats_ext = true; @@ -3293,7 +3207,7 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_QUEUE) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; context->double_confirm_supported_counters = true; return context; @@ -3307,18 +3221,18 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_PG) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; context->double_confirm_supported_counters = true; return context; } else if (context_name == COUNTER_TYPE_RIF) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_ROUTER_INTERFACE, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_ROUTER_INTERFACE, m_vendorSai.get(), m_statsMode); } else if (context_name == COUNTER_TYPE_SWITCH_DEBUG) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_SWITCH, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_SWITCH, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; context->use_sai_stats_capa_query = false; context->use_sai_stats_ext = true; @@ -3327,13 +3241,13 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_MACSEC_FLOW) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_MACSEC_FLOW, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_FLOW, m_vendorSai.get(), m_statsMode); context->use_sai_stats_capa_query = false; return context; } else if (context_name == COUNTER_TYPE_MACSEC_SA) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; context->use_sai_stats_capa_query = false; context->dont_clear_support_counter = true; @@ -3341,7 +3255,7 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_FLOW) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_COUNTER, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_COUNTER, m_vendorSai.get(), m_statsMode); context->use_sai_stats_capa_query = false; context->use_sai_stats_ext = true; @@ -3349,19 +3263,19 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_TUNNEL) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_TUNNEL, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_TUNNEL, m_vendorSai.get(), m_statsMode); context->use_sai_stats_capa_query = false; return context; } else if (context_name == COUNTER_TYPE_BUFFER_POOL) { - auto context = std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_BUFFER_POOL, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_BUFFER_POOL, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; return context; } else if (context_name == COUNTER_TYPE_ENI) { - auto context = std::make_shared>(context_name, instance, (sai_object_type_t)SAI_OBJECT_TYPE_ENI, m_vendorSai.get(), m_statsMode); + auto context = std::make_shared>(context_name, (sai_object_type_t)SAI_OBJECT_TYPE_ENI, m_vendorSai.get(), m_statsMode); context->always_check_supported_counters = true; return context; } @@ -3373,7 +3287,7 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == COUNTER_TYPE_METER_BUCKET) { - return std::make_shared(context_name, instance, m_vendorSai.get(), m_dbCounters); + return std::make_shared(context_name, m_vendorSai.get(), m_dbCounters); } else if (context_name == ATTR_TYPE_PORT_PHY_ATTR) { @@ -3385,23 +3299,23 @@ std::shared_ptr FlexCounter::createCounterContext( } else if (context_name == ATTR_TYPE_QUEUE) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); } else if (context_name == ATTR_TYPE_PG) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); } else if (context_name == ATTR_TYPE_MACSEC_SA) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); } else if (context_name == ATTR_TYPE_ACL_COUNTER) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_ACL_COUNTER, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_ACL_COUNTER, m_vendorSai.get(), m_statsMode); } else if (context_name == COUNTER_TYPE_POLICER) { - return std::make_shared>(context_name, instance, SAI_OBJECT_TYPE_POLICER, m_vendorSai.get(), m_statsMode); + return std::make_shared>(context_name, SAI_OBJECT_TYPE_POLICER, m_vendorSai.get(), m_statsMode); } else if (context_name == COUNTER_TYPE_SRV6) { diff --git a/syncd/FlexCounter.h b/syncd/FlexCounter.h index 62e846e5c8..1de7157c96 100644 --- a/syncd/FlexCounter.h +++ b/syncd/FlexCounter.h @@ -43,19 +43,13 @@ namespace syncd class BaseCounterContext { public: - BaseCounterContext(const std::string &name, const std::string &instance); + BaseCounterContext(const std::string &name); void addPlugins( _In_ const std::vector& shaStrings); void setNoDoubleCheckBulkCapability( _In_ bool); - virtual void setBulkChunkSize( - _In_ uint32_t bulkChunkSize); - - virtual void setBulkChunkSizePerPrefix( - _In_ const std::string& bulkChunkSizePerPrefix); - bool hasPlugin() const {return !m_plugins.empty();} void removePlugins() {m_plugins.clear();} @@ -86,9 +80,7 @@ namespace syncd protected: std::string m_name; - std::string m_instanceId; std::set m_plugins; - std::string m_bulkChunkSizePerPrefix; public: bool always_check_supported_counters = false; @@ -163,8 +155,7 @@ namespace syncd _In_ const std::string &name); std::shared_ptr createCounterContext( - _In_ const std::string &name, - _In_ const std::string &instance); + _In_ const std::string &name); void removeCounterContext( _In_ const std::string &name); diff --git a/tests/aspell.en.pws b/tests/aspell.en.pws index 6ef4d0c9b6..89a7cb980b 100644 --- a/tests/aspell.en.pws +++ b/tests/aspell.en.pws @@ -36,7 +36,6 @@ ecmp ECMP FDB FDBs -FEC FIXME FlexCounter gbsyncd diff --git a/unittest/syncd/TestFlexCounter.cpp b/unittest/syncd/TestFlexCounter.cpp index 84e3c517ad..f9b43d8782 100644 --- a/unittest/syncd/TestFlexCounter.cpp +++ b/unittest/syncd/TestFlexCounter.cpp @@ -248,20 +248,6 @@ void testAddRemoveCounter( values.emplace_back(POLL_INTERVAL_FIELD, "1000"); values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); values.emplace_back(STATS_MODE_FIELD, statsMode); - std::vector fcValues = values; - auto &bulkChunkSizeValues = bulkChunkSizeAfterPort ? fcValues : values; - if (!bulkChunkSize.empty()) - { - bulkChunkSizeValues.emplace_back(BULK_CHUNK_SIZE_FIELD, bulkChunkSize); - } - if (!bulkChunkSizePerCounter.empty()) - { - bulkChunkSizeValues.emplace_back(BULK_CHUNK_SIZE_PER_PREFIX_FIELD, bulkChunkSizePerCounter); - } - if (!pluginName.empty()) - { - values.emplace_back(pluginName, ""); - } fc.addCounterPlugin(values); values.clear(); @@ -298,17 +284,6 @@ void testAddRemoveCounter( } } - if (bulkChunkSizeAfterPort) - { - fc.addCounterPlugin(bulkChunkSizeValues); - if (immediatelyRemoveBulkChunkSizePerCounter) - { - bulkChunkSizeValues.clear(); - bulkChunkSizeValues.emplace_back(BULK_CHUNK_SIZE_PER_PREFIX_FIELD, ""); - fc.addCounterPlugin(bulkChunkSizeValues); - } - } - EXPECT_EQ(fc.isEmpty(), false); swss::DBConnector db("COUNTERS_DB", 0); @@ -1817,204 +1792,6 @@ TEST(FlexCounter, bulkChunksize) EXPECT_TRUE(allObjectIds.empty()); } -TEST(FlexCounter, bulkChunksize) -{ - /* - * Test logic - * 1. Generate counter values and store them whenever the bulk get stat is called after initialization - * 2. Convert stored counter values to string when the verify function is called - * and verify whether the database content aligns with the stored values - * 3. Verify whether values of all counter IDs of all objects have been generated - * 4. Verify whether the bulk chunk size is correct - */ - sai->mock_getStatsExt = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, sai_stats_mode_t, uint64_t *counters) { - return SAI_STATUS_SUCCESS; - }; - sai->mock_getStats = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, uint64_t *counters) { - return SAI_STATUS_SUCCESS; - }; - sai->mock_queryStatsCapability = [&](sai_object_id_t switch_id, sai_object_type_t object_type, sai_stat_capability_list_t *stats_capability) { - // For now, just return failure to make test simple, will write a singe test to cover querySupportedCounters - return SAI_STATUS_FAILURE; - }; - - // Map of number from {oid: {counter_id: counter value}} - std::map> counterValuesMap; - // Map of string from {oid: {counter_id: counter value}} - std::map> expectedValuesMap; - - std::set allCounterIds = { - "SAI_PORT_STAT_IF_IN_OCTETS", - "SAI_PORT_STAT_IF_IN_UCAST_PKTS", - "SAI_PORT_STAT_IF_OUT_QLEN", - "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", - "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES" - }; - std::set allObjectIds; - auto generateExpectedValues = [&]() - { - std::set allCounterValueSet; - for (const auto &oidRef : counterValuesMap) - { - auto &expected = expectedValuesMap[toOid(oidRef.first)]; - std::set localAllCounterIds = allCounterIds; - for (const auto &counters : oidRef.second) - { - // No duplicate counter value - EXPECT_EQ(allCounterValueSet.find(counters.second), allCounterValueSet.end()); - allCounterValueSet.insert(counters.second); - - // For each object, no unexpected counter ID - const auto &counterId = sai_serialize_port_stat((sai_port_stat_t)counters.first); - EXPECT_TRUE(localAllCounterIds.find(counterId) != localAllCounterIds.end()); - localAllCounterIds.erase(counterId); - - expected[counterId] = to_string(counters.second); - } - - // For each object, all expected counters are generated - EXPECT_TRUE(localAllCounterIds.empty()); - } - }; - - std::vector> counterRecord; - std::vector> valueRecord; - sai_uint64_t counterSeed = 0; - uint32_t unifiedBulkChunkSize = 0; - sai->mock_bulkGetStats = [&](sai_object_id_t, - sai_object_type_t, - uint32_t object_count, - const sai_object_key_t *object_keys, - uint32_t number_of_counters, - const sai_stat_id_t *counter_ids, - sai_stats_mode_t mode, - sai_status_t *object_status, - uint64_t *counters) - { - EXPECT_TRUE(mode == SAI_STATS_MODE_BULK_READ); - std::vector record; - std::vector value; - if (number_of_counters >= 5 && object_count == 1) - { - allObjectIds.insert(toOid(object_keys[0].key.object_id)); - // This call is to check whether bulk counter polling is supported during initialization - return SAI_STATUS_SUCCESS; - } - for (uint32_t i = 0; i < object_count; i++) - { - object_status[i] = SAI_STATUS_SUCCESS; - auto &counterMap = counterValuesMap[object_keys[i].key.object_id]; - for (uint32_t j = 0; j < number_of_counters; j++) - { - const auto &searchRef = counterMap.find(counter_ids[j]); - if (searchRef == counterMap.end()) - { - counterMap[counter_ids[j]] = ++counterSeed; - } - counters[i * number_of_counters + j] = counterMap[counter_ids[j]]; - record.emplace_back(counter_ids[j]); - value.emplace_back(counterSeed); - if (unifiedBulkChunkSize > 0) - { - if (object_count != unifiedBulkChunkSize) - { - EXPECT_EQ(object_count, unifiedBulkChunkSize); - } - continue; - } - switch (counter_ids[j]) - { - case SAI_PORT_STAT_IF_IN_OCTETS: - case SAI_PORT_STAT_IF_IN_UCAST_PKTS: - // default chunk size 2, object number 6, object count 6 / 2 = 3 - EXPECT_EQ(object_count, 3); - break; - case SAI_PORT_STAT_IF_OUT_QLEN: - // queue length chunk size 0, object number 6, object count 6 - EXPECT_EQ(object_count, 6); - break; - case SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES: - case SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES: - // FEC chunk size 2, object number 6, object count 6 / 3 = 2 - EXPECT_EQ(object_count, 2); - default: - break; - } - } - } - return SAI_STATUS_SUCCESS; - }; - - auto counterVerifyFunc = [&] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector&) - { - std::string value; - if (expectedValuesMap.empty()) - { - generateExpectedValues(); - } - auto const &searchRef = expectedValuesMap.find(key); - ASSERT_TRUE(searchRef != expectedValuesMap.end()); - auto &oidCounters = searchRef->second; - - for (auto const &counter : counterIdNames) - { - countersTable.hget(key, counter, value); - EXPECT_EQ(value, oidCounters[counter]); - oidCounters.erase(counter); - } - - EXPECT_TRUE(oidCounters.empty()); - expectedValuesMap.erase(searchRef); - - allObjectIds.erase(key); - }; - - testAddRemoveCounter( - 6, - SAI_OBJECT_TYPE_PORT, - PORT_COUNTER_ID_LIST, - {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, - {}, - counterVerifyFunc, - false, - STATS_MODE_READ, - "3", - "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2"); - EXPECT_TRUE(allObjectIds.empty()); - - testAddRemoveCounter( - 6, - SAI_OBJECT_TYPE_PORT, - PORT_COUNTER_ID_LIST, - {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, - {}, - counterVerifyFunc, - false, - STATS_MODE_READ, - "3", - "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", - false, - PORT_PLUGIN_FIELD); - EXPECT_TRUE(allObjectIds.empty()); - - unifiedBulkChunkSize = 3; - testAddRemoveCounter( - 6, - SAI_OBJECT_TYPE_PORT, - PORT_COUNTER_ID_LIST, - {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, - {}, - counterVerifyFunc, - false, - STATS_MODE_READ, - "3", - "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", - true, - "", - true); - EXPECT_TRUE(allObjectIds.empty()); -} - TEST(FlexCounter, counterIdChange) { sai->mock_queryStatsCapability = [](sai_object_id_t, sai_object_type_t, sai_stat_capability_list_t *capability) { @@ -2403,3 +2180,4 @@ TEST(FlexCounter, noEniDashMeterCounter) counterVerifyFunc, false); } + From ecfc0d76459ed6550262cad64c81712545cf6393 Mon Sep 17 00:00:00 2001 From: Jimmy Jin Date: Mon, 6 Oct 2025 14:09:43 -0700 Subject: [PATCH 3/6] switch SAI submodule to OTN repos --- SAI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SAI b/SAI index 4923e924ac..fe62f9aa6e 160000 --- a/SAI +++ b/SAI @@ -1 +1 @@ -Subproject commit 4923e924ace60b702b1f166038a56c2b3120e2e0 +Subproject commit fe62f9aa6edead354b0dc4a1cdd4337bdfe50690 From 58e38975cdf9571ddd4370c8a00076fea1dd34ff Mon Sep 17 00:00:00 2001 From: oplklum Date: Mon, 13 Oct 2025 15:05:10 -0700 Subject: [PATCH 4/6] Fix the incorrect size limitation for string attribute in meta_generic_validation_create (#1663) 1. SAI_HOSTIF_NAME_SIZE only applies to SAI_HOSTIF_ATTR_NAME 2. SAI_HOSTIF_GENETLINK_MCGRP_NAME_SIZE applies to SAI_HOSTIF_ATTR_GENETLINK_MCGRP_NAME 3. Others apply to chardata size. Signed-off-by: oplklum --- meta/Meta.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/meta/Meta.cpp b/meta/Meta.cpp index ca562b8167..d3021916a5 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -3474,18 +3474,24 @@ sai_status_t Meta::meta_generic_validation_create( { const char* chardata = value.chardata; - size_t len = strnlen(chardata, SAI_HOSTIF_NAME_SIZE); + // Check the length of host interface name and genetlink multicast group name. + // Others should be less than the size defined for char data array. + size_t limit_len = attr->id == SAI_HOSTIF_ATTR_NAME ? SAI_HOSTIF_NAME_SIZE : + (attr->id == SAI_HOSTIF_ATTR_GENETLINK_MCGRP_NAME ? SAI_HOSTIF_GENETLINK_MCGRP_NAME_SIZE : + sizeof(((sai_attribute_value_t*)nullptr)->chardata)); - if (len == SAI_HOSTIF_NAME_SIZE) + size_t len = strnlen(chardata, limit_len); + + if (len == limit_len) { - META_LOG_ERROR(md, "host interface name is too long"); + META_LOG_ERROR(md, "char data is too long"); return SAI_STATUS_INVALID_PARAMETER; } if (len == 0) { - META_LOG_ERROR(md, "host interface name is zero"); + META_LOG_ERROR(md, "char data is zero"); return SAI_STATUS_INVALID_PARAMETER; } @@ -3496,7 +3502,7 @@ sai_status_t Meta::meta_generic_validation_create( if (c < 0x20 || c > 0x7e) { - META_LOG_ERROR(md, "interface name contains invalid character 0x%02x", c); + META_LOG_ERROR(md, "char data contains invalid character 0x%02x", c); return SAI_STATUS_INVALID_PARAMETER; } From 6ecf316c9067410a5259f470c15dd27d87cf7524 Mon Sep 17 00:00:00 2001 From: "Lu.Mao" Date: Sat, 15 Mar 2025 00:35:50 +0000 Subject: [PATCH 5/6] Support OTN 1. Support OTN SAI interface 2. Support OTN flex counter 3. Update SAI submodule to 202411_otn branch Signed-off-by: oplklum --- .gitmodules | 1 + debian/libsaimetadata-dev.install | 1 + meta/Makefile.am | 3 +- meta/sai_serialize_otn.cpp | 88 +++++++++++++++++ meta/sai_serialize_otn.h | 48 +++++++++ syncd/FlexCounter.cpp | 28 ++++++ syncd/FlexCounter.h | 1 + syncd/FlexCounterOtn.cpp | 158 ++++++++++++++++++++++++++++++ syncd/FlexCounterOtn.h | 119 ++++++++++++++++++++++ syncd/Makefile.am | 3 +- 10 files changed, 448 insertions(+), 2 deletions(-) create mode 100644 meta/sai_serialize_otn.cpp create mode 100644 meta/sai_serialize_otn.h create mode 100644 syncd/FlexCounterOtn.cpp create mode 100644 syncd/FlexCounterOtn.h diff --git a/.gitmodules b/.gitmodules index cea7ddefd9..9fd9de1c09 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "SAI"] path = SAI url = https://github.com/sonic-otn/SAI.git + branch = 202411_otn diff --git a/debian/libsaimetadata-dev.install b/debian/libsaimetadata-dev.install index 7421e79035..aff4dd3e47 100644 --- a/debian/libsaimetadata-dev.install +++ b/debian/libsaimetadata-dev.install @@ -7,6 +7,7 @@ meta/OidRefCounter.h usr/include/sai meta/PortRelatedSet.h usr/include/sai meta/Notification*.h usr/include/sai meta/Globals.h usr/include/sai +meta/sai_serialize_otn.h usr/include/sai SAI/meta/sai*.h usr/include/sai usr/lib/*/libsaimetadata.so usr/lib/*/libsaimeta.so diff --git a/meta/Makefile.am b/meta/Makefile.am index 81c695d2e3..03995ee413 100644 --- a/meta/Makefile.am +++ b/meta/Makefile.am @@ -58,7 +58,8 @@ libsaimeta_la_SOURCES = \ SaiSerialize.cpp \ SelectableChannel.cpp \ DummySaiInterface.cpp \ - ZeroMQSelectableChannel.cpp + ZeroMQSelectableChannel.cpp \ + sai_serialize_otn.cpp libsaimeta_la_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) libsaimeta_la_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) $(CODE_COVERAGE_CXXFLAGS) diff --git a/meta/sai_serialize_otn.cpp b/meta/sai_serialize_otn.cpp new file mode 100644 index 0000000000..341b3b6bb8 --- /dev/null +++ b/meta/sai_serialize_otn.cpp @@ -0,0 +1,88 @@ +#include "sai_serialize_otn.h" +#include "meta/sai_serialize.h" + +std::string sai_serialize_otn_attenuator_attr( + _In_ const sai_otn_attenuator_attr_t counter) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(counter, &sai_metadata_enum_sai_otn_attenuator_attr_t); +} + +void sai_deserialize_otn_attenuator_attr( + _In_ const std::string& s, + _Out_ sai_otn_attenuator_attr_t& attr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_attenuator_attr_t, (int32_t&)attr); +} + +std::string sai_serialize_otn_oa_attr( + _In_ const sai_otn_oa_attr_t counter) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(counter, &sai_metadata_enum_sai_otn_oa_attr_t); +} + +void sai_deserialize_otn_oa_attr( + _In_ const std::string& s, + _Out_ sai_otn_oa_attr_t& attr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_oa_attr_t, (int32_t&)attr); +} + +std::string sai_serialize_otn_ocm_attr( + _In_ const sai_otn_ocm_attr_t counter) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(counter, &sai_metadata_enum_sai_otn_ocm_attr_t); +} + +void sai_deserialize_otn_ocm_attr( + _In_ const std::string& s, + _Out_ sai_otn_ocm_attr_t& attr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_ocm_attr_t, (int32_t&)attr); +} + + +std::string sai_serialize_otn_ocm_channel_attr( + _In_ const sai_otn_ocm_channel_attr_t counter) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(counter, &sai_metadata_enum_sai_otn_ocm_channel_attr_t); +} + +void sai_deserialize_otn_ocm_channel_attr( + _In_ const std::string& s, + _Out_ sai_otn_ocm_channel_attr_t& attr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_ocm_channel_attr_t, (int32_t&)attr); +} + +std::string sai_serialize_otn_osc_attr( + _In_ const sai_otn_osc_attr_t counter) +{ + SWSS_LOG_ENTER(); + + return sai_serialize_enum(counter, &sai_metadata_enum_sai_otn_osc_attr_t); +} + +void sai_deserialize_otn_osc_attr( + _In_ const std::string& s, + _Out_ sai_otn_osc_attr_t& attr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_osc_attr_t, (int32_t&)attr); +} diff --git a/meta/sai_serialize_otn.h b/meta/sai_serialize_otn.h new file mode 100644 index 0000000000..6949764625 --- /dev/null +++ b/meta/sai_serialize_otn.h @@ -0,0 +1,48 @@ +#pragma once + +extern "C" { +#include "sai.h" +#include "saimetadata.h" +} + +#include + +// OTN attenuator +std::string sai_serialize_otn_attenuator_attr( + _In_ const sai_otn_attenuator_attr_t counter); + +void sai_deserialize_otn_attenuator_attr( + _In_ const std::string& s, + _Out_ sai_otn_attenuator_attr_t& attr); + +// OTN oa +std::string sai_serialize_otn_oa_attr( + _In_ const sai_otn_oa_attr_t counter); + +void sai_deserialize_otn_oa_attr( + _In_ const std::string& s, + _Out_ sai_otn_oa_attr_t& attr); + +// OTN ocm +std::string sai_serialize_otn_ocm_attr( + _In_ const sai_otn_ocm_attr_t counter); + +void sai_deserialize_otn_ocm_attr( + _In_ const std::string& s, + _Out_ sai_otn_ocm_attr_t& attr); + +// OTN ocm channel +std::string sai_serialize_otn_ocm_channel_attr( + _In_ const sai_otn_ocm_channel_attr_t counter); + +void sai_deserialize_otn_ocm_channel_attr( + _In_ const std::string& s, + _Out_ sai_otn_ocm_channel_attr_t& attr); + +// OTN osc +std::string sai_serialize_otn_osc_attr( + _In_ const sai_otn_osc_attr_t counter); + +void sai_deserialize_otn_osc_attr( + _In_ const std::string& s, + _Out_ sai_otn_osc_attr_t& attr); diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index 91dc8a3993..f179bb08a2 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -2964,6 +2964,8 @@ class DashMeterCounterContext : public BaseCounterContext bool m_initalized = false; }; +FLEX_COUNTER_OTN_IMPLEMENT(); + FlexCounter::FlexCounter( _In_ const std::string& instanceId, _In_ std::shared_ptr vendorSai, @@ -2981,6 +2983,10 @@ FlexCounter::FlexCounter( m_enable = false; m_isDiscarded = false; + m_flexCounterOtn = make_shared( + std::bind(&FlexCounter::getCounterContext, this, std::placeholders::_1), + std::bind(&FlexCounter::hasCounterContext, this, std::placeholders::_1)); + startFlexCounterThread(); } @@ -3125,6 +3131,11 @@ void FlexCounter::addCounterPlugin( } else { + if (m_flexCounterOtn ->addCounterPlugin(field, shaStrings)) + { + continue; + } + SWSS_LOG_ERROR("Field is not supported %s", field.c_str()); } } @@ -3332,6 +3343,13 @@ std::shared_ptr FlexCounter::createCounterContext( return context; } + // Create OTN counter context here + auto otn_context = createOtnCounterContext(context_name, m_vendorSai, m_statsMode); + if (otn_context != nullptr) + { + return otn_context; + } + SWSS_LOG_THROW("Invalid counter type %s", context_name.c_str()); // GCC 8.3 requires a return value here return nullptr; @@ -3661,6 +3679,11 @@ void FlexCounter::removeCounter( } else { + if (m_flexCounterOtn->removeCounter(vid, objectType)) + { + return; + } + SWSS_LOG_ERROR("Object type for removal not supported, %s", sai_serialize_object_type(objectType).c_str()); } @@ -3707,6 +3730,11 @@ void FlexCounter::addCounter( } else { + if (m_flexCounterOtn->addCounter(vid, rid, objectType, field, idStrings)) + { + continue; + } + SWSS_LOG_ERROR("Object type and field combination is not supported, object type %s, field %s", sai_serialize_object_type(objectType).c_str(), field.c_str()); diff --git a/syncd/FlexCounter.h b/syncd/FlexCounter.h index 1de7157c96..bb6fd72f1e 100644 --- a/syncd/FlexCounter.h +++ b/syncd/FlexCounter.h @@ -5,6 +5,7 @@ extern "C" { } #include "meta/SaiInterface.h" +#include "FlexCounterOtn.h" #include "swss/table.h" diff --git a/syncd/FlexCounterOtn.cpp b/syncd/FlexCounterOtn.cpp new file mode 100644 index 0000000000..055f576012 --- /dev/null +++ b/syncd/FlexCounterOtn.cpp @@ -0,0 +1,158 @@ +#include "FlexCounterOtn.h" +#include "FlexCounter.h" + +using namespace syncd; +using namespace std; + + +const std::string FlexCounterOtn::COUNTER_TYPE_OTN_ATTENUATOR_ATTR = "OTN Attenuator Attributes Counter"; +const std::string FlexCounterOtn::COUNTER_TYPE_OTN_OA_ATTR = "OTN OA Attributes Counter"; +const std::string FlexCounterOtn::COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR = "OTN OCM Channel Attributes Counter"; +const std::string FlexCounterOtn::COUNTER_TYPE_OTN_OSC_ATTR = "OTN OSC Attributes Counter"; + + +FlexCounterOtn::FlexCounterOtn( + std::function(_In_ const std::string &name)> getCounterContext, + std::function hasCounterContext): +m_getCounterContext(getCounterContext), +m_hasCounterContext(hasCounterContext) +{ + SWSS_LOG_ENTER(); +} + +FlexCounterOtn::~FlexCounterOtn() +{ + SWSS_LOG_ENTER(); +} + +bool FlexCounterOtn::addCounter( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ sai_object_type_t objectType, + _In_ const std::string &field, + _In_ const std::vector &idStrings) +{ + SWSS_LOG_ENTER(); + + sai_object_type_extensions_t extObjectType = (sai_object_type_extensions_t)objectType; + if (extObjectType == SAI_OBJECT_TYPE_OTN_ATTENUATOR && field == OTN_ATTENUATOR_ATTR_ID_LIST) + { + m_getCounterContext(COUNTER_TYPE_OTN_ATTENUATOR_ATTR)->addObject( + vid, + rid, + idStrings, + ""); + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OA && field == OTN_OA_ATTR_ID_LIST) + { + m_getCounterContext(COUNTER_TYPE_OTN_OA_ATTR)->addObject( + vid, + rid, + idStrings, + ""); + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OCM_CHANNEL && field == OTN_OCM_CHANNEL_ATTR_ID_LIST) + { + m_getCounterContext(COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR)->addObject( + vid, + rid, + idStrings, + ""); + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OSC && field == OTN_OSC_ATTR_ID_LIST) + { + m_getCounterContext(COUNTER_TYPE_OTN_OSC_ATTR)->addObject( + vid, + rid, + idStrings, + ""); + return true; + } + + return false; +} + +bool FlexCounterOtn::removeCounter( + _In_ sai_object_id_t vid, + _In_ sai_object_type_t objectType) +{ + SWSS_LOG_ENTER(); + + sai_object_type_extensions_t extObjectType = (sai_object_type_extensions_t)objectType; + if (extObjectType == SAI_OBJECT_TYPE_OTN_ATTENUATOR) + { + if (m_hasCounterContext(COUNTER_TYPE_OTN_ATTENUATOR_ATTR)) + { + m_getCounterContext(COUNTER_TYPE_OTN_ATTENUATOR_ATTR)->removeObject(vid); + } + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OA) + { + if (m_hasCounterContext(COUNTER_TYPE_OTN_OA_ATTR)) + { + m_getCounterContext(COUNTER_TYPE_OTN_OA_ATTR)->removeObject(vid); + } + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OCM_CHANNEL) + { + if (m_hasCounterContext(COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR)) + { + m_getCounterContext(COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR)->removeObject(vid); + } + return true; + } + + if (extObjectType == SAI_OBJECT_TYPE_OTN_OSC) + { + if (m_hasCounterContext(COUNTER_TYPE_OTN_OSC_ATTR)) + { + m_getCounterContext(COUNTER_TYPE_OTN_OSC_ATTR)->removeObject(vid); + } + return true; + } + + return false; +} + +bool FlexCounterOtn::addCounterPlugin( + _In_ const std::string &field, + _In_ const std::vector &shaStrings) +{ + SWSS_LOG_ENTER(); + + if (field == OTN_ATTENUATOR_PLUGIN_FIELD) + { + m_getCounterContext(COUNTER_TYPE_OTN_ATTENUATOR_ATTR)->addPlugins(shaStrings); + return true; + } + + if (field == OTN_OA_PLUGIN_FIELD) + { + m_getCounterContext(COUNTER_TYPE_OTN_OA_ATTR)->addPlugins(shaStrings); + return true; + } + + if (field == OTN_OCM_CHANNEL_PLUGIN_FIELD) + { + m_getCounterContext(COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR)->addPlugins(shaStrings); + return true; + } + + if (field == OTN_OSC_PLUGIN_FIELD) + { + m_getCounterContext(COUNTER_TYPE_OTN_OSC_ATTR)->addPlugins(shaStrings); + return true; + } + + return false; +} diff --git a/syncd/FlexCounterOtn.h b/syncd/FlexCounterOtn.h new file mode 100644 index 0000000000..f21183c4ba --- /dev/null +++ b/syncd/FlexCounterOtn.h @@ -0,0 +1,119 @@ +#pragma once + +extern "C" { +#include "sai.h" +} + +#include "meta/SaiInterface.h" +#include "meta/sai_serialize_otn.h" + +#include +#include +#include + +namespace syncd +{ + class BaseCounterContext; + + class FlexCounterOtn + { + public: + FlexCounterOtn( + std::function(_In_ const std::string &name)> getCounterContext, + std::function hasCounterContext); + virtual ~FlexCounterOtn(); + + bool addCounter( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ sai_object_type_t objectType, + _In_ const std::string &field, + _In_ const std::vector &idStrings); + + bool removeCounter( + _In_ sai_object_id_t vid, + _In_ sai_object_type_t objectType); + + bool addCounterPlugin( + _In_ const std::string &field, + _In_ const std::vector &shaStrings); + + public: + static const std::string COUNTER_TYPE_OTN_ATTENUATOR_ATTR; + static const std::string COUNTER_TYPE_OTN_OA_ATTR; + static const std::string COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR; + static const std::string COUNTER_TYPE_OTN_OSC_ATTR; + + private: + std::function(_In_ const std::string &name)> m_getCounterContext; + std::function m_hasCounterContext; + }; + + + #define FLEX_COUNTER_OTN_IMPLEMENT() \ + std::shared_ptr createOtnCounterContext( \ + _In_ const std::string &context_name, \ + _In_ std::shared_ptr vendorSai, \ + _In_ sai_stats_mode_t statsMode) \ + { \ + SWSS_LOG_ENTER(); \ + if (context_name == FlexCounterOtn::COUNTER_TYPE_OTN_ATTENUATOR_ATTR)\ + { \ + return std::make_shared>(context_name, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_ATTENUATOR, vendorSai.get(), statsMode);\ + } \ + \ + if (context_name == FlexCounterOtn::COUNTER_TYPE_OTN_OA_ATTR)\ + { \ + return std::make_shared>(context_name, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_OA, vendorSai.get(), statsMode);\ + } \ + \ + if (context_name == FlexCounterOtn::COUNTER_TYPE_OTN_OCM_CHANNEL_ATTR)\ + { \ + return std::make_shared>(context_name, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_OCM_CHANNEL, vendorSai.get(), statsMode);\ + } \ + \ + if (context_name == FlexCounterOtn::COUNTER_TYPE_OTN_OSC_ATTR)\ + { \ + return std::make_shared>(context_name, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_OSC, vendorSai.get(), statsMode);\ + } \ + \ + return nullptr; \ + } \ + \ + template <> \ + void deserializeAttr( \ + _In_ const std::string &name, \ + _Out_ sai_otn_attenuator_attr_t &attr) \ + { \ + SWSS_LOG_ENTER(); \ + sai_deserialize_otn_attenuator_attr(name, attr); \ + } \ + \ + template <> \ + void deserializeAttr( \ + _In_ const std::string &name, \ + _Out_ sai_otn_oa_attr_t &attr) \ + { \ + SWSS_LOG_ENTER(); \ + sai_deserialize_otn_oa_attr(name, attr); \ + } \ + \ + template <> \ + void deserializeAttr( \ + _In_ const std::string &name, \ + _Out_ sai_otn_ocm_channel_attr_t &attr) \ + { \ + SWSS_LOG_ENTER(); \ + sai_deserialize_otn_ocm_channel_attr(name, attr); \ + } \ + \ + template <> \ + void deserializeAttr( \ + _In_ const std::string &name, \ + _Out_ sai_otn_osc_attr_t &attr) \ + { \ + SWSS_LOG_ENTER(); \ + sai_deserialize_otn_osc_attr(name, attr); \ + } + +} diff --git a/syncd/Makefile.am b/syncd/Makefile.am index cf6af17ab1..358dcdc296 100644 --- a/syncd/Makefile.am +++ b/syncd/Makefile.am @@ -59,7 +59,8 @@ libSyncd_a_SOURCES = \ WatchdogScope.cpp \ Workaround.cpp \ ZeroMQNotificationProducer.cpp \ - syncd_main.cpp + syncd_main.cpp \ + FlexCounterOtn.cpp libSyncd_a_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) libSyncd_a_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) $(CODE_COVERAGE_CXXFLAGS) From 10355ac7ff5a2bca7f0d79132a25bac8227375fe Mon Sep 17 00:00:00 2001 From: Jimmy Jin Date: Fri, 27 Feb 2026 16:02:07 -0800 Subject: [PATCH 6/6] Support OTN alarm event notification (excluding SAI submodule update) Made-with: Cursor --- SAI | 2 +- meta/Makefile.am | 1 + meta/Meta.cpp | 64 ++++++++++ meta/Meta.h | 11 +- meta/NotificationFactory.cpp | 4 + meta/NotificationOtnAlarmEvent.cpp | 80 +++++++++++++ meta/NotificationOtnAlarmEvent.h | 35 ++++++ meta/sai_serialize.h | 5 + meta/sai_serialize_otn.cpp | 98 ++++++++++++++++ meta/sai_serialize_otn.h | 14 +++ proxylib/Proxy.cpp | 12 ++ proxylib/Proxy.h | 4 + pyext/pysairedis.i | 4 + saiplayer/SaiPlayer.cpp | 11 ++ saiplayer/SaiPlayer.h | 4 + syncd/NotificationHandler.cpp | 12 ++ syncd/NotificationHandler.h | 4 + syncd/NotificationProcessor.cpp | 40 +++++++ syncd/NotificationProcessor.h | 7 ++ syncd/SwitchNotifications.cpp | 10 ++ syncd/SwitchNotifications.h | 19 ++- syncd/Syncd.cpp | 1 + unittest/meta/Makefile.am | 1 + unittest/meta/TestDummySaiInterface.cpp | 16 +++ .../meta/TestNotificationOtnAlarmEvent.cpp | 110 ++++++++++++++++++ unittest/proxylib/TestProxy.cpp | 18 ++- unittest/proxylib/TestSai.cpp | 20 +++- 27 files changed, 600 insertions(+), 7 deletions(-) create mode 100644 meta/NotificationOtnAlarmEvent.cpp create mode 100644 meta/NotificationOtnAlarmEvent.h create mode 100644 unittest/meta/TestNotificationOtnAlarmEvent.cpp diff --git a/SAI b/SAI index fe62f9aa6e..a73e92089a 160000 --- a/SAI +++ b/SAI @@ -1 +1 @@ -Subproject commit fe62f9aa6edead354b0dc4a1cdd4337bdfe50690 +Subproject commit a73e92089aa593afc9dfcd9c24219cd0d7081648 diff --git a/meta/Makefile.am b/meta/Makefile.am index 03995ee413..4855e448c5 100644 --- a/meta/Makefile.am +++ b/meta/Makefile.am @@ -45,6 +45,7 @@ libsaimeta_la_SOURCES = \ NotificationTamTelTypeConfigChange.cpp \ NotificationSwitchMacsecPostStatus.cpp \ NotificationMacsecPostStatus.cpp \ + NotificationOtnAlarmEvent.cpp \ NumberOidIndexGenerator.cpp \ OidRefCounter.cpp \ PerformanceIntervalTimer.cpp \ diff --git a/meta/Meta.cpp b/meta/Meta.cpp index d3021916a5..47703f0528 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -7597,3 +7597,67 @@ std::vector Meta::getValidIcmpEchoSessionObjectTypes() return v; } + +void Meta::meta_sai_on_otn_alarm_event_single( + _In_ const sai_otn_alarm_event_data_t& data) +{ + SWSS_LOG_ENTER(); + + auto ot = objectTypeQuery(data.object_id); + + bool valid = false; + + switch ((int)ot) + { + // TODO hardcoded types, must advance SAI repository commit to get metadata for this + case SAI_OBJECT_TYPE_OTN_DEVICE: + case SAI_OBJECT_TYPE_OTN_ATTENUATOR: + case SAI_OBJECT_TYPE_OTN_OA: + case SAI_OBJECT_TYPE_OTN_OCM: + case SAI_OBJECT_TYPE_OTN_OCM_CHANNEL: + case SAI_OBJECT_TYPE_OTN_OSC: + + valid = true; + break; + + default: + + SWSS_LOG_ERROR("data.object_id %s has unexpected type: %s, expected OTN_DEVICE", + sai_serialize_object_id(data.object_id).c_str(), + sai_serialize_object_type(ot).c_str()); + break; + } + + if (valid && !m_oids.objectReferenceExists(data.object_id)) + { + SWSS_LOG_NOTICE("data.object_id new object spotted %s not present in local DB (snoop!)", + sai_serialize_object_id(data.object_id).c_str()); + + sai_object_meta_key_t key = { .objecttype = (sai_object_type_t)ot, .objectkey = { .key = { .object_id = data.object_id } } }; + + m_oids.objectReferenceInsert(data.object_id); + + if (!m_saiObjectCollection.objectExists(key)) + { + m_saiObjectCollection.createObject(key); + } + } +} + +void Meta::meta_sai_on_otn_alarm_event( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + if (count && data == NULL) + { + SWSS_LOG_ERROR("sai_otn_alarm_event_notification_data_t pointer is NULL but count is %u", count); + return; + } + + for (uint32_t i = 0; i < count; ++i) + { + meta_sai_on_otn_alarm_event_single(data[i]); + } +} diff --git a/meta/Meta.h b/meta/Meta.h index 85d3466584..817ecd3039 100644 --- a/meta/Meta.h +++ b/meta/Meta.h @@ -273,7 +273,11 @@ namespace saimeta void meta_sai_on_tam_tel_type_config_change(_In_ sai_object_id_t m_tam_id); - private: // notifications helpers + void meta_sai_on_otn_alarm_event( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data); + + private: // notifications helpers void meta_sai_on_fdb_flush_event_consolidated( _In_ const sai_fdb_event_notification_data_t& data); @@ -308,7 +312,10 @@ namespace saimeta void meta_sai_on_twamp_session_event_single( _In_ const sai_twamp_session_event_notification_data_t& data); - private: // validation helpers + void meta_sai_on_otn_alarm_event_single( + _In_ const sai_otn_alarm_event_data_t& data); + + private: // validation helpers sai_status_t meta_generic_validation_objlist( _In_ const sai_attr_metadata_t& md, diff --git a/meta/NotificationFactory.cpp b/meta/NotificationFactory.cpp index fe8769d4d8..e849ae643e 100644 --- a/meta/NotificationFactory.cpp +++ b/meta/NotificationFactory.cpp @@ -16,6 +16,7 @@ #include "NotificationFlowBulkGetSessionEvent.h" #include "NotificationSwitchMacsecPostStatus.h" #include "NotificationMacsecPostStatus.h" +#include "NotificationOtnAlarmEvent.h" #include "sairediscommon.h" #include "swss/logger.h" @@ -79,5 +80,8 @@ std::shared_ptr NotificationFactory::deserialize( if (name == SAI_SWITCH_NOTIFICATION_NAME_MACSEC_POST_STATUS) return std::make_shared(serializedNotification); + if (name == SAI_SWITCH_NOTIFICATION_NAME_OTN_ALARM_EVENT) + return std::make_shared(serializedNotification); + SWSS_LOG_THROW("unknown notification: '%s', FIXME", name.c_str()); } diff --git a/meta/NotificationOtnAlarmEvent.cpp b/meta/NotificationOtnAlarmEvent.cpp new file mode 100644 index 0000000000..e3b8f396f6 --- /dev/null +++ b/meta/NotificationOtnAlarmEvent.cpp @@ -0,0 +1,80 @@ +#include "NotificationOtnAlarmEvent.h" + +#include "swss/logger.h" + +#include "meta/sai_serialize_otn.h" + +using namespace sairedis; + +NotificationOtnAlarmEvent::NotificationOtnAlarmEvent( + _In_ const std::string& serializeNotification): + Notification( + SAI_SWITCH_NOTIFICATION_TYPE_OTN_ALARM_EVENT, + serializeNotification), + m_otnAlarmEventData(nullptr) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_otn_alarm_event_ntf( + serializeNotification, + m_count, + &m_otnAlarmEventData); +} + +NotificationOtnAlarmEvent::~NotificationOtnAlarmEvent() +{ + SWSS_LOG_ENTER(); + + sai_deserialize_free_otn_alarm_event_ntf(m_count, m_otnAlarmEventData); +} + +sai_object_id_t NotificationOtnAlarmEvent::getSwitchId() const +{ + SWSS_LOG_ENTER(); + + // Otn alarm event does not have switch id + return SAI_NULL_OBJECT_ID; +} + +sai_object_id_t NotificationOtnAlarmEvent::getAnyObjectId() const +{ + SWSS_LOG_ENTER(); + + if (m_otnAlarmEventData == nullptr) + { + return SAI_NULL_OBJECT_ID; + } + + for (uint32_t i = 0; i < m_count; ++i) + { + if (m_otnAlarmEventData[i].object_id != SAI_NULL_OBJECT_ID) + { + return m_otnAlarmEventData[i].object_id; + } + } + + return SAI_NULL_OBJECT_ID; +} + +void NotificationOtnAlarmEvent::processMetadata( + _In_ std::shared_ptr meta) const +{ + SWSS_LOG_ENTER(); + + meta->meta_sai_on_otn_alarm_event( + m_count, + m_otnAlarmEventData); +} + +void NotificationOtnAlarmEvent::executeCallback( + _In_ const sai_switch_notifications_t& switchNotifications) const +{ + SWSS_LOG_ENTER(); + + if(switchNotifications.on_otn_alarm_event) + { + switchNotifications.on_otn_alarm_event( + m_count, + m_otnAlarmEventData); + } +} diff --git a/meta/NotificationOtnAlarmEvent.h b/meta/NotificationOtnAlarmEvent.h new file mode 100644 index 0000000000..33749cd096 --- /dev/null +++ b/meta/NotificationOtnAlarmEvent.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Notification.h" + +namespace sairedis +{ + class NotificationOtnAlarmEvent: + public Notification + { + public: + + NotificationOtnAlarmEvent( + _In_ const std::string& serializedNotification); + + virtual ~NotificationOtnAlarmEvent(); + + public: + + virtual sai_object_id_t getSwitchId() const override; + + virtual sai_object_id_t getAnyObjectId() const override; + + virtual void processMetadata( + _In_ std::shared_ptr meta) const override; + + virtual void executeCallback( + _In_ const sai_switch_notifications_t& switchNotifications) const override; + + private: + + uint32_t m_count; + + sai_otn_alarm_event_data_t* m_otnAlarmEventData; + }; +} diff --git a/meta/sai_serialize.h b/meta/sai_serialize.h index 2a9ec67363..c459cecf2c 100644 --- a/meta/sai_serialize.h +++ b/meta/sai_serialize.h @@ -820,3 +820,8 @@ void sai_deserialize_macsec_post_status_ntf( _In_ const std::string& s, _Out_ sai_object_id_t& macsec_id, _Out_ sai_macsec_post_status_t& macsec_post_status); + +void sai_deserialize_hex_binary( + _In_ const std::string &s, + _Out_ void *buffer, + _In_ size_t length); diff --git a/meta/sai_serialize_otn.cpp b/meta/sai_serialize_otn.cpp index 341b3b6bb8..65f41b1bee 100644 --- a/meta/sai_serialize_otn.cpp +++ b/meta/sai_serialize_otn.cpp @@ -1,5 +1,9 @@ #include "sai_serialize_otn.h" #include "meta/sai_serialize.h" +#include + +using json = nlohmann::json; + std::string sai_serialize_otn_attenuator_attr( _In_ const sai_otn_attenuator_attr_t counter) @@ -86,3 +90,97 @@ void sai_deserialize_otn_osc_attr( sai_deserialize_enum(s, &sai_metadata_enum_sai_otn_osc_attr_t, (int32_t&)attr); } + +std::string sai_serialize_otn_alarm_event_ntf( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t* otn_alarm_event) +{ + SWSS_LOG_ENTER(); + + if (otn_alarm_event == NULL) + { + SWSS_LOG_THROW("otn_alarm_event pointer is null"); + } + + json j = json::array(); + + for (uint32_t i = 0; i < count; ++i) + { + json item; + + item["object_id"] = sai_serialize_object_id(otn_alarm_event[i].object_id); + /* cast from uint8_t* to string */ + item["event_name"] = std::string((char*)otn_alarm_event[i].event_name.list, otn_alarm_event[i].event_name.count); + item["timestamp"] = sai_serialize_timespec(otn_alarm_event[i].timestamp); + item["severity"] = sai_serialize_enum(otn_alarm_event[i].severity, &sai_metadata_enum_sai_otn_alarm_severity_t); + item["action"] = sai_serialize_enum(otn_alarm_event[i].action, &sai_metadata_enum_sai_otn_alarm_action_t); + /* cast from uint8_t* to string */ + item["description"] = std::string((char*)otn_alarm_event[i].description.list, otn_alarm_event[i].description.count); + /* cast from uint8_t* to hex binary */ + item["data"] = sai_serialize_hex_binary(otn_alarm_event[i].data.list, otn_alarm_event[i].data.count); + j.push_back(item); + } + + return j.dump(); +} + +void sai_deserialize_otn_alarm_event_ntf( + _In_ const std::string& s, + _Out_ uint32_t& count, + _Out_ sai_otn_alarm_event_data_t** otn_alarm_event) +{ + SWSS_LOG_ENTER(); + + json j = json::parse(s); + + count = (uint32_t)j.size(); + + auto data = new sai_otn_alarm_event_data_t[count]; + + for (uint32_t i = 0; i < count; ++i) + { + sai_deserialize_object_id(j[i]["object_id"], data[i].object_id); + + std::string s_event_name = j[i]["event_name"]; + data[i].event_name.count = (uint32_t)s_event_name.length(); + data[i].event_name.list = new uint8_t[data[i].event_name.count + 1]; + memcpy(data[i].event_name.list, s_event_name.c_str(), data[i].event_name.count + 1); + + sai_deserialize_timespec(j[i]["timestamp"], data[i].timestamp); + + int32_t val; + sai_deserialize_enum(j[i]["severity"], &sai_metadata_enum_sai_otn_alarm_severity_t, val); + data[i].severity = (sai_otn_alarm_severity_t)val; + + sai_deserialize_enum(j[i]["action"], &sai_metadata_enum_sai_otn_alarm_action_t, val); + data[i].action = (sai_otn_alarm_action_t)val; + + std::string s_desc = j[i]["description"]; + data[i].description.count = (uint32_t)s_desc.length(); + data[i].description.list = new uint8_t[data[i].description.count + 1]; + memcpy(data[i].description.list, s_desc.c_str(), data[i].description.count + 1); + + std::string s_data = j[i]["data"]; + data[i].data.count = (uint32_t)s_data.length() / 2; + data[i].data.list = new uint8_t[data[i].data.count]; + sai_deserialize_hex_binary(s_data, data[i].data.list, data[i].data.count); + } + + *otn_alarm_event = data; +} + +void sai_deserialize_free_otn_alarm_event_ntf( + _In_ uint32_t count, + _In_ sai_otn_alarm_event_data_t* otn_alarm_event) +{ + SWSS_LOG_ENTER(); + + for (uint32_t i = 0; i < count; ++i) + { + delete[] otn_alarm_event[i].event_name.list; + delete[] otn_alarm_event[i].description.list; + delete[] otn_alarm_event[i].data.list; + } + + delete[] otn_alarm_event; +} diff --git a/meta/sai_serialize_otn.h b/meta/sai_serialize_otn.h index 6949764625..3dad05c674 100644 --- a/meta/sai_serialize_otn.h +++ b/meta/sai_serialize_otn.h @@ -46,3 +46,17 @@ std::string sai_serialize_otn_osc_attr( void sai_deserialize_otn_osc_attr( _In_ const std::string& s, _Out_ sai_otn_osc_attr_t& attr); + +// OTN alarm event notification +std::string sai_serialize_otn_alarm_event_ntf( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *otn_alarm_event); + +void sai_deserialize_otn_alarm_event_ntf( + _In_ const std::string& s, + _Out_ uint32_t& count, + _Out_ sai_otn_alarm_event_data_t** otn_alarm_event); + +void sai_deserialize_free_otn_alarm_event_ntf( + _In_ uint32_t count, + _In_ sai_otn_alarm_event_data_t* otn_alarm_event); diff --git a/proxylib/Proxy.cpp b/proxylib/Proxy.cpp index b48e20fc4a..6021df0ca0 100644 --- a/proxylib/Proxy.cpp +++ b/proxylib/Proxy.cpp @@ -6,6 +6,7 @@ #include "meta/SaiAttributeList.h" #include "meta/sai_serialize.h" +#include "meta/sai_serialize_otn.h" #include "meta/ZeroMQSelectableChannel.h" #include "syncd/ZeroMQNotificationProducer.h" @@ -1296,3 +1297,14 @@ uint64_t Proxy::getNotificationsSentCount() const return m_notificationsSentCount; } + +void Proxy::onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + std::string s = sai_serialize_otn_alarm_event_ntf(count, data); + + sendNotification(SAI_SWITCH_NOTIFICATION_NAME_OTN_ALARM_EVENT, s); +} diff --git a/proxylib/Proxy.h b/proxylib/Proxy.h index 6c3df76e0d..fd98ed69a3 100644 --- a/proxylib/Proxy.h +++ b/proxylib/Proxy.h @@ -172,6 +172,10 @@ namespace saiproxy void onTamTelTypeConfigChange( _In_ sai_object_id_t tam_tel_id); + void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data); + void sendNotification( _In_ const std::string& op, _In_ const std::string& data); diff --git a/pyext/pysairedis.i b/pyext/pysairedis.i index d749d4efaa..fee151fa07 100644 --- a/pyext/pysairedis.i +++ b/pyext/pysairedis.i @@ -84,6 +84,8 @@ sai_ip_prefix_t* sai_ip_prefix_t_from_string(const std::string& s); %pointer_functions(sai_port_oper_status_notification_t, sai_port_oper_status_notification_t_p); %array_functions(sai_queue_deadlock_notification_data_t, sai_queue_deadlock_notification_data_t_arr); %pointer_functions(sai_queue_deadlock_notification_data_t, sai_queue_deadlock_notification_data_t_p); +%array_functions(sai_otn_alarm_event_data_t, sai_otn_alarm_event_data_t_arr); +%pointer_functions(sai_otn_alarm_event_data_t, sai_otn_alarm_event_data_t_p); %{ PyObject *py_convert_sai_fdb_event_notification_data_t_to_PyObject(const sai_fdb_event_notification_data_t*ntf) @@ -102,6 +104,8 @@ PyObject *py_convert_sai_port_oper_status_notification_t_to_PyObject(const sai_p { return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_port_oper_status_notification_t, 0 | 0); } PyObject *py_convert_sai_queue_deadlock_notification_data_t_to_PyObject(const sai_queue_deadlock_notification_data_t*ntf) { return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_queue_deadlock_notification_data_t, 0 | 0); } +PyObject *py_convert_sai_otn_alarm_event_data_t_to_PyObject(const sai_otn_alarm_event_data_t*ntf) +{ return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_otn_alarm_event_data_t, 0 | 0); } %} diff --git a/saiplayer/SaiPlayer.cpp b/saiplayer/SaiPlayer.cpp index eff9a8e5a6..65090c34c3 100644 --- a/saiplayer/SaiPlayer.cpp +++ b/saiplayer/SaiPlayer.cpp @@ -96,6 +96,8 @@ SaiPlayer::SaiPlayer( m_sn.onFlowBulkGetSessionEvent = std::bind(&SaiPlayer::onFlowBulkGetSessionEvent, this, _1, _2, _3); m_sn.onPortHostTxReady = std::bind(&SaiPlayer::onPortHostTxReady, this, _1, _2, _3); m_sn.onIcmpEchoSessionStateChange = std::bind(&SaiPlayer::onIcmpEchoSessionStateChange, this, _1, _2); + m_sn.onOtnAlarmEvent = std::bind(&SaiPlayer::onOtnAlarmEvent, this, _1, _2); + m_switchNotifications= m_sn.getSwitchNotifications(); } @@ -227,6 +229,15 @@ void SaiPlayer::onPortHostTxReady( // empty } +void SaiPlayer::onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + // empty +} + void SaiPlayer::onQueuePfcDeadlock( _In_ uint32_t count, _In_ const sai_queue_deadlock_notification_data_t *data) diff --git a/saiplayer/SaiPlayer.h b/saiplayer/SaiPlayer.h index da320a16de..40ab06447e 100644 --- a/saiplayer/SaiPlayer.h +++ b/saiplayer/SaiPlayer.h @@ -289,6 +289,10 @@ namespace saiplayer _In_ sai_object_id_t port_id, _In_ sai_port_host_tx_ready_status_t host_tx_ready_status); + void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data); + private: std::shared_ptr m_sai; diff --git a/syncd/NotificationHandler.cpp b/syncd/NotificationHandler.cpp index 9918ecbd15..cb339c19eb 100644 --- a/syncd/NotificationHandler.cpp +++ b/syncd/NotificationHandler.cpp @@ -6,6 +6,7 @@ #include "swss/logger.h" #include "meta/sai_serialize.h" +#include "meta/sai_serialize_otn.h" #include @@ -329,6 +330,17 @@ void NotificationHandler::onMacsecPostStatus( enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_MACSEC_POST_STATUS, s); } +void NotificationHandler::onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + std::string s = sai_serialize_otn_alarm_event_ntf(count, data); + + enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_OTN_ALARM_EVENT, s); +} + void NotificationHandler::enqueueNotification( _In_ const std::string& op, _In_ const std::string& data) diff --git a/syncd/NotificationHandler.h b/syncd/NotificationHandler.h index 440b29cd72..99591f8475 100644 --- a/syncd/NotificationHandler.h +++ b/syncd/NotificationHandler.h @@ -116,6 +116,10 @@ namespace syncd _In_ sai_object_id_t macsec_id, _In_ sai_macsec_post_status_t macsec_post_status); + void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data); + private: void enqueueNotification( diff --git a/syncd/NotificationProcessor.cpp b/syncd/NotificationProcessor.cpp index 1bd5ce0b97..6dbd44d270 100644 --- a/syncd/NotificationProcessor.cpp +++ b/syncd/NotificationProcessor.cpp @@ -5,6 +5,7 @@ #include "sairediscommon.h" #include "meta/sai_serialize.h" +#include "meta/sai_serialize_otn.h" #include "meta/SaiAttributeList.h" #include "swss/logger.h" @@ -679,6 +680,26 @@ void NotificationProcessor::process_on_twamp_session_event( sendNotification(SAI_SWITCH_NOTIFICATION_NAME_TWAMP_SESSION_EVENT, s); } +void NotificationProcessor::process_on_otn_alarm_event( + _In_ uint32_t count, + _In_ sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_DEBUG("otn alarm event notification count: %u", count); + + for (uint32_t i = 0; i < count; i++) + { + sai_otn_alarm_event_data_t *otn_alarm_event = &data[i]; + + otn_alarm_event->object_id = m_translator->translateRidToVid(otn_alarm_event->object_id, SAI_NULL_OBJECT_ID); + } + + std::string s = sai_serialize_otn_alarm_event_ntf(count, data); + + sendNotification(SAI_SWITCH_NOTIFICATION_NAME_OTN_ALARM_EVENT, s); +} + void NotificationProcessor::handle_switch_state_change( _In_ const std::string &data) { @@ -990,6 +1011,21 @@ void NotificationProcessor::handle_macsec_post_status( sai_serialize_macsec_post_status(macsec_post_status)); } +void NotificationProcessor::handle_otn_alarm_event( + _In_ const std::string &data) +{ + SWSS_LOG_ENTER(); + + uint32_t count; + sai_otn_alarm_event_data_t *otn_alarm_event = NULL; + + sai_deserialize_otn_alarm_event_ntf(data, count, &otn_alarm_event); + + process_on_otn_alarm_event(count, otn_alarm_event); + + sai_deserialize_free_otn_alarm_event_ntf(count, otn_alarm_event); +} + void NotificationProcessor::processNotification( _In_ const swss::KeyOpFieldsValuesTuple& item) { @@ -1094,6 +1130,10 @@ void NotificationProcessor::syncProcessNotification( { handle_flow_bulk_get_session_event(data); } + else if (notification == SAI_SWITCH_NOTIFICATION_NAME_OTN_ALARM_EVENT) + { + handle_otn_alarm_event(data); + } else { SWSS_LOG_ERROR("unknown notification: %s", notification.c_str()); diff --git a/syncd/NotificationProcessor.h b/syncd/NotificationProcessor.h index 3ee4a941cf..435d8bbd38 100644 --- a/syncd/NotificationProcessor.h +++ b/syncd/NotificationProcessor.h @@ -125,6 +125,10 @@ namespace syncd _In_ uint32_t count, _In_ sai_twamp_session_event_notification_data_t *data); + void process_on_otn_alarm_event( + _In_ uint32_t count, + _In_ sai_otn_alarm_event_data_t *data); + private: // handlers void handle_switch_state_change( @@ -179,6 +183,9 @@ namespace syncd void handle_macsec_post_status( _In_ const std::string &data); + void handle_otn_alarm_event( + _In_ const std::string &data); + void processNotification( _In_ const swss::KeyOpFieldsValuesTuple& item); diff --git a/syncd/SwitchNotifications.cpp b/syncd/SwitchNotifications.cpp index 17e9050951..6d030ef118 100644 --- a/syncd/SwitchNotifications.cpp +++ b/syncd/SwitchNotifications.cpp @@ -231,6 +231,16 @@ void SwitchNotifications::SlotBase::onSwitchIpsecPostStatus( return m_slots.at(context)->m_handler->onSwitchIpsecPostStatus(switch_id, post_status); } +void SwitchNotifications::SlotBase::onOtnAlarmEvent( + _In_ int context, + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + return m_slots.at(context)->m_handler->onOtnAlarmEvent(count, data); +} + const sai_switch_notifications_t& SwitchNotifications::SlotBase::getSwitchNotifications() const { SWSS_LOG_ENTER(); diff --git a/syncd/SwitchNotifications.h b/syncd/SwitchNotifications.h index a63a723ce5..8b665b9370 100644 --- a/syncd/SwitchNotifications.h +++ b/syncd/SwitchNotifications.h @@ -134,6 +134,11 @@ namespace syncd _In_ int context, _In_ sai_object_id_t switch_id, _In_ sai_switch_ipsec_post_status_t post_status ); + + static void onOtnAlarmEvent( + _In_ int context, + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data); protected: SwitchNotifications* m_handler; @@ -172,6 +177,7 @@ namespace syncd .on_ha_set_event = &Slot::onHaSetEvent, .on_ha_scope_event = &Slot::onHaScopeEvent, .on_flow_bulk_get_session_event = &Slot::onFlowBulkGetSessionEvent, + .on_otn_alarm_event = &Slot::onOtnAlarmEvent, }) { } virtual ~Slot() {} @@ -355,6 +361,15 @@ namespace syncd return SlotBase::onSwitchIpsecPostStatus(context, switch_id, post_status); } + + static void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) + { + SWSS_LOG_ENTER(); + + return SlotBase::onOtnAlarmEvent(context, count, data); + } }; static std::vector m_slots; @@ -395,7 +410,9 @@ namespace syncd std::function onIpsecPostStatus; std::function onSwitchMacsecPostStatus; std::function onSwitchIpsecPostStatus; - private: + std::function onOtnAlarmEvent; + + private: SlotBase*m_slot; }; diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index 1280dcbe77..cffc1e0bdb 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -185,6 +185,7 @@ Syncd::Syncd( m_sn.onHaSetEvent = std::bind(&NotificationHandler::onHaSetEvent, m_handler.get(), _1, _2); m_sn.onHaScopeEvent = std::bind(&NotificationHandler::onHaScopeEvent, m_handler.get(), _1, _2); m_sn.onFlowBulkGetSessionEvent = std::bind(&NotificationHandler::onFlowBulkGetSessionEvent, m_handler.get(), _1, _2, _3); + m_sn.onOtnAlarmEvent = std::bind(&NotificationHandler::onOtnAlarmEvent, m_handler.get(), _1, _2); m_handler->setSwitchNotifications(m_sn.getSwitchNotifications()); diff --git a/unittest/meta/Makefile.am b/unittest/meta/Makefile.am index 61f4989aa7..24d443dcb8 100644 --- a/unittest/meta/Makefile.am +++ b/unittest/meta/Makefile.am @@ -33,6 +33,7 @@ tests_SOURCES = \ TestNotificationTam.cpp \ TestNotificationMacsecPostStatus.cpp \ TestNotificationSwitchMacsecPostStatus.cpp \ + TestNotificationOtnAlarmEvent.cpp \ TestOidRefCounter.cpp \ TestPerformanceIntervalTimer.cpp \ TestPortRelatedSet.cpp \ diff --git a/unittest/meta/TestDummySaiInterface.cpp b/unittest/meta/TestDummySaiInterface.cpp index e5b98d9ac2..9d10480621 100644 --- a/unittest/meta/TestDummySaiInterface.cpp +++ b/unittest/meta/TestDummySaiInterface.cpp @@ -251,6 +251,17 @@ void onTamTelTypeConfigChange( ntfCounter++; } +static void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("received: onOtnAlarmEvent"); + + ntfCounter++; +} + TEST(DummySaiInterface, sendNotification) { DummySaiInterface sai; @@ -278,6 +289,7 @@ TEST(DummySaiInterface, sendNotification) EXPECT_EQ(sai.enqueueNotificationToSend(SAI_SWITCH_ATTR_SHUTDOWN_REQUEST_NOTIFY), SAI_STATUS_SUCCESS); EXPECT_EQ(sai.enqueueNotificationToSend(SAI_SWITCH_ATTR_TAM_TEL_TYPE_CONFIG_CHANGE_NOTIFY), SAI_STATUS_SUCCESS); + EXPECT_EQ(sai.enqueueNotificationToSend(SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY), SAI_STATUS_SUCCESS); sai_attribute_t attr; @@ -340,6 +352,10 @@ TEST(DummySaiInterface, sendNotification) attr.value.ptr = (void*)&onTamTelTypeConfigChange; sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + attr.id = SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY; + attr.value.ptr = (void*)&onOtnAlarmEvent; + sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + EXPECT_EQ(sai.start(), SAI_STATUS_SUCCESS); sleep(1); diff --git a/unittest/meta/TestNotificationOtnAlarmEvent.cpp b/unittest/meta/TestNotificationOtnAlarmEvent.cpp new file mode 100644 index 0000000000..7820a65b09 --- /dev/null +++ b/unittest/meta/TestNotificationOtnAlarmEvent.cpp @@ -0,0 +1,110 @@ +#include "MetaTestSaiInterface.h" +#include "NotificationOtnAlarmEvent.h" + +#include "sairediscommon.h" +#include "sai_serialize.h" + +#include + +#include + +using namespace sairedis; +using namespace saimeta; + +static std::string s = "[" + "{" + "\"timestamp\":\"{" + "\\\"tv_nsec\\\":\\\"28715881\\\"," + "\\\"tv_sec\\\":\\\"1700042919\\\"" + "}\"," + "\"object_id\":\"oid:0x123456789abcdef\"," + "\"event_name\": \"OTN OA LOS\"," + "\"severity\": \"SAI_OTN_ALARM_SEVERITY_CRITICAL\"," + "\"action\": \"SAI_OTN_ALARM_ACTION_RAISE\"," + "\"description\": \"OA input LOS, power -60dBm\"," + "\"data\": \"0\"" + "}" + "]"; + +static std::string null = "[" + "{" + "\"timestamp\":\"{" + "\\\"tv_nsec\\\":\\\"28715881\\\"," + "\\\"tv_sec\\\":\\\"1700042919\\\"" + "}\"," + "\"object_id\":\"oid:0x0\"," + "\"event_name\": \"OTN OA LOS\"," + "\"severity\": \"SAI_OTN_ALARM_SEVERITY_CRITICAL\"," + "\"action\": \"SAI_OTN_ALARM_ACTION_RAISE\"," + "\"description\": \"OA input LOS, power -60dBm\"," + "\"data\": \"0\"" + "}" + "]"; + +static std::string fullnull = "[]"; + +TEST(NotificationOtnAlarmEvent, otn_alarm) +{ + NotificationOtnAlarmEvent n(s); +} + +TEST(NotificationOtnAlarmEvent, getSwitchId) +{ + NotificationOtnAlarmEvent n(s); + + EXPECT_EQ(n.getSwitchId(), SAI_NULL_OBJECT_ID); + + NotificationOtnAlarmEvent n2(null); + + EXPECT_EQ(n2.getSwitchId(), SAI_NULL_OBJECT_ID); + + NotificationOtnAlarmEvent n3(fullnull); + + EXPECT_EQ(n3.getSwitchId(), SAI_NULL_OBJECT_ID); +} + +TEST(NotificationOtnAlarmEvent, getAnyObjectId) +{ + NotificationOtnAlarmEvent n(s); + + EXPECT_EQ(n.getAnyObjectId(), 0x123456789abcdef); + + NotificationOtnAlarmEvent n2(null); + + EXPECT_EQ(n2.getAnyObjectId(), SAI_NULL_OBJECT_ID); + + NotificationOtnAlarmEvent n3(fullnull); + + EXPECT_EQ(n3.getAnyObjectId(), SAI_NULL_OBJECT_ID); +} + +TEST(NotificationOtnAlarmEvent, processMetadata) +{ + NotificationOtnAlarmEvent n(s); + + auto sai = std::make_shared(); + auto meta = std::make_shared(sai); + + n.processMetadata(meta); +} + +static void on_otn_alarm_event( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("received: on_otn_alarm_event"); +} + +TEST(NotificationOtnAlarmEvent, executeCallback) +{ + NotificationOtnAlarmEvent n(s); + + sai_switch_notifications_t switchNotifications; + memset(&switchNotifications, 0, sizeof(switchNotifications)); + + switchNotifications.on_otn_alarm_event = &on_otn_alarm_event; + + n.executeCallback(switchNotifications); +} diff --git a/unittest/proxylib/TestProxy.cpp b/unittest/proxylib/TestProxy.cpp index bcb36012bb..eb65e78e02 100644 --- a/unittest/proxylib/TestProxy.cpp +++ b/unittest/proxylib/TestProxy.cpp @@ -229,6 +229,17 @@ static void onTamTelTypeConfigChange( ntfCounter++; } +static void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("received: onOtnAlarmEvent"); + + ntfCounter++; +} + TEST(Proxy, notifications) { Sai sai; @@ -251,6 +262,7 @@ TEST(Proxy, notifications) EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_ICMP_ECHO_SESSION_STATE_CHANGE_NOTIFY), SAI_STATUS_SUCCESS); EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_TWAMP_SESSION_EVENT_NOTIFY), SAI_STATUS_SUCCESS); EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_TAM_TEL_TYPE_CONFIG_CHANGE_NOTIFY), SAI_STATUS_SUCCESS); + EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY), SAI_STATUS_SUCCESS); auto thread = std::make_shared(fun,proxy); @@ -334,6 +346,10 @@ TEST(Proxy, notifications) attr.value.ptr = (void*)&onTamTelTypeConfigChange; sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + attr.id = SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY; + attr.value.ptr = (void*)&onOtnAlarmEvent; + sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + // dummy start sending notifications EXPECT_EQ(dummy->start(), SAI_STATUS_SUCCESS); @@ -342,7 +358,7 @@ TEST(Proxy, notifications) // dummy stop sending notifications EXPECT_EQ(dummy->stop(), SAI_STATUS_SUCCESS); - EXPECT_EQ(proxy->getNotificationsSentCount(), 4+7+1); + EXPECT_EQ(proxy->getNotificationsSentCount(), 4+7+1+1); proxy->stop(); diff --git a/unittest/proxylib/TestSai.cpp b/unittest/proxylib/TestSai.cpp index eb1647249e..8bf33c031d 100644 --- a/unittest/proxylib/TestSai.cpp +++ b/unittest/proxylib/TestSai.cpp @@ -759,6 +759,17 @@ static void onTamTelTypeConfigChange( ntfCounter++; } +static void onOtnAlarmEvent( + _In_ uint32_t count, + _In_ const sai_otn_alarm_event_data_t *data) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("received: onOtnAlarmEvent"); + + ntfCounter++; +} + TEST(Sai, handleNotification) { Sai sai; @@ -781,6 +792,7 @@ TEST(Sai, handleNotification) EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_ICMP_ECHO_SESSION_STATE_CHANGE_NOTIFY), SAI_STATUS_SUCCESS); EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_TWAMP_SESSION_EVENT_NOTIFY), SAI_STATUS_SUCCESS); EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_TAM_TEL_TYPE_CONFIG_CHANGE_NOTIFY), SAI_STATUS_SUCCESS); + EXPECT_EQ(dummy->enqueueNotificationToSend(SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY), SAI_STATUS_SUCCESS); auto thread = std::make_shared(fun, proxy); @@ -860,6 +872,10 @@ TEST(Sai, handleNotification) attr.value.ptr = (void*)&onTamTelTypeConfigChange; sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + attr.id = SAI_SWITCH_ATTR_OTN_ALARM_EVENT_NOTIFY; + attr.value.ptr = (void*)&onOtnAlarmEvent; + sai.set(SAI_OBJECT_TYPE_SWITCH, switch_id, &attr); + // dummy start sending notifications EXPECT_EQ(dummy->start(), SAI_STATUS_SUCCESS); @@ -868,10 +884,10 @@ TEST(Sai, handleNotification) // dummy stop sending notifications EXPECT_EQ(dummy->stop(), SAI_STATUS_SUCCESS); - EXPECT_EQ(proxy->getNotificationsSentCount(), 12); + EXPECT_EQ(proxy->getNotificationsSentCount(), 13); // important check, whether Sai class processed notifications correctly - EXPECT_EQ(ntfCounter, 12); + EXPECT_EQ(ntfCounter, 13); proxy->stop();