diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e676226d6..adabaf91b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,7 +7,7 @@ on: branches: - 'master' - '202[0-9][0-9][0-9]' - pull_request_target: + pull_request: branches: - 'master' - '202[0-9][0-9][0-9]' @@ -54,7 +54,7 @@ jobs: libyang-dev \ libzmq3-dev \ libzmq5 \ - swig3.0 \ + swig4.0 \ libpython2.7-dev \ libgtest-dev \ libgmock-dev \ diff --git a/configure.ac b/configure.ac index 5cddce073..736406841 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,10 @@ AX_ADD_AM_MACRO_STATIC([]) AM_CONDITIONAL(SONIC_ASIC_PLATFORM_BAREFOOT, test x$CONFIGURED_PLATFORM = xbarefoot) AM_CONDITIONAL(SONIC_ASIC_PLATFORM_BROADCOM, test x$CONFIGURED_PLATFORM = xbroadcom) +AM_CONDITIONAL(SONIC_ASIC_PLATFORM_MELLANOX, test x$CONFIGURED_PLATFORM = xmellanox) + +AM_COND_IF([SONIC_ASIC_PLATFORM_MELLANOX], + AC_DEFINE([MELLANOX], [1], [Define to 1 on Mellanox Platform])) AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging], @@ -144,7 +148,7 @@ fi AM_CONDITIONAL(ASAN_ENABLED, test x$asan_enabled = xtrue) AM_CONDITIONAL(PYTHON2, test x$python2 = xtrue) -AC_PATH_PROGS(SWIG, [swig3.0 swig]) +AC_PATH_PROGS(SWIG, [swig4.0 swig3.0 swig]) CXXFLAGS_COMMON="" CXXFLAGS_COMMON+=" -ansi" diff --git a/lib/RedisRemoteSaiInterface.cpp b/lib/RedisRemoteSaiInterface.cpp index 1c846fe5a..cbd8118b6 100644 --- a/lib/RedisRemoteSaiInterface.cpp +++ b/lib/RedisRemoteSaiInterface.cpp @@ -2049,6 +2049,21 @@ sai_switch_notifications_t RedisRemoteSaiInterface::syncProcessNotification( return { }; } +bool RedisRemoteSaiInterface::containsSwitch( + _In_ sai_object_id_t switchId) const +{ + SWSS_LOG_ENTER(); + + if (!m_switchContainer->contains(switchId)) + { + SWSS_LOG_INFO("context %s failed to find switch %s", + m_contextConfig->m_name.c_str(), sai_serialize_object_id(switchId).c_str()); + return false; + } + + return true; +} + const std::map& RedisRemoteSaiInterface::getTableDump() const { SWSS_LOG_ENTER(); diff --git a/lib/RedisRemoteSaiInterface.h b/lib/RedisRemoteSaiInterface.h index aa8c136cd..a97d34b62 100644 --- a/lib/RedisRemoteSaiInterface.h +++ b/lib/RedisRemoteSaiInterface.h @@ -227,6 +227,9 @@ namespace sairedis const std::map& getTableDump() const; + bool containsSwitch( + _In_ sai_object_id_t switchId) const; + private: // QUAD API helpers sai_status_t create( diff --git a/lib/Sai.cpp b/lib/Sai.cpp index 6e45c2bf6..433a421cf 100644 --- a/lib/Sai.cpp +++ b/lib/Sai.cpp @@ -224,13 +224,19 @@ sai_status_t Sai::set( // skip metadata if attribute is redis extension attribute - // TODO this is setting on all contexts, but maybe we want one specific? - // and do set on all if objectId == NULL - bool success = true; + // Setting on all contexts if objectType != SAI_OBJECT_TYPE_SWITCH or objectId == NULL for (auto& kvp: m_contextMap) { + if (objectType == SAI_OBJECT_TYPE_SWITCH && objectId != SAI_NULL_OBJECT_ID) + { + if (!kvp.second->m_redisSai->containsSwitch(objectId)) + { + continue; + } + } + sai_status_t status = kvp.second->m_redisSai->set(objectType, objectId, attr); success &= (status == SAI_STATUS_SUCCESS); diff --git a/proxylib/Proxy.cpp b/proxylib/Proxy.cpp index a844a4b2d..ab3a280e0 100644 --- a/proxylib/Proxy.cpp +++ b/proxylib/Proxy.cpp @@ -9,6 +9,7 @@ #include "meta/ZeroMQSelectableChannel.h" #include "syncd/ZeroMQNotificationProducer.h" +#include "syncd/Workaround.h" #include @@ -35,7 +36,8 @@ Proxy::Proxy( m_vendorSai(vendorSai), m_options(options), m_apiInitialized(false), - m_notificationsSentCount(0) + m_notificationsSentCount(0), + m_apiVersion(SAI_VERSION(0,0,0)) { SWSS_LOG_ENTER(); @@ -79,6 +81,17 @@ Proxy::Proxy( SWSS_LOG_NOTICE("api initialized success"); } + + auto st = m_vendorSai->queryApiVersion(&m_apiVersion); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN("failed to obtain libsai api version: %s", sai_serialize_status(st).c_str()); + } + else + { + SWSS_LOG_NOTICE("libsai api version: %lu", m_apiVersion); + } } Proxy::~Proxy() @@ -1113,7 +1126,9 @@ void Proxy::onPortStateChange( { SWSS_LOG_ENTER(); - auto s = sai_serialize_port_oper_status_ntf(count, data); + auto ntfdata = syncd::Workaround::convertPortOperStatusNotification(count, data, m_apiVersion); + + auto s = sai_serialize_port_oper_status_ntf((uint32_t)ntfdata.size(), ntfdata.data()); sendNotification(SAI_SWITCH_NOTIFICATION_NAME_PORT_STATE_CHANGE, s); } diff --git a/proxylib/Proxy.h b/proxylib/Proxy.h index 50aa302a9..029772634 100644 --- a/proxylib/Proxy.h +++ b/proxylib/Proxy.h @@ -206,5 +206,7 @@ namespace saiproxy * notifications. */ uint64_t m_notificationsSentCount; + + sai_api_version_t m_apiVersion; }; } diff --git a/pyext/pysairedis.i b/pyext/pysairedis.i index 32e76518a..8aad50ce7 100644 --- a/pyext/pysairedis.i +++ b/pyext/pysairedis.i @@ -2,6 +2,10 @@ %include "cpointer.i" %include "carrays.i" +// These objects cause issues on Buster because of the function pointers +%ignore _sai_struct_member_info_t; +%ignore _sai_object_type_info_t; + %{ #pragma GCC optimize("no-var-tracking-assignments") diff --git a/syncd/ComparisonLogic.cpp b/syncd/ComparisonLogic.cpp index f8691c074..959625595 100644 --- a/syncd/ComparisonLogic.cpp +++ b/syncd/ComparisonLogic.cpp @@ -3129,6 +3129,21 @@ void ComparisonLogic::applyViewTransition( } } + for (auto &obj: temp.m_soAll) + { + /* + * Make sure we will create all neighbor entries before next hop that + * have the same IP address as neighbor entry. In Broadcom platform + * neighbor entry needs to be created before next hop with the same ip + * address otherwise create next hop will fail (hardware limitation?). + */ + + if (obj.second->getObjectType() == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) + { + processObjectForViewTransition(current, temp, obj.second); + } + } + for (auto &obj: temp.m_soAll) { if (obj.second->getObjectType() != SAI_OBJECT_TYPE_ROUTE_ENTRY) diff --git a/syncd/NotificationHandler.cpp b/syncd/NotificationHandler.cpp index 5a4fa5300..2815d8e3b 100644 --- a/syncd/NotificationHandler.cpp +++ b/syncd/NotificationHandler.cpp @@ -1,4 +1,5 @@ #include "NotificationHandler.h" +#include "Workaround.h" #include "sairediscommon.h" #include "swss/logger.h" @@ -10,8 +11,10 @@ using namespace syncd; NotificationHandler::NotificationHandler( - _In_ std::shared_ptr processor): - m_processor(processor) + _In_ std::shared_ptr processor, + _In_ sai_api_version_t apiVersion): + m_processor(processor), + m_apiVersion(apiVersion) { SWSS_LOG_ENTER(); @@ -27,6 +30,21 @@ NotificationHandler::~NotificationHandler() // empty } +void NotificationHandler::setApiVersion( + _In_ sai_api_version_t apiVersion) +{ + SWSS_LOG_ENTER(); + + m_apiVersion = apiVersion; +} + +sai_api_version_t NotificationHandler::getApiVersion() const +{ + SWSS_LOG_ENTER(); + + return m_apiVersion; +} + void NotificationHandler::setSwitchNotifications( _In_ const sai_switch_notifications_t& switchNotifications) { @@ -93,7 +111,9 @@ void NotificationHandler::onPortStateChange( { SWSS_LOG_ENTER(); - auto s = sai_serialize_port_oper_status_ntf(count, data); + auto ntfdata = Workaround::convertPortOperStatusNotification(count, data, m_apiVersion); + + auto s = sai_serialize_port_oper_status_ntf((uint32_t)ntfdata.size(), ntfdata.data()); enqueueNotification(SAI_SWITCH_NOTIFICATION_NAME_PORT_STATE_CHANGE, s); } diff --git a/syncd/NotificationHandler.h b/syncd/NotificationHandler.h index 1ca355e58..970dd552a 100644 --- a/syncd/NotificationHandler.h +++ b/syncd/NotificationHandler.h @@ -20,7 +20,8 @@ namespace syncd public: NotificationHandler( - _In_ std::shared_ptr processor); + _In_ std::shared_ptr processor, + _In_ sai_api_version_t apiVersion = SAI_VERSION(0,0,0)); virtual ~NotificationHandler(); @@ -35,6 +36,11 @@ namespace syncd _In_ uint32_t attr_count, _In_ sai_attribute_t *attr_list) const; + void setApiVersion( + _In_ sai_api_version_t apiVersion); + + sai_api_version_t getApiVersion() const; + public: // members reflecting SAI callbacks void onFdbEvent( @@ -99,5 +105,7 @@ namespace syncd std::shared_ptr m_notificationQueue; std::shared_ptr m_processor; + + sai_api_version_t m_apiVersion; }; } diff --git a/syncd/NotificationQueue.cpp b/syncd/NotificationQueue.cpp index c68414242..11fbe701d 100644 --- a/syncd/NotificationQueue.cpp +++ b/syncd/NotificationQueue.cpp @@ -18,7 +18,7 @@ NotificationQueue::NotificationQueue( { SWSS_LOG_ENTER(); - // empty; + m_queue = std::make_shared>(); } NotificationQueue::~NotificationQueue() @@ -34,7 +34,9 @@ bool NotificationQueue::enqueue( MUTEX; SWSS_LOG_ENTER(); + bool candidateToDrop = false; + std::string currentEvent; /* @@ -49,8 +51,10 @@ bool NotificationQueue::enqueue( * will also be dropped regardless of its event type to protect the device from crashing due to * running out of memory */ - auto queueSize = m_queue.size(); + auto queueSize = m_queue->size(); + currentEvent = kfvKey(item); + if (currentEvent == m_lastEvent) { m_lastEventCount++; @@ -60,12 +64,15 @@ bool NotificationQueue::enqueue( m_lastEventCount = 1; m_lastEvent = currentEvent; } + if (queueSize >= m_queueSizeLimit) { - /* Too many queued up already check if notification fits condition to e dropped + /* + * Too many queued up already check if notification fits condition to e dropped * 1. All FDB events should be dropped at this point. * 2. All other notification events will start to drop if it reached the consecutive threshold limit */ + if (currentEvent == SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT) { candidateToDrop = true; @@ -81,7 +88,7 @@ bool NotificationQueue::enqueue( if (!candidateToDrop) { - m_queue.push(item); + m_queue->push(item); return true; } @@ -106,14 +113,38 @@ bool NotificationQueue::tryDequeue( SWSS_LOG_ENTER(); - if (m_queue.empty()) + if (m_queue->empty()) { return false; } - item = m_queue.front(); + item = m_queue->front(); - m_queue.pop(); + m_queue->pop(); + + if (m_queue->empty()) + { + /* + * Since there could be burst of notifications, that allocated memory + * can be over 2GB, but when queue will be drained that memory will not + * be automatically released. Underlying deque container contains + * function shrink_to_fit but that is just a request, and usually this + * function does nothing. + * + * Make sure we will destroy queue and allocate new one. Assignment + * operator is not enough here, since internal deque container will not + * release memory under assignment. While making sure queue is deleted + * all memory will be released. + * + * Downside of this approach is that even if we will have steady stream + * of single notifications, each time we will allocate new queue. + * Partial solution for this could allocating new queue only when + * previous queue exceeded some size limit, for example 128 items. + */ + m_queue = nullptr; + + m_queue = std::make_shared>(); + } return true; } @@ -124,5 +155,5 @@ size_t NotificationQueue::getQueueSize() SWSS_LOG_ENTER(); - return m_queue.size(); + return m_queue->size(); } diff --git a/syncd/NotificationQueue.h b/syncd/NotificationQueue.h index 12459ff6a..b655b92f0 100644 --- a/syncd/NotificationQueue.h +++ b/syncd/NotificationQueue.h @@ -2,13 +2,14 @@ extern "C" { #include -#include +#include } #include "swss/table.h" #include #include +#include /** * @brief Default notification queue size limit. @@ -54,7 +55,7 @@ namespace syncd std::mutex m_mutex; - std::queue m_queue; + std::shared_ptr> m_queue; size_t m_queueSizeLimit; diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index c755b5b18..13c46c80d 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -206,6 +206,21 @@ Syncd::Syncd( abort(); } + sai_api_version_t apiVersion = SAI_VERSION(0,0,0); // invalid version + + status = m_vendorSai->queryApiVersion(&apiVersion); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN("failed to obtain libsai api version: %s", sai_serialize_status(status).c_str()); + } + else + { + SWSS_LOG_NOTICE("libsai api version: %lu", apiVersion); + } + + m_handler->setApiVersion(apiVersion); + m_breakConfig = BreakConfigParser::parseBreakConfig(m_commandLineOptions->m_breakConfig); SWSS_LOG_NOTICE("syncd started"); @@ -3707,6 +3722,12 @@ void Syncd::inspectAsic() continue; } + SaiAttributeList redis_list(metaKey.objecttype, values, false); + + sai_attribute_t *redis_attr_list = redis_list.get_attr_list(); + + m_translator->translateVidToRid(metaKey.objecttype, attr_count, redis_attr_list); + // compare fields and values from ASIC_DB and SAI response and log the difference for (uint32_t index = 0; index < attr_count; ++index) @@ -3725,7 +3746,7 @@ void Syncd::inspectAsic() std::string strSaiAttrValue = sai_serialize_attr_value(*meta, attr, false); - std::string strRedisAttrValue = hash[meta->attridname]; + std::string strRedisAttrValue = sai_serialize_attr_value(*meta, redis_attr_list[index], false); if (strRedisAttrValue == strSaiAttrValue) { @@ -3819,9 +3840,15 @@ sai_status_t Syncd::processNotifySyncd( m_veryFirstRun = false; m_asicInitViewMode = false; - - if (m_commandLineOptions->m_startType == SAI_START_TYPE_FASTFAST_BOOT || - m_commandLineOptions->m_startType == SAI_START_TYPE_EXPRESS_BOOT) +#ifdef MELLANOX + bool applyViewInFastFastBoot = m_commandLineOptions->m_startType == SAI_START_TYPE_FASTFAST_BOOT || + m_commandLineOptions->m_startType == SAI_START_TYPE_EXPRESS_BOOT || + m_commandLineOptions->m_startType == SAI_START_TYPE_FAST_BOOT; +#else + bool applyViewInFastFastBoot = m_commandLineOptions->m_startType == SAI_START_TYPE_FASTFAST_BOOT || + m_commandLineOptions->m_startType == SAI_START_TYPE_EXPRESS_BOOT; +#endif + if (applyViewInFastFastBoot) { // express/fastfast boot configuration end @@ -3830,6 +3857,14 @@ sai_status_t Syncd::processNotifySyncd( SWSS_LOG_NOTICE("setting very first run to FALSE, op = %s", key.c_str()); } + else if (redisNotifySyncd == SAI_REDIS_NOTIFY_SYNCD_INSPECT_ASIC) + { + SWSS_LOG_NOTICE("syncd switched to INSPECT ASIC mode"); + + inspectAsic(); + + sendNotifyResponse(SAI_STATUS_SUCCESS); + } else { SWSS_LOG_THROW("unknown operation: %s", key.c_str()); diff --git a/syncd/Workaround.cpp b/syncd/Workaround.cpp index a7dbae5e4..6137b1b19 100644 --- a/syncd/Workaround.cpp +++ b/syncd/Workaround.cpp @@ -6,6 +6,11 @@ using namespace syncd; +/** + * @def Maximum port count on port notification + */ +#define MAX_PORT_COUNT (4096) + /** * @brief Determines whether attribute is "workaround" attribute for SET API. * @@ -57,3 +62,43 @@ bool Workaround::isSetAttributeWorkaround( return false; } + +std::vector Workaround::convertPortOperStatusNotification( + _In_ const uint32_t count, + _In_ const sai_port_oper_status_notification_t* data, + _In_ sai_api_version_t version) +{ + SWSS_LOG_ENTER(); + + std::vector ntf; + + if (data == nullptr || count > MAX_PORT_COUNT) + { + SWSS_LOG_ERROR("invalid notification parameters: data: %p, count: %d", data, count); + + return ntf; + } + + if (version > SAI_VERSION(1,14,0)) + { + // structure is compatible, no need for change + + ntf.assign(data, data + count); + + return ntf; + } + + SWSS_LOG_INFO("converting sai_port_oper_status_notification_t data from %lu to %u", version, SAI_API_VERSION); + + const sai_port_oper_status_notification_v1_14_0_t* dataold = + reinterpret_cast(data); + + for (uint32_t i = 0; i < count; i++) + { + sai_port_oper_status_notification_t item{ dataold[i].port_id, dataold[i].port_state, (sai_port_error_status_t)0}; + + ntf.push_back(item); + } + + return ntf; +} diff --git a/syncd/Workaround.h b/syncd/Workaround.h index 8bb9b4725..cbd5b211c 100644 --- a/syncd/Workaround.h +++ b/syncd/Workaround.h @@ -4,6 +4,8 @@ extern "C" { #include "saimetadata.h" } +#include + namespace syncd { class Workaround @@ -31,5 +33,38 @@ namespace syncd _In_ sai_object_type_t objectType, _In_ sai_attr_id_t attrId, _In_ sai_status_t status); + + /** + * @brief Convert port status notification from older version. + * + * This method will convert port status notification from SAI + * v1.14.0 to version v1.15.0, since from that version a new + * structure field was added, and there is possibility that syncd + * compiled against headers v1.15.0 will receive notification from + * sai library v1.14.0 or older, and since that change is not + * backward compatible, it can cause invalid memory read or garbage + * memory read. To prevent that, we will convert structures. + * + * Similar thing can happen if older syncd will receive + * notification from newer version of sai library. + */ + static std::vector convertPortOperStatusNotification( + _In_ const uint32_t count, + _In_ const sai_port_oper_status_notification_t* data, + _In_ sai_api_version_t version); + public: + + /** + * @brief Port operational status notification as in SAI version v1.14.0 + * + * This will imitate structure size needed for notification conversion. + */ + typedef struct _sai_port_oper_status_notification_v1_14_0_t + { + sai_object_id_t port_id; + + sai_port_oper_status_t port_state; + + } sai_port_oper_status_notification_v1_14_0_t; }; } diff --git a/syncd/tests/TestSyncdMlnx.cpp b/syncd/tests/TestSyncdMlnx.cpp index 34311cb42..3c0c852c6 100644 --- a/syncd/tests/TestSyncdMlnx.cpp +++ b/syncd/tests/TestSyncdMlnx.cpp @@ -284,10 +284,14 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; attr.value.ptr = (void*)&flexCounterGroupParam; - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr); + // Failed to create if the switchId is invalid for the context + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId + 1, &attr); + std::vector fvVector, fvVectorExpected; + ASSERT_FALSE(m_flexCounterGroupTable->get("PORT_STAT_COUNTER", fvVector)); + + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); ASSERT_EQ(status, SAI_STATUS_SUCCESS); - std::vector fvVector, fvVectorExpected; ASSERT_TRUE(m_flexCounterGroupTable->get("PORT_STAT_COUNTER", fvVector)); fvVectorExpected.emplace_back(POLL_INTERVAL_FIELD, poll_interval); fvVectorExpected.emplace_back(STATS_MODE_FIELD, stats_mode); @@ -315,7 +319,7 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER; attr.value.ptr = (void*)&flexCounterParam; - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); ASSERT_EQ(status, SAI_STATUS_FAILURE); ASSERT_FALSE(m_flexCounterTable->get(key, fvVector)); @@ -323,7 +327,7 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) key = "PORT_STAT_COUNTER:" + sai_serialize_object_id(oidList[0]); flexCounterParam.counter_key.list = (int8_t*)const_cast(key.c_str()); flexCounterParam.counter_key.count = (uint32_t)key.length(); - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); ASSERT_EQ(status, SAI_STATUS_SUCCESS); ASSERT_TRUE(m_flexCounterTable->get(key, fvVector)); @@ -336,7 +340,7 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) flexCounterParam.counter_field_name.count = 0; // 3. Stop counter polling for the port - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); ASSERT_EQ(status, SAI_STATUS_SUCCESS); ASSERT_FALSE(m_flexCounterTable->get(key, fvVector)); @@ -351,7 +355,7 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; attr.value.ptr = (void*)&flexCounterGroupParam; - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); ASSERT_EQ(status, SAI_STATUS_SUCCESS); ASSERT_FALSE(m_flexCounterTable->get(key, fvVector)); diff --git a/tests/BCM56850.pl b/tests/BCM56850.pl index 7dd6ea0a8..bca5fc4ce 100755 --- a/tests/BCM56850.pl +++ b/tests/BCM56850.pl @@ -835,8 +835,36 @@ sub test_acl_pre_match_999 for (1..8) { play "acl_pre_match_999.rec", 0; } } +sub test_neighbor_next_hop +{ + fresh_start; + + play "neighbor_next_hop.rec"; + + open (my $H, "<", "applyview.log") or die "failed to open applyview.log $!"; + + my @lines = <$H>; + + close ($H); + + my $order = ""; + + for(@lines) + { + $order .= "E" if /create.+NEIGHBOR_ENTRY:/; + $order .= "N" if /create.+NEXT_HOP:/; + } + + if (not $order =~ /^E+N+$/) + { + print color('red') . "Invalid order, expected neighbor created first, then next hop" . color('reset') . "\n"; + exit 1; + } +} + # RUN TESTS +test_neighbor_next_hop; test_acl_pre_match_999; test_relaxed; test_acl_counter_match; diff --git a/tests/BCM56850/neighbor_next_hop.rec b/tests/BCM56850/neighbor_next_hop.rec new file mode 100644 index 000000000..0e7841954 --- /dev/null +++ b/tests/BCM56850/neighbor_next_hop.rec @@ -0,0 +1,23 @@ +2018-11-14.19:34:17.416379|a|INIT_VIEW +2018-11-14.19:34:17.419035|A|SAI_STATUS_SUCCESS +2018-11-14.19:34:17.420345|c|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_INIT_SWITCH=true +2018-11-14.19:34:26.317753|a|APPLY_VIEW +2018-11-14.19:34:26.319120|A|SAI_STATUS_SUCCESS +2018-11-14.19:34:17.416379|a|INIT_VIEW +2018-11-14.19:34:17.419035|A|SAI_STATUS_SUCCESS +2018-11-14.19:34:17.420345|c|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_INIT_SWITCH=true +2018-11-14.19:34:17.420634|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x0 +2018-11-14.19:34:26.138403|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x3000000000022 +2018-11-14.19:34:26.147205|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_PORT_LIST=32:oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0 +2018-11-14.19:34:26.151676|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_PORT_LIST=32:oid:0x1000000000002,oid:0x1000000000003,oid:0x1000000000004,oid:0x1000000000005,oid:0x1000000000006,oid:0x1000000000007,oid:0x1000000000008,oid:0x1000000000009,oid:0x100000000000a,oid:0x100000000000b,oid:0x100000000000c,oid:0x100000000000d,oid:0x100000000000e,oid:0x100000000000f,oid:0x1000000000010,oid:0x1000000000011,oid:0x1000000000012,oid:0x1000000000013,oid:0x1000000000014,oid:0x1000000000015,oid:0x1000000000016,oid:0x1000000000017,oid:0x1000000000018,oid:0x1000000000019,oid:0x100000000001a,oid:0x100000000001b,oid:0x100000000001c,oid:0x100000000001d,oid:0x100000000001e,oid:0x100000000001f,oid:0x1000000000020,oid:0x1000000000021 +2018-11-14.19:34:27.438163|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005bc|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000022|SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS=00:E0:EC:C2:AD:F1|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_INTERFACE_TYPE_PORT|SAI_ROUTER_INTERFACE_ATTR_PORT_ID=oid:0x1000000000009|SAI_ROUTER_INTERFACE_ATTR_MTU=9100 +2018-11-14.19:34:29.338659|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x600000000065d|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000022|SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS=00:E0:EC:C2:AD:F1|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_INTERFACE_TYPE_PORT|SAI_ROUTER_INTERFACE_ATTR_PORT_ID=oid:0x100000000001e|SAI_ROUTER_INTERFACE_ATTR_MTU=9100 +2018-11-14.19:34:29.350477|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000663|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000022|SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS=00:E0:EC:C2:AD:F1|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_INTERFACE_TYPE_PORT|SAI_ROUTER_INTERFACE_ATTR_PORT_ID=oid:0x1000000000005|SAI_ROUTER_INTERFACE_ATTR_MTU=9100 +2018-11-14.19:34:31.339104|c|SAI_OBJECT_TYPE_NEXT_HOP:oid:0x4000000000667|SAI_NEXT_HOP_ATTR_TYPE=SAI_NEXT_HOP_TYPE_IP|SAI_NEXT_HOP_ATTR_IP=10.0.0.55|SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID=oid:0x60000000005bc +2018-11-14.19:34:31.799264|c|SAI_OBJECT_TYPE_NEXT_HOP:oid:0x4000000000668|SAI_NEXT_HOP_ATTR_TYPE=SAI_NEXT_HOP_TYPE_IP|SAI_NEXT_HOP_ATTR_IP=10.0.0.47|SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID=oid:0x6000000000663 +2018-11-14.19:34:32.067463|c|SAI_OBJECT_TYPE_NEXT_HOP:oid:0x4000000000669|SAI_NEXT_HOP_ATTR_TYPE=SAI_NEXT_HOP_TYPE_IP|SAI_NEXT_HOP_ATTR_IP=10.0.0.57|SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID=oid:0x600000000065d +2018-11-14.19:34:32.067141|c|SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{"ip":"10.0.0.57","rif":"oid:0x600000000065d","switch_id":"oid:0x21000000000000"}|SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS=52:54:00:58:BC:32 +2018-11-14.19:34:31.798881|c|SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{"ip":"10.0.0.47","rif":"oid:0x6000000000663","switch_id":"oid:0x21000000000000"}|SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS=52:54:00:57:24:59 +2018-11-14.19:34:31.338650|c|SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{"ip":"10.0.0.55","rif":"oid:0x60000000005bc","switch_id":"oid:0x21000000000000"}|SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS=52:54:00:A4:67:AB +2018-11-14.19:34:26.317753|a|APPLY_VIEW +2018-11-14.19:34:26.319120|A|SAI_STATUS_SUCCESS diff --git a/tests/MLNX2700.pl b/tests/MLNX2700.pl index ca0a6713a..ed6334efc 100755 --- a/tests/MLNX2700.pl +++ b/tests/MLNX2700.pl @@ -59,8 +59,16 @@ sub test_mlnx_full_to_full play "full_no_hostif_entry_second.rec"; } +sub test_inspect_asic +{ + fresh_start; + + play "inspect_asic.rec" +} + # RUN +test_inspect_asic(); test_mlnx_nhg_member; test_mlnx_full_to_empty; test_mlnx_empty_to_full_to_empty; diff --git a/tests/MLNX2700/inspect_asic.rec b/tests/MLNX2700/inspect_asic.rec new file mode 100644 index 000000000..577618d78 --- /dev/null +++ b/tests/MLNX2700/inspect_asic.rec @@ -0,0 +1,26 @@ +2017-05-11.01:43:51.003662|#|recording to: sairedis.2017-05-11.01:43:51.003467.rec +2017-05-11.01:43:51.004710|a|INIT_VIEW +2017-05-11.01:43:51.008012|A|SAI_STATUS_SUCCESS +2017-05-11.01:43:51.010010|c|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_INIT_SWITCH=true|SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY=0x415000|SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY=0x415160|SAI_SWITCH_ATTR_SWITCH_SHUTDOWN_REQUEST_NOTIFY=0x4152c0 +2017-05-11.01:44:02.229827|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x0 +2017-05-11.01:44:02.230913|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x3000000000002 +2017-05-11.01:44:02.233014|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_CPU_PORT=oid:0x0 +2017-05-11.01:44:02.250340|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_CPU_PORT=oid:0x1000000000001 +2017-05-11.01:44:02.250435|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_NUMBER_OF_ACTIVE_PORTS=1 +2017-05-11.01:44:02.251154|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_NUMBER_OF_ACTIVE_PORTS=32 +2017-05-11.01:44:02.251258|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_PORT_LIST=32:oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0,oid:0x0 +2017-05-11.01:44:02.252737|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_PORT_LIST=32:oid:0x100000000011a,oid:0x100000000013e,oid:0x1000000000162,oid:0x1000000000186,oid:0x10000000001aa,oid:0x10000000001ce,oid:0x10000000001f2,oid:0x1000000000216,oid:0x100000000023a,oid:0x100000000025e,oid:0x1000000000282,oid:0x10000000002a6,oid:0x10000000002ca,oid:0x10000000002ee,oid:0x1000000000312,oid:0x1000000000336,oid:0x100000000035a,oid:0x100000000037e,oid:0x10000000003a2,oid:0x10000000003c6,oid:0x10000000003ea,oid:0x100000000040e,oid:0x1000000000432,oid:0x1000000000456,oid:0x100000000047a,oid:0x100000000049e,oid:0x10000000004c2,oid:0x10000000004e6,oid:0x100000000050a,oid:0x100000000052e,oid:0x1000000000552,oid:0x1000000000576 +2017-05-11.01:44:02.506421|c|SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"0.0.0.0/0","switch_id":"oid:0x21000000000000","vr":"oid:0x3000000000002"}|SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION=SAI_PACKET_ACTION_DROP +2017-05-11.01:44:02.506914|c|SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"::/0","switch_id":"oid:0x21000000000000","vr":"oid:0x3000000000002"}|SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION=SAI_PACKET_ACTION_DROP +2017-05-11.01:44:05.124489|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005e1|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000002|SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS=7C:FE:90:5E:6A:80|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_INTERFACE_TYPE_PORT|SAI_ROUTER_INTERFACE_ATTR_PORT_ID=oid:0x100000000023a +2017-05-11.01:44:05.126397|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005e2|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000002|SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS=7C:FE:90:5E:6A:80|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_INTERFACE_TYPE_PORT|SAI_ROUTER_INTERFACE_ATTR_PORT_ID=oid:0x1000000000552 +2017-05-11.01:44:22.585866|c|SAI_OBJECT_TYPE_NEXT_HOP:oid:0x400000000061c|SAI_NEXT_HOP_ATTR_TYPE=SAI_NEXT_HOP_TYPE_IP|SAI_NEXT_HOP_ATTR_IP=10.0.0.49|SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID=oid:0x60000000005e1 +2017-05-11.01:44:22.587132|c|SAI_OBJECT_TYPE_NEXT_HOP:oid:0x400000000061d|SAI_NEXT_HOP_ATTR_TYPE=SAI_NEXT_HOP_TYPE_IP|SAI_NEXT_HOP_ATTR_IP=10.0.0.1|SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID=oid:0x60000000005e2 +2017-05-11.01:44:29.528915|c|SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0x5000000000627|SAI_NEXT_HOP_GROUP_ATTR_TYPE=SAI_NEXT_HOP_GROUP_TYPE_ECMP +2017-05-11.01:44:29.529963|c|SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0x2d000000000628|SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID=oid:0x5000000000627|SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID=oid:0x400000000061d +2017-05-11.01:44:32.111307|c|SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"192.168.0.48/32","switch_id":"oid:0x21000000000000","vr":"oid:0x3000000000002"}|SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID=oid:0x5000000000627 +2017-05-11.01:44:32.246917|c|SAI_OBJECT_TYPE_ROUTE_ENTRY:{"dest":"192.168.0.192/32","switch_id":"oid:0x21000000000000","vr":"oid:0x3000000000002"}|SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID=oid:0x5000000000627 +2017-05-11.01:44:02.533119|a|APPLY_VIEW +2017-05-11.01:44:02.535313|A|SAI_STATUS_SUCCESS +2017-05-11.01:44:02.533119|a|SYNCD_INSPECT_ASIC +2017-05-11.01:44:02.535313|A|SAI_STATUS_SUCCESS diff --git a/tests/Makefile.am b/tests/Makefile.am index b86eb095b..882ef26da 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,7 +21,7 @@ tests_LDADD = -lhiredis -lswsscommon -lpthread \ $(top_srcdir)/lib/libsairedis.la $(top_srcdir)/syncd/libSyncd.a \ -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta -lzmq $(CODE_COVERAGE_LIBS) -testclient_SOURCES = TestClient.cpp testclient.cpp +testclient_SOURCES = TestClient.cpp testclient_main.cpp testclient_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) testclient_LDADD = -lhiredis -lswsscommon -lpthread \ $(top_srcdir)/lib/libsairedis.la $(top_srcdir)/syncd/libSyncd.a \ diff --git a/tests/aspell.en.pws b/tests/aspell.en.pws index 71268a351..1908c5834 100644 --- a/tests/aspell.en.pws +++ b/tests/aspell.en.pws @@ -477,3 +477,4 @@ TWAMP saiproxy submodule Enqueue +deque diff --git a/tests/testclient.cpp b/tests/testclient_main.cpp similarity index 100% rename from tests/testclient.cpp rename to tests/testclient_main.cpp diff --git a/unittest/syncd/Makefile.am b/unittest/syncd/Makefile.am index b6c0cba94..b06a3ec08 100644 --- a/unittest/syncd/Makefile.am +++ b/unittest/syncd/Makefile.am @@ -2,7 +2,7 @@ AM_CXXFLAGS = $(SAIINC) -I$(top_srcdir)/syncd -I$(top_srcdir)/lib -I$(top_srcdir bin_PROGRAMS = tests -LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main +LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main -lgmock tests_SOURCES = main.cpp \ MockableSaiInterface.cpp \ @@ -17,10 +17,12 @@ tests_SOURCES = main.cpp \ TestMdioIpcServer.cpp \ TestPortStateChangeHandler.cpp \ TestWorkaround.cpp \ + TestSyncd.cpp \ TestVendorSai.cpp tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) tests_LDFLAGS = -Wl,-rpath,$(top_srcdir)/lib/.libs -Wl,-rpath,$(top_srcdir)/meta/.libs -tests_LDADD = $(LDADD_GTEST) $(top_srcdir)/syncd/libSyncd.a $(top_srcdir)/vslib/libSaiVS.a $(top_srcdir)/syncd/libMdioIpcClient.a -lhiredis -lswsscommon -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3 -lpthread -L$(top_srcdir)/lib/.libs -lsairedis -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta -lzmq $(CODE_COVERAGE_LIBS) +tests_LDADD = $(LDADD_GTEST) $(top_srcdir)/syncd/libSyncdRequestShutdown.a $(top_srcdir)/syncd/libSyncd.a $(top_srcdir)/vslib/libSaiVS.a $(top_srcdir)/syncd/libMdioIpcClient.a \ + -lhiredis -lswsscommon -lnl-genl-3 -lnl-nf-3 -lnl-route-3 -lnl-3 -lpthread -L$(top_srcdir)/lib/.libs -lsairedis -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta -lzmq $(CODE_COVERAGE_LIBS) TESTS = tests diff --git a/unittest/syncd/TestNotificationHandler.cpp b/unittest/syncd/TestNotificationHandler.cpp index 59566676c..9e3f25d8d 100644 --- a/unittest/syncd/TestNotificationHandler.cpp +++ b/unittest/syncd/TestNotificationHandler.cpp @@ -67,3 +67,16 @@ TEST(NotificationHandler, NotificationHandlerTest) data, description); } + +TEST(NotificationHandler, setApiVersion) +{ + auto np = std::make_shared(nullptr, nullptr, nullptr); + + auto nh = std::make_shared(np); + + EXPECT_EQ(SAI_VERSION(0,0,0), nh->getApiVersion()); + + nh->setApiVersion(SAI_VERSION(1,15,0)); + + EXPECT_EQ(SAI_VERSION(1,15,0), nh->getApiVersion()); +} diff --git a/unittest/syncd/TestNotificationQueue.cpp b/unittest/syncd/TestNotificationQueue.cpp index 348520857..88e25e56e 100644 --- a/unittest/syncd/TestNotificationQueue.cpp +++ b/unittest/syncd/TestNotificationQueue.cpp @@ -66,3 +66,19 @@ TEST(NotificationQueue, EnqueueLimitTest) } } +TEST(NotificationQueue, tryDequeue) +{ + syncd::NotificationQueue nq(5, 3); + + EXPECT_EQ(nq.getQueueSize(), 0); + + swss::KeyOpFieldsValuesTuple item; + + nq.enqueue(item); + + EXPECT_EQ(nq.getQueueSize(), 1); + + EXPECT_EQ(nq.tryDequeue(item), true); + + EXPECT_EQ(nq.getQueueSize(), 0); +} diff --git a/unittest/syncd/TestSyncd.cpp b/unittest/syncd/TestSyncd.cpp new file mode 100644 index 000000000..9816aa912 --- /dev/null +++ b/unittest/syncd/TestSyncd.cpp @@ -0,0 +1,262 @@ +#include "Syncd.h" +#include "RequestShutdown.h" +#include "vslib/ContextConfigContainer.h" +#include "vslib/VirtualSwitchSaiInterface.h" +#include "vslib/Sai.h" +#include "lib/Sai.h" + +#include "swss/dbconnector.h" + +#include "sairediscommon.h" + +#include "MockableSaiInterface.h" +#include "CommandLineOptions.h" +#include "sairediscommon.h" +#include "SelectableChannel.h" +#include "swss/dbconnector.h" +#include "swss/redisreply.h" + +#include +#include + +using namespace syncd; +using namespace saivs; + +static void syncd_thread( + _In_ std::shared_ptr syncd) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("thread stared"); + + syncd->run(); + + SWSS_LOG_NOTICE("thread end"); +} + +static std::map profileMap; +static std::map::iterator profileIter; + +static const char* profileGetValue( + _In_ sai_switch_profile_id_t profile_id, + _In_ const char* variable) +{ + SWSS_LOG_ENTER(); + + if (variable == NULL) + { + SWSS_LOG_WARN("variable is null"); + return NULL; + } + + auto it = profileMap.find(variable); + + if (it == profileMap.end()) + { + SWSS_LOG_NOTICE("%s: NULL", variable); + return NULL; + } + + SWSS_LOG_NOTICE("%s: %s", variable, it->second.c_str()); + + return it->second.c_str(); +} + +static int profileGetNextValue( + _In_ sai_switch_profile_id_t profile_id, + _Out_ const char** variable, + _Out_ const char** value) +{ + SWSS_LOG_ENTER(); + + if (value == NULL) + { + SWSS_LOG_INFO("resetting profile map iterator"); + + profileIter = profileMap.begin(); + return 0; + } + + if (variable == NULL) + { + SWSS_LOG_WARN("variable is null"); + return -1; + } + + if (profileIter == profileMap.end()) + { + SWSS_LOG_INFO("iterator reached end"); + return -1; + } + + *variable = profileIter->first.c_str(); + *value = profileIter->second.c_str(); + + SWSS_LOG_INFO("key: %s:%s", *variable, *value); + + profileIter++; + + return 0; +} + +TEST(Syncd, inspectAsic) +{ + auto db = std::make_shared("ASIC_DB", 0, true); + + swss::RedisReply r(db.get(), "FLUSHALL", REDIS_REPLY_STATUS); + + r.checkStatusOK(); + + sai_service_method_table_t smt; + + smt.profile_get_value = &profileGetValue; + smt.profile_get_next_value = &profileGetNextValue; + + auto vssai = std::make_shared(); + + auto cmd = std::make_shared(); + + cmd->m_redisCommunicationMode = SAI_REDIS_COMMUNICATION_MODE_REDIS_SYNC; + cmd->m_enableTempView = true; + cmd->m_profileMapFile = "profile.ini"; + + auto syncd = std::make_shared(vssai, cmd, false); + + std::thread thread(syncd_thread, syncd); + + auto sai = std::make_shared(); + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->apiInitialize(0, &smt)); + + sai_attribute_t attr; + + attr.id = SAI_REDIS_SWITCH_ATTR_REDIS_COMMUNICATION_MODE; + attr.value.s32 = SAI_REDIS_COMMUNICATION_MODE_REDIS_SYNC; + + // set syncd mode on sairedis + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->set(SAI_OBJECT_TYPE_SWITCH, SAI_NULL_OBJECT_ID, &attr)); + + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + sai_object_id_t switchId; + + // create switch + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->create(SAI_OBJECT_TYPE_SWITCH, &switchId, SAI_NULL_OBJECT_ID, 1, &attr)); + + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + + // get default virtual router + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->get(SAI_OBJECT_TYPE_SWITCH, switchId, 1, &attr)); + + sai_object_id_t routerId = attr.value.oid; + + sai_object_id_t list[32]; + + attr.id = SAI_SWITCH_ATTR_PORT_LIST; + attr.value.objlist.count = 32; + attr.value.objlist.list = list; + + // get port list + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->get(SAI_OBJECT_TYPE_SWITCH, switchId, 1, &attr)); + + sai_attribute_t attrs[4]; + + attrs[0].id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + attrs[0].value.oid = routerId; + attrs[1].id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; + attrs[2].id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + attrs[2].value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; + attrs[3].id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; + attrs[3].value.oid = list[0]; + + // create router interface, we need oid with oid attributes + // to validate inspect asic routine + + sai_object_id_t rifId; + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->create(SAI_OBJECT_TYPE_ROUTER_INTERFACE, &rifId, switchId, 4, attrs)); + + attr.id = SAI_REDIS_SWITCH_ATTR_NOTIFY_SYNCD; + attr.value.s32 = SAI_REDIS_NOTIFY_SYNCD_INSPECT_ASIC; + + // inspect asic on cold boot + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->set(SAI_OBJECT_TYPE_SWITCH, switchId, &attr)); + + // request shutdown + + auto opt = std::make_shared(); + + opt->setRestartType(SYNCD_RESTART_TYPE_WARM); + + RequestShutdown rs(opt); + + rs.send(); + + // join thread for syncd + + thread.join(); + + syncd = nullptr; + + // TODO inspect asic on warm boot + + EXPECT_EQ(SAI_STATUS_SUCCESS, sai->apiUninitialize()); +} + +using namespace syncd; + +#ifdef MOCK_METHOD +class MockSelectableChannel : public sairedis::SelectableChannel { +public: + MOCK_METHOD(bool, empty, (), (override)); + MOCK_METHOD(void, pop, (swss::KeyOpFieldsValuesTuple& kco, bool initViewMode), (override)); + MOCK_METHOD(void, set, (const std::string& key, const std::vector& values, const std::string& op), (override)); + MOCK_METHOD(int, getFd, (), (override)); + MOCK_METHOD(uint64_t, readData, (), (override)); +}; + +void clearDB() +{ + SWSS_LOG_ENTER(); + + swss::DBConnector db("ASIC_DB", 0, true); + swss::RedisReply r(&db, "FLUSHALL", REDIS_REPLY_STATUS); + + r.checkStatusOK(); +} + +class SyncdTest : public ::testing::Test +{ +protected: + void SetUp() override + { + clearDB(); + } + void TearDown() override + { + clearDB(); + } +}; + +TEST_F(SyncdTest, processNotifySyncd) +{ + auto sai = std::make_shared(); + auto opt = std::make_shared(); + opt->m_enableTempView = true; + opt->m_startType = SAI_START_TYPE_FASTFAST_BOOT; + syncd::Syncd syncd_object(sai, opt, false); + + MockSelectableChannel consumer; + EXPECT_CALL(consumer, empty()).WillOnce(testing::Return(true)); + EXPECT_CALL(consumer, pop(testing::_, testing::_)).WillOnce(testing::Invoke([](swss::KeyOpFieldsValuesTuple& kco, bool initViewMode) { + kfvKey(kco) = SYNCD_APPLY_VIEW; + kfvOp(kco) = REDIS_ASIC_STATE_COMMAND_NOTIFY; + })); + syncd_object.processEvent(consumer); +} +#endif diff --git a/unittest/syncd/TestWorkaround.cpp b/unittest/syncd/TestWorkaround.cpp index 36dd822e6..3b35c0539 100644 --- a/unittest/syncd/TestWorkaround.cpp +++ b/unittest/syncd/TestWorkaround.cpp @@ -19,3 +19,51 @@ TEST(Workaround, isSetAttributeWorkaround) ASSERT_EQ(Workaround::isSetAttributeWorkaround(SAI_OBJECT_TYPE_PORT, SAI_PORT_ATTR_TYPE, SAI_STATUS_FAILURE), false); ASSERT_EQ(Workaround::isSetAttributeWorkaround(SAI_OBJECT_TYPE_PORT, SAI_PORT_ATTR_TYPE, SAI_STATUS_SUCCESS), false); } + +TEST(Workaround,convertPortOperStatusNotification) +{ + sai_port_oper_status_notification_t data[2]; + + ASSERT_EQ(Workaround::convertPortOperStatusNotification(0, nullptr, SAI_API_VERSION).size(), 0); + ASSERT_EQ(Workaround::convertPortOperStatusNotification(5000, data, SAI_API_VERSION).size(), 0); + + ASSERT_EQ(Workaround::convertPortOperStatusNotification(2, data, SAI_VERSION(1,15,0)).size(), 2); + ASSERT_EQ(Workaround::convertPortOperStatusNotification(2, data, SAI_VERSION(1,14,1)).size(), 2); + + // check new structure notifications + + data[0].port_id = 12; + data[0].port_state = SAI_PORT_OPER_STATUS_DOWN; + data[0].port_error_status = SAI_PORT_ERROR_STATUS_HIGH_BER; + data[1].port_id = 22; + data[1].port_state = SAI_PORT_OPER_STATUS_UP; + data[1].port_error_status = SAI_PORT_ERROR_STATUS_DATA_UNIT_MISALIGNMENT_ERROR; + + auto ntf = Workaround::convertPortOperStatusNotification(2, data, SAI_VERSION(1,14,1)); + + ASSERT_EQ(ntf[0].port_id, 12); + ASSERT_EQ(ntf[0].port_state, SAI_PORT_OPER_STATUS_DOWN); + ASSERT_EQ(ntf[0].port_error_status, SAI_PORT_ERROR_STATUS_HIGH_BER); + ASSERT_EQ(ntf[1].port_id, 22); + ASSERT_EQ(ntf[1].port_state, SAI_PORT_OPER_STATUS_UP); + ASSERT_EQ(ntf[1].port_error_status, SAI_PORT_ERROR_STATUS_DATA_UNIT_MISALIGNMENT_ERROR); + + // check old structure notification + Workaround::sai_port_oper_status_notification_v1_14_0_t old[2]; + + old[0].port_id = 42; + old[0].port_state = SAI_PORT_OPER_STATUS_UP; + old[1].port_id = 43; + old[1].port_state = SAI_PORT_OPER_STATUS_DOWN; + + auto ntf2 = Workaround::convertPortOperStatusNotification(2, reinterpret_cast(old), SAI_VERSION(1,14,0)); + + ASSERT_EQ(ntf.size(), 2); + + ASSERT_EQ(ntf2[0].port_id, 42); + ASSERT_EQ(ntf2[0].port_state, SAI_PORT_OPER_STATUS_UP); + ASSERT_EQ(ntf2[0].port_error_status, 0); + ASSERT_EQ(ntf2[1].port_id, 43); + ASSERT_EQ(ntf2[1].port_state, SAI_PORT_OPER_STATUS_DOWN); + ASSERT_EQ(ntf2[1].port_error_status, 0); +} diff --git a/unittest/syncd/profile.ini b/unittest/syncd/profile.ini new file mode 100644 index 000000000..6f84b07ea --- /dev/null +++ b/unittest/syncd/profile.ini @@ -0,0 +1,3 @@ +SAI_WARM_BOOT_READ_FILE=./sai_warmboot.bin +SAI_WARM_BOOT_WRITE_FILE=./sai_warmboot.bin +SAI_VS_SWITCH_TYPE=SAI_VS_SWITCH_TYPE_MLNX2700