diff --git a/lib/inc/sairedis.h b/lib/inc/sairedis.h index 88409e8aad..0c0efe7f12 100644 --- a/lib/inc/sairedis.h +++ b/lib/inc/sairedis.h @@ -7,6 +7,7 @@ extern "C" { #define SYNCD_INIT_VIEW "INIT_VIEW" #define SYNCD_APPLY_VIEW "APPLY_VIEW" +#define SYNCD_INSPECT_ASIC "SYNCD_INSPECT_ASIC" #define ASIC_STATE_TABLE "ASIC_STATE" #define TEMP_PREFIX "TEMP_" @@ -14,7 +15,9 @@ typedef enum _sai_redis_notify_syncd_t { SAI_REDIS_NOTIFY_SYNCD_INIT_VIEW, - SAI_REDIS_NOTIFY_SYNCD_APPLY_VIEW + SAI_REDIS_NOTIFY_SYNCD_APPLY_VIEW, + + SAI_REDIS_NOTIFY_SYNCD_INSPECT_ASIC } sai_redis_notify_syncd_t; diff --git a/lib/src/sai_redis_switch.cpp b/lib/src/sai_redis_switch.cpp index cec1e71d3d..f664232d25 100644 --- a/lib/src/sai_redis_switch.cpp +++ b/lib/src/sai_redis_switch.cpp @@ -109,6 +109,11 @@ sai_status_t sai_redis_notify_syncd( g_asicInitViewMode = false; break; + case SAI_REDIS_NOTIFY_SYNCD_INSPECT_ASIC: + SWSS_LOG_NOTICE("sending syncd INSPECT ASIC"); + op = SYNCD_INSPECT_ASIC; + break; + default: SWSS_LOG_ERROR("invalid notify syncd attr value %d", attr->value.s32); return SAI_STATUS_FAILURE; diff --git a/meta/saiattributelist.cpp b/meta/saiattributelist.cpp index 7e2d44e8ad..6d365e376b 100644 --- a/meta/saiattributelist.cpp +++ b/meta/saiattributelist.cpp @@ -38,6 +38,40 @@ SaiAttributeList::SaiAttributeList( } } +SaiAttributeList::SaiAttributeList( + _In_ const sai_object_type_t object_type, + _In_ const std::unordered_map& hash, + _In_ bool countOnly) +{ + for (auto it = hash.begin(); it != hash.end(); it++) + { + const std::string &str_attr_id = it->first; + const std::string &str_attr_value = it->second; + + if (str_attr_id == "NULL") + { + continue; + } + + sai_attribute_t attr; + memset(&attr, 0, sizeof(sai_attribute_t)); + + sai_deserialize_attr_id(str_attr_id, attr.id); + + auto meta = sai_metadata_get_attr_metadata(object_type, attr.id); + + if (meta == NULL) + { + SWSS_LOG_THROW("FATAL: failed to find metadata for object type %d and attr id %d", object_type, attr.id); + } + + sai_deserialize_attr_value(str_attr_value, *meta, attr, countOnly); + + m_attr_list.push_back(attr); + m_attr_value_type_list.push_back(meta->attrvaluetype); + } +} + SaiAttributeList::~SaiAttributeList() { size_t attr_count = m_attr_list.size(); diff --git a/meta/saiattributelist.h b/meta/saiattributelist.h index 4fad3f51a6..8c3a7c92c6 100644 --- a/meta/saiattributelist.h +++ b/meta/saiattributelist.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "swss/dbconnector.h" @@ -21,6 +22,11 @@ class SaiAttributeList _In_ const std::vector &values, _In_ bool countOnly); + SaiAttributeList( + _In_ const sai_object_type_t object_type, + _In_ const std::unordered_map& hash, + _In_ bool countOnly); + ~SaiAttributeList(); sai_attribute_t* get_attr_list(); diff --git a/saiplayer/saiplayer.cpp b/saiplayer/saiplayer.cpp index 9321b19f41..9a2f20e3ea 100644 --- a/saiplayer/saiplayer.cpp +++ b/saiplayer/saiplayer.cpp @@ -1063,7 +1063,7 @@ int replay(int argc, char **argv) SWSS_LOG_ENTER(); - if (argc < 2) + if (argc == 0) { fprintf(stderr, "ERR: need to specify filename\n"); @@ -1244,13 +1244,16 @@ void printUsage() std::cout << " Enable syslog debug messages" << std::endl << std::endl; std::cout << " -u --useTempView:" << std::endl; std::cout << " Enable temporary view between init and apply" << std::endl << std::endl; + std::cout << " -i --inspectAsic:" << std::endl; + std::cout << " Inspect ASIC by ASIC DB" << std::endl << std::endl; std::cout << " -h --help:" << std::endl; std::cout << " Print out this message" << std::endl << std::endl; } bool g_useTempView = false; +bool g_inspectAsic = false; -void handleCmdLine(int argc, char **argv) +int handleCmdLine(int argc, char **argv) { SWSS_LOG_ENTER(); @@ -1262,14 +1265,13 @@ void handleCmdLine(int argc, char **argv) { "help", no_argument, 0, 'h' }, { "skipNotifySyncd", no_argument, 0, 'C' }, { "enableDebug", no_argument, 0, 'd' }, + { "inspectAsic", no_argument, 0, 'i' }, { 0, 0, 0, 0 } }; - const char* const optstring = "hCdu"; + const char* const optstring = "hCdui"; - int option_index; - - int c = getopt_long(argc, argv, optstring, long_options, &option_index); + int c = getopt_long(argc, argv, optstring, long_options, 0); if (c == -1) break; @@ -1288,6 +1290,10 @@ void handleCmdLine(int argc, char **argv) g_notifySyncd = false; break; + case 'i': + g_inspectAsic = true; + break; + case 'h': printUsage(); exit(EXIT_SUCCESS); @@ -1302,6 +1308,8 @@ void handleCmdLine(int argc, char **argv) exit(EXIT_FAILURE); } } + + return optind; } void sai_meta_log_syncd( @@ -1340,11 +1348,11 @@ void sai_meta_log_syncd( break; case SAI_LOG_LEVEL_ERROR: p = swss::Logger::SWSS_ERROR; - fprintf(stderr, "ERROR: %s: %s", func, buffer); + fprintf(stderr, "ERROR: %s: %s\n", func, buffer); break; case SAI_LOG_LEVEL_WARN: p = swss::Logger::SWSS_WARN; - fprintf(stderr, "WARN: %s: %s", func, buffer); + fprintf(stderr, "WARN: %s: %s\n", func, buffer); break; case SAI_LOG_LEVEL_CRITICAL: p = swss::Logger::SWSS_CRIT; @@ -1366,7 +1374,9 @@ int main(int argc, char **argv) swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_NOTICE); - handleCmdLine(argc, argv); + int handled = handleCmdLine(argc, argv); + argc -= handled; + argv += handled; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-attribute=format" @@ -1380,9 +1390,6 @@ int main(int argc, char **argv) sai_attribute_t attr; - attr.id = SAI_REDIS_SWITCH_ATTR_USE_TEMP_VIEW; - attr.value.booldata = g_useTempView; - /* * Notice that we use null object id as switch id, which is fine since * those attributes don't need switch. @@ -1390,9 +1397,23 @@ int main(int argc, char **argv) sai_object_id_t switch_id = SAI_NULL_OBJECT_ID; - EXIT_ON_ERROR(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr)); + if (g_inspectAsic) + { + attr.id = SAI_REDIS_SWITCH_ATTR_NOTIFY_SYNCD; + attr.value.s32 = SAI_REDIS_NOTIFY_SYNCD_INSPECT_ASIC; + EXIT_ON_ERROR(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr)); + } + + int exitcode = 0; + if (argc > 0) + { + attr.id = SAI_REDIS_SWITCH_ATTR_USE_TEMP_VIEW; + attr.value.booldata = g_useTempView; - int exitcode = replay(argc, argv); + EXIT_ON_ERROR(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr)); + + exitcode = replay(argc, argv); + } sai_api_uninitialize(); diff --git a/syncd/syncd.cpp b/syncd/syncd.cpp index c018455f8e..ab50e0d0f5 100644 --- a/syncd/syncd.cpp +++ b/syncd/syncd.cpp @@ -11,6 +11,7 @@ extern "C" { #include #include +#include /** * @brief Global mutex for thread synchronization @@ -1440,6 +1441,165 @@ void clearTempView() initViewRemovedVidSet.clear(); } +void InspectAsic() +{ + SWSS_LOG_ENTER(); + + // Fetch all the keys from ASIC DB + // Loop through all the keys in ASIC DB + std::string pattern = ASIC_STATE_TABLE + std::string(":*"); + for (const auto &key: g_redisClient->keys(pattern)) + { + // ASIC_STATE:objecttype:objectid (object id may contain ':') + auto start = key.find_first_of(":"); + if (start == std::string::npos) + { + SWSS_LOG_ERROR("invalid ASIC_STATE_TABLE %s: no start :", key.c_str()); + break; + } + auto mid = key.find_first_of(":", start + 1); + if (mid == std::string::npos) + { + SWSS_LOG_ERROR("invalid ASIC_STATE_TABLE %s: no mid :", key.c_str()); + break; + } + auto str_object_type = key.substr(start + 1, mid - start - 1); + auto str_object_id = key.substr(mid + 1); + + sai_object_type_t object_type; + sai_deserialize_object_type(str_object_type, object_type); + + // Find all the attrid from ASIC DB, and use them to query ASIC + auto hash = g_redisClient->hgetall(key); + std::vector values; + for (auto &kv: hash) + { + const std::string &skey = kv.first; + const std::string &svalue = kv.second; + + swss::FieldValueTuple fvt(skey, svalue); + + values.push_back(fvt); + } + + SaiAttributeList list(object_type, values, false); + + sai_attribute_t *attr_list = list.get_attr_list(); + + uint32_t attr_count = list.get_attr_count(); + + SWSS_LOG_DEBUG("attr count: %u", list.get_attr_count()); + + if (attr_count == 0) + { + // TODO: how to check ASIC on ASIC DB key with NULL:NULL hash + continue; // Just ignore + } + + auto info = sai_metadata_get_object_type_info(object_type); + + // Call SAI Get API on this key + sai_status_t status; + switch (object_type) + { + case SAI_OBJECT_TYPE_FDB_ENTRY: + { + sai_fdb_entry_t fdb_entry; + sai_deserialize_fdb_entry(str_object_id, fdb_entry); + + fdb_entry.switch_id = translate_vid_to_rid(fdb_entry.switch_id); + fdb_entry.bv_id = translate_vid_to_rid(fdb_entry.bv_id); + + status = sai_metadata_sai_fdb_api->get_fdb_entry_attribute(&fdb_entry, attr_count, attr_list); + break; + } + + case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY: + { + sai_neighbor_entry_t neighbor_entry; + sai_deserialize_neighbor_entry(str_object_id, neighbor_entry); + + neighbor_entry.switch_id = translate_vid_to_rid(neighbor_entry.switch_id); + neighbor_entry.rif_id = translate_vid_to_rid(neighbor_entry.rif_id); + + status = sai_metadata_sai_neighbor_api->get_neighbor_entry_attribute(&neighbor_entry, attr_count, attr_list); + break; + } + + case SAI_OBJECT_TYPE_ROUTE_ENTRY: + { + sai_route_entry_t route_entry; + sai_deserialize_route_entry(str_object_id, route_entry); + + route_entry.switch_id = translate_vid_to_rid(route_entry.switch_id); + route_entry.vr_id = translate_vid_to_rid(route_entry.vr_id); + + status = sai_metadata_sai_route_api->get_route_entry_attribute(&route_entry, attr_count, attr_list); + break; + } + + default: + { + if (info->isnonobjectid) + { + SWSS_LOG_THROW("object %s:%s is non object id, but not handled, FIXME", + sai_serialize_object_type(object_type).c_str(), + str_object_id.c_str()); + } + + sai_object_id_t object_id; + sai_deserialize_object_id(str_object_id, object_id); + + sai_object_meta_key_t meta_key; + + meta_key.objecttype = object_type; + meta_key.objectkey.key.object_id = translate_vid_to_rid(object_id); + + status = info->get(&meta_key, attr_count, attr_list); + break; + } + } + + if (status == SAI_STATUS_NOT_IMPLEMENTED) + { + SWSS_LOG_ERROR("not implemented get api: %s", str_object_type.c_str()); + } + else if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("failed to execute get api: %s", sai_serialize_status(status).c_str()); + } + + // Compare fields and values from ASIC_DB and SAI response + // Log the difference + for (uint32_t index = 0; index < attr_count; ++index) + { + const sai_attribute_t *attr = &attr_list[index]; + + auto meta = sai_metadata_get_attr_metadata(object_type, attr->id); + + if (meta == NULL) + { + SWSS_LOG_ERROR("FATAL: failed to find metadata for object type %d and attr id %d", object_type, attr->id); + break; + } + + std::string str_attr_id = sai_serialize_attr_id(*meta); + + std::string str_attr_value = sai_serialize_attr_value(*meta, *attr, false); + + std::string hash_attr_value = hash[str_attr_id]; + if (hash_attr_value == str_attr_value) + { + SWSS_LOG_INFO("Matched %s redis attr %s with asic attr %s for %s:%s", str_attr_id.c_str(), hash_attr_value.c_str(), str_attr_value.c_str(), str_object_type.c_str(), str_object_id.c_str()); + } + else + { + SWSS_LOG_ERROR("Failed to match %s redis attr %s with asic attr %s for %s:%s", str_attr_id.c_str(), hash_attr_value.c_str(), str_attr_value.c_str(), str_object_type.c_str(), str_object_id.c_str()); + } + } + } +} + sai_status_t notifySyncd( _In_ const std::string& op) { @@ -1567,6 +1727,14 @@ sai_status_t notifySyncd( return status; } } + else if (op == SYNCD_INSPECT_ASIC) + { + SWSS_LOG_NOTICE("syncd switched to INSPECT ASIC mode"); + + InspectAsic(); + + sendNotifyResponse(SAI_STATUS_SUCCESS); + } else { SWSS_LOG_ERROR("unknown operation: %s", op.c_str());