diff --git a/lib/inc/sai_redis.h b/lib/inc/sai_redis.h index 10025277d..ebe54ad06 100644 --- a/lib/inc/sai_redis.h +++ b/lib/inc/sai_redis.h @@ -16,6 +16,8 @@ extern "C" { #include "swss/dbconnector.h" #include "swss/producertable.h" #include "swss/consumertable.h" +#include "swss/notificationconsumer.h" +#include "swss/notificationproducer.h" #include "swss/table.h" #include "swss/select.h" #include "swss/scheme.h" @@ -25,11 +27,11 @@ extern service_method_table_t g_services; extern swss::DBConnector *g_db; extern swss::ProducerTable *g_asicState; -extern swss::ProducerTable *g_notifySyncdProducer; +extern swss::NotificationProducer *g_notifySyncdProducer; extern swss::ProducerTable *g_redisGetProducer; extern swss::ConsumerTable *g_redisGetConsumer; -extern swss::ConsumerTable *g_redisNotifications; -extern swss::ConsumerTable *g_notifySyncdConsumer; +extern swss::NotificationConsumer *g_redisNotifications; +extern swss::NotificationConsumer *g_notifySyncdConsumer; extern swss::Table *g_vidToRid; extern swss::Table *g_ridToVid; diff --git a/lib/src/sai_redis_interfacequery.cpp b/lib/src/sai_redis_interfacequery.cpp index 981b8ab1d..44ac2de40 100644 --- a/lib/src/sai_redis_interfacequery.cpp +++ b/lib/src/sai_redis_interfacequery.cpp @@ -12,11 +12,11 @@ swss::DBConnector *g_dbNtf = NULL; swss::ProducerTable *g_asicState = NULL; // we probably don't need those to tables to access GET requests -swss::ProducerTable *g_notifySyncdProducer = NULL; -swss::ProducerTable *g_redisGetProducer = NULL; -swss::ConsumerTable *g_redisGetConsumer = NULL; -swss::ConsumerTable *g_redisNotifications = NULL; -swss::ConsumerTable *g_notifySyncdConsumer = NULL; +swss::NotificationProducer *g_notifySyncdProducer = NULL; +swss::ProducerTable *g_redisGetProducer = NULL; +swss::ConsumerTable *g_redisGetConsumer = NULL; +swss::NotificationConsumer *g_redisNotifications = NULL; +swss::NotificationConsumer *g_notifySyncdConsumer = NULL; swss::RedisClient *g_redisClient = NULL; @@ -60,7 +60,7 @@ sai_status_t sai_api_initialize( if (g_notifySyncdProducer != NULL) delete g_notifySyncdProducer; - g_notifySyncdProducer = new swss::ProducerTable(g_db, "NOTIFYSYNCDREQUERY"); + g_notifySyncdProducer = new swss::NotificationProducer(g_db, "NOTIFYSYNCDREQUERY"); if (g_redisGetProducer != NULL) delete g_redisGetProducer; @@ -70,7 +70,7 @@ sai_status_t sai_api_initialize( if (g_notifySyncdConsumer != NULL) delete g_notifySyncdConsumer; - g_notifySyncdConsumer = new swss::ConsumerTable(g_db, "NOTIFYSYNCRESPONSE"); + g_notifySyncdConsumer = new swss::NotificationConsumer(g_db, "NOTIFYSYNCRESPONSE"); if (g_redisGetConsumer != NULL) delete g_redisGetConsumer; @@ -80,7 +80,7 @@ sai_status_t sai_api_initialize( if (g_redisNotifications != NULL) delete g_redisNotifications; - g_redisNotifications = new swss::ConsumerTable(g_dbNtf, "NOTIFICATIONS"); + g_redisNotifications = new swss::NotificationConsumer(g_dbNtf, "NOTIFICATIONS"); if (g_redisClient != NULL) delete g_redisClient; diff --git a/lib/src/sai_redis_switch.cpp b/lib/src/sai_redis_switch.cpp index f369ce964..e8cee2c26 100644 --- a/lib/src/sai_redis_switch.cpp +++ b/lib/src/sai_redis_switch.cpp @@ -1,13 +1,15 @@ #include "sai_redis.h" #include +#include "selectableevent.h" + // if we will not get response in 60 seconds when // notify syncd to compile new state or to switch // to compiled state, then there is something wrong #define NOTIFY_SYNCD_TIMEOUT (60*1000) -#define NOTIFY_COMPILE "compile" -#define NOTIFY_SWITCH "switch" +#define NOTIFY_SAI_COMPILE_VIEW "sai_compile_view" +#define NOTIFY_SAI_SWITCH_VIEW "sai_switch_view" sai_switch_notification_t redis_switch_notifications; @@ -16,6 +18,9 @@ volatile bool g_run = false; std::shared_ptr notification_thread; +// this event is used to nice end notifications thread +swss::SelectableEvent g_redisNotificationTrheadEvent; + void ntf_thread() { SWSS_LOG_ENTER(); @@ -23,6 +28,7 @@ void ntf_thread() swss::Select s; s.addSelectable(g_redisNotifications); + s.addSelectable(&g_redisNotificationTrheadEvent); while (g_run) { @@ -30,27 +36,27 @@ void ntf_thread() int fd; - int result = s.select(&sel, &fd, 500); + int result = s.select(&sel, &fd); + + if (sel == &g_redisNotificationTrheadEvent) + { + // user requested shutdown_switch + break; + } if (result == swss::Select::OBJECT) { swss::KeyOpFieldsValuesTuple kco; - g_redisNotifications->pop(kco); + std::string op; + std::string data; + std::vector values; - const std::string &op = kfvOp(kco); - const std::string &key = kfvKey(kco); - const std::vector &values = kfvFieldsValues(kco); + g_redisNotifications->pop(op, data, values); - SWSS_LOG_DEBUG("notification: op = %s, key = %s", op.c_str(), key.c_str()); + SWSS_LOG_DEBUG("notification: op = %s, data = %s", op.c_str(), data.c_str()); - if (op != "ntf") - continue; - - const std::string &ntf = key.substr(0, key.find_first_of(":")); - const std::string &data = key.substr(key.find_last_of(":") + 1); - - handle_notification(ntf, data, values); + handle_notification(op, data, values); } } } @@ -61,7 +67,7 @@ sai_status_t notify_syncd(const std::string &op) std::vector entry; - g_notifySyncdProducer->set("", entry, op); + g_notifySyncdProducer->send(op, "", entry); swss::Select s; @@ -79,9 +85,13 @@ sai_status_t notify_syncd(const std::string &op) { swss::KeyOpFieldsValuesTuple kco; - g_notifySyncdConsumer->pop(kco); + std::string op; + std::string data; + std::vector values; - const std::string &strStatus = kfvOp(kco); + g_notifySyncdConsumer->pop(op, data, values); + + const std::string &strStatus = op; sai_status_t status; @@ -134,7 +144,7 @@ sai_status_t redis_initialize_switch( SWSS_LOG_INFO("operation: '%s'", op.c_str()); - if (op == NOTIFY_COMPILE || op == NOTIFY_SWITCH) + if (op == NOTIFY_SAI_COMPILE_VIEW || op == NOTIFY_SAI_SWITCH_VIEW) { sai_status_t status = notify_syncd(op); @@ -219,6 +229,9 @@ void redis_shutdown_switch( g_run = false; + // notify thread that it should end + g_redisNotificationTrheadEvent.notify(); + notification_thread->join(); g_switchInitialized = false; diff --git a/syncd/syncd.cpp b/syncd/syncd.cpp index 85f93218a..241588d8d 100644 --- a/syncd/syncd.cpp +++ b/syncd/syncd.cpp @@ -1,10 +1,12 @@ #include #include "syncd.h" +#include + std::mutex g_mutex; -swss::RedisClient *g_redisClient = NULL; -swss::ProducerTable *notifySyncdResponse = NULL; +swss::RedisClient *g_redisClient = NULL; +swss::NotificationProducer *notifySyncdResponse = NULL; std::map gProfileMap; @@ -320,38 +322,77 @@ void internal_syncd_get_send( } -swss::ConsumerTable *getRequest = NULL; -swss::ProducerTable *getResponse = NULL; -swss::ProducerTable *notifications = NULL; +swss::ConsumerTable *getRequest = NULL; +swss::ProducerTable *getResponse = NULL; +swss::NotificationProducer *notifications = NULL; -const char* dummy_profile_get_value( +const char* profile_get_value( _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 = gProfileMap.find(variable); if (it == gProfileMap.end()) + { + SWSS_LOG_INFO("%s: NULL", variable); return NULL; + } - return it->second.c_str(); + SWSS_LOG_INFO("%s: %s", variable, it->second.c_str()); + return it->second.c_str(); } -int dummy_profile_get_next_value( +std::map::iterator gProfileIter = gProfileMap.begin(); + +int profile_get_next_value( _In_ sai_switch_profile_id_t profile_id, _Out_ const char** variable, _Out_ const char** value) { - UNREFERENCED_PARAMETER(profile_id); - UNREFERENCED_PARAMETER(variable); - UNREFERENCED_PARAMETER(value); + SWSS_LOG_ENTER(); - return -1; + if (value == NULL) + { + SWSS_LOG_INFO("resetting profile map iterator"); + + gProfileIter = gProfileMap.begin(); + return 0; + } + + if (variable == NULL) + { + SWSS_LOG_WARN("variable is null"); + return -1; + } + + if (gProfileIter == gProfileMap.end()) + { + SWSS_LOG_INFO("iterator reached end"); + return -1; + } + + *variable = gProfileIter->first.c_str(); + *value = gProfileIter->second.c_str(); + + SWSS_LOG_INFO("key: %s:%s", *variable, *value); + + gProfileIter++; + + return 0; } const service_method_table_t test_services = { - dummy_profile_get_value, - dummy_profile_get_next_value + profile_get_value, + profile_get_next_value }; sai_status_t handle_generic( @@ -681,12 +722,7 @@ sai_status_t processEvent(swss::ConsumerTable &consumer) std::string str_object_type = key.substr(0, key.find(":")); std::string str_object_id = key.substr(key.find(":")+1); - SWSS_LOG_INFO( - "key: %s op: %s objtype: %s objid: %s", - key.c_str(), - op.c_str(), - str_object_type.c_str(), - str_object_id.c_str()); + SWSS_LOG_INFO("key: %s op: %s", key.c_str(), op.c_str()); sai_common_api_t api = SAI_COMMON_API_MAX; @@ -766,7 +802,7 @@ sai_status_t processEvent(swss::ConsumerTable &consumer) } else if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("failed to execute api: %s: %u", op.c_str(), status); + SWSS_LOG_ERROR("failed to execute api: %s: %d", op.c_str(), status); exit(EXIT_FAILURE); } @@ -774,40 +810,6 @@ sai_status_t processEvent(swss::ConsumerTable &consumer) return status; } -void handler(int sig) -{ - signal(SIGSEGV, SIG_DFL); - - SWSS_LOG_ENTER(); - - SWSS_LOG_ERROR("SIGNAL %d", sig); - - void *array[10]; - char **strings; - size_t size; - - size = backtrace(array, 10); - - SWSS_LOG_ERROR("backtrace() returned %d addresses", size); - - strings = backtrace_symbols(array, size); - - if (strings == NULL) - { - SWSS_LOG_ERROR("backtrace_sumbols() returned NULL"); - exit(EXIT_FAILURE); - } - - for (size_t j = 0; j < size; j++) - SWSS_LOG_ERROR("backtrace stack: %s", strings[j]); - - free(strings); - - backtrace_symbols_fd(array, size, STDERR_FILENO); - - exit(EXIT_FAILURE); -} - swss::Logger::Priority redisGetLogLevel() { SWSS_LOG_ENTER(); @@ -858,23 +860,24 @@ void sendResponse(sai_status_t status) SWSS_LOG_INFO("sending response: %s", strStatus.c_str()); - notifySyncdResponse->set("", entry, strStatus); + notifySyncdResponse->send(strStatus, "", entry); } -void notifySyncd(swss::ConsumerTable &consumer) +void notifySyncd(swss::NotificationConsumer &consumer) { std::lock_guard lock(g_mutex); SWSS_LOG_ENTER(); - swss::KeyOpFieldsValuesTuple kco; - consumer.pop(kco); + std::string op; + std::string data; + std::vector values; - const std::string &op = kfvOp(kco); + consumer.pop(op, data, values); sai_status_t status = SAI_STATUS_FAILURE; - if (op == "compile") + if (op == NOTIFY_SAI_COMPILE_VIEW) { // TODO SWSS_LOG_ERROR("op = %s - not implemented", op.c_str()); @@ -882,7 +885,7 @@ void notifySyncd(swss::ConsumerTable &consumer) status = SAI_STATUS_NOT_IMPLEMENTED; } - if (op == "switch") + if (op == NOTIFY_SAI_SWITCH_VIEW) { // TODO SWSS_LOG_ERROR("op = %s - not implemented", op.c_str()); @@ -897,13 +900,105 @@ void notifySyncd(swss::ConsumerTable &consumer) sendResponse(status); } +struct cmdOptions +{ + bool diagShell; + std::string profileMapFile; +}; + +cmdOptions handleCmdLine(int argc, char **argv) +{ + SWSS_LOG_ENTER(); + + cmdOptions options = {}; + + while(true) + { + static struct option long_options[] = + { + {"diag", no_argument, 0, 'd' }, + {"profile", required_argument, 0, 'p' }, + {0, 0, 0, 0} + }; + + int option_index = 0; + + int c = getopt_long(argc, argv, "dp:", long_options, &option_index); + + if (c == -1) + break; + + switch (c) + { + case 'd': + SWSS_LOG_INFO("enable diag shell"); + options.diagShell = true; + break; + + case 'p': + SWSS_LOG_INFO("profile map file: %s", optarg); + options.profileMapFile = std::string(optarg); + break; + + case '?': + SWSS_LOG_WARN("unknown get opti option %c", optopt); + exit(EXIT_FAILURE); + break; + + default: + SWSS_LOG_ERROR("getopt_long failure"); + exit(EXIT_FAILURE); + } + } + + return options; +} + +void handleProfileMap(const std::string& profileMapFile) +{ + SWSS_LOG_ENTER(); + + if (profileMapFile.size() == 0) + return; + + std::ifstream profile(profileMapFile); + + if (!profile.is_open()) + { + SWSS_LOG_ERROR("failed to open profile map file: %s : %s", profileMapFile.c_str(), strerror(errno)); + exit(EXIT_FAILURE); + } + + std::string line; + + while(getline(profile, line)) + { + size_t pos = line.find("="); + + if (pos == std::string::npos) + { + SWSS_LOG_WARN("not found '=' in line %s", line.c_str()); + continue; + } + + std::string key = line.substr(0, pos); + std::string value = line.substr(pos + 1); + + gProfileMap[key] = value; + + SWSS_LOG_INFO("insert: %s:%s", key.c_str(), value.c_str()); + } +} + int main(int argc, char **argv) { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); SWSS_LOG_ENTER(); - signal(SIGSEGV, handler); + auto options = handleCmdLine(argc, argv); + + handleProfileMap(options.profileMapFile); swss::DBConnector *db = new swss::DBConnector(ASIC_DB, "localhost", 6379, 0); swss::DBConnector *dbNtf = new swss::DBConnector(ASIC_DB, "localhost", 6379, 0); @@ -913,15 +1008,15 @@ int main(int argc, char **argv) updateLogLevel(); swss::ConsumerTable *asicState = new swss::ConsumerTable(db, "ASIC_STATE"); - swss::ConsumerTable *notifySyncdQuery = new swss::ConsumerTable(db, "NOTIFYSYNCDREQUERY"); + swss::NotificationConsumer *notifySyncdQuery = new swss::NotificationConsumer(db, "NOTIFYSYNCDREQUERY"); // at the end we cant use producer consumer concept since // if one proces will restart there may be something in the queue // also "remove" from response queue will also trigger another "response" getRequest = new swss::ConsumerTable(db, "GETREQUEST"); getResponse = new swss::ProducerTable(db, "GETRESPONSE"); - notifications = new swss::ProducerTable(dbNtf, "NOTIFICATIONS"); - notifySyncdResponse = new swss::ProducerTable(db, "NOTIFYSYNCDRESPONSE"); + notifications = new swss::NotificationProducer(dbNtf, "NOTIFICATIONS"); + notifySyncdResponse = new swss::NotificationProducer(db, "NOTIFYSYNCDRESPONSE"); #ifdef MLNXSAI std::string mlnx_config_file = "/etc/ssw/ACS-MSN2700/sai_2700.xml"; @@ -934,8 +1029,6 @@ int main(int argc, char **argv) initialize_common_api_pointers(); -#if 1 - sai_status_t status = sai_switch_api->initialize_switch(0, "0xb850", "", &switch_notifications); if (status != SAI_STATUS_SUCCESS) @@ -946,26 +1039,16 @@ int main(int argc, char **argv) #ifdef BRCMSAI - for (int i = 0; i < argc; i++) + if (options.diagShell) { - if (strcmp(argv[i],"--diag") == 0) - { - std::thread bcm_diag_shell_thread = std::thread(sai_diag_shell); - bcm_diag_shell_thread.detach(); - break; - } + SWSS_LOG_INFO("starting bcm diag shell thread"); + + std::thread bcm_diag_shell_thread = std::thread(sai_diag_shell); + bcm_diag_shell_thread.detach(); } #endif /* BRCMSAI */ -#else - sai_switch_api->initialize_switch( - 0, // profile id - "dummy_hardware_id", - "dummy_firmwre_path_name", - &switch_notifications); -#endif - SWSS_LOG_INFO("syncd started"); try @@ -1004,14 +1087,6 @@ int main(int argc, char **argv) { SWSS_LOG_ERROR("Runtime error: %s", e.what()); } - catch(...) - { - SWSS_LOG_ERROR("Runtime error: unhandled exception"); - - handler(SIGSEGV); - } sai_api_uninitialize(); } - - diff --git a/syncd/syncd.h b/syncd/syncd.h index 66e802227..f4a016288 100644 --- a/syncd/syncd.h +++ b/syncd/syncd.h @@ -22,6 +22,8 @@ extern "C" { #include "swss/dbconnector.h" #include "swss/producertable.h" #include "swss/consumertable.h" +#include "swss/notificationconsumer.h" +#include "swss/notificationproducer.h" #include "swss/select.h" #include "swss/scheme.h" #include "swss/logger.h" @@ -37,6 +39,9 @@ extern "C" { #define DEFAULT_VIRTUAL_ROUTER_ID "DEFAULT_VIRTUAL_ROUTER_ID" #define CPU_PORT_ID "CPU_PORT_ID" +#define NOTIFY_SAI_COMPILE_VIEW "sai_compile_view" +#define NOTIFY_SAI_SWITCH_VIEW "sai_switch_view" + extern std::mutex g_mutex; void onSyncdStart(); @@ -50,9 +55,9 @@ sai_object_id_t redisGetDefaultVirtualRouterId(); void redisClearVidToRidMap(); void redisClearRidToVidMap(); -extern swss::ConsumerTable *getRequest; -extern swss::ProducerTable *getResponse; -extern swss::ProducerTable *notifications; +extern swss::ConsumerTable *getRequest; +extern swss::ProducerTable *getResponse; +extern swss::NotificationProducer *notifications; extern swss::RedisClient *g_redisClient; diff --git a/syncd/syncd_notifications.cpp b/syncd/syncd_notifications.cpp index 799cce617..06ae5cef5 100644 --- a/syncd/syncd_notifications.cpp +++ b/syncd/syncd_notifications.cpp @@ -1,31 +1,28 @@ #include "syncd.h" void send_notification( - _In_ std::string key, + _In_ std::string op, _In_ std::string data, _In_ std::vector &entry) { SWSS_LOG_ENTER(); - key = key + ":" + data; + SWSS_LOG_DEBUG("sending notification: %s:%s", op.c_str(), data.c_str()); - SWSS_LOG_DEBUG("sending notification: %s", key.c_str()); - - notifications->set(key, entry, "ntf"); - notifications->del(key, "delntf"); + notifications->send(op, data, entry); SWSS_LOG_DEBUG("notification send successfull"); } void send_notification( - _In_ std::string key, + _In_ std::string op, _In_ std::string data) { SWSS_LOG_ENTER(); std::vector entry; - send_notification(key, data, entry); + send_notification(op, data, entry); } void on_switch_state_change(