From 8e21fdb411427d7adb7dd7eac66d8701d02c523a Mon Sep 17 00:00:00 2001 From: Junhua Zhai Date: Wed, 20 Jul 2022 17:01:24 +0000 Subject: [PATCH] Add mdio register read/write via rpc --- lib/sairedis.h | 9 + syncd/CommandLineOptions.cpp | 2 + syncd/CommandLineOptions.h | 2 + syncd/CommandLineOptionsParser.cpp | 15 +- syncd/Ipc.cpp | 275 +++++++++++++++++++++++++++++ syncd/Ipc.h | 135 ++++++++++++++ syncd/Makefile.am | 2 + syncd/Mdio.cpp | 204 +++++++++++++++++++++ syncd/Mdio.h | 75 ++++++++ syncd/NotificationHandler.cpp | 15 ++ syncd/Syncd.cpp | 16 ++ syncd/Syncd.h | 3 + syncd/VendorSai.cpp | 7 + syncd/VendorSai.h | 2 + 14 files changed, 758 insertions(+), 4 deletions(-) create mode 100644 syncd/Ipc.cpp create mode 100644 syncd/Ipc.h create mode 100644 syncd/Mdio.cpp create mode 100644 syncd/Mdio.h diff --git a/lib/sairedis.h b/lib/sairedis.h index 924226205..32309bde5 100644 --- a/lib/sairedis.h +++ b/lib/sairedis.h @@ -250,3 +250,12 @@ typedef enum _sai_redis_switch_attr_t SAI_REDIS_SWITCH_ATTR_SYNC_OPERATION_RESPONSE_TIMEOUT, } sai_redis_switch_attr_t; + +typedef enum _sai_redis_switch_register_fn_t +{ + SAI_REDIS_SWITCH_REGISTER_FN_NULL = 0, + SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL22_READ, + SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL22_WRITE, + SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL45_READ, + SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL45_WRITE, +} sai_redis_switch_register_fn_t; diff --git a/syncd/CommandLineOptions.cpp b/syncd/CommandLineOptions.cpp index 43ee2c2d4..f1a2ad6c7 100644 --- a/syncd/CommandLineOptions.cpp +++ b/syncd/CommandLineOptions.cpp @@ -19,6 +19,7 @@ CommandLineOptions::CommandLineOptions() m_disableExitSleep = false; m_enableUnittests = false; m_enableConsistencyCheck = false; + m_enableIpcServer = false; m_enableSyncMode = false; m_enableSaiBulkSupport = false; @@ -55,6 +56,7 @@ std::string CommandLineOptions::getCommandLineString() const ss << " DisableExitSleep=" << (m_disableExitSleep ? "YES" : "NO"); ss << " EnableUnittests=" << (m_enableUnittests ? "YES" : "NO"); ss << " EnableConsistencyCheck=" << (m_enableConsistencyCheck ? "YES" : "NO"); + ss << " EnableIpcServer=" << (m_enableIpcServer ? "YES" : "NO"); ss << " EnableSyncMode=" << (m_enableSyncMode ? "YES" : "NO"); ss << " RedisCommunicationMode=" << sai_serialize_redis_communication_mode(m_redisCommunicationMode); ss << " EnableSaiBulkSuport=" << (m_enableSaiBulkSupport ? "YES" : "NO"); diff --git a/syncd/CommandLineOptions.h b/syncd/CommandLineOptions.h index 8c1e245cd..66dbad041 100644 --- a/syncd/CommandLineOptions.h +++ b/syncd/CommandLineOptions.h @@ -68,6 +68,8 @@ namespace syncd */ bool m_enableConsistencyCheck; + bool m_enableIpcServer; + bool m_enableSyncMode; bool m_enableSaiBulkSupport; diff --git a/syncd/CommandLineOptionsParser.cpp b/syncd/CommandLineOptionsParser.cpp index f2bb90fc8..f42fe3e1a 100644 --- a/syncd/CommandLineOptionsParser.cpp +++ b/syncd/CommandLineOptionsParser.cpp @@ -19,9 +19,9 @@ std::shared_ptr CommandLineOptionsParser::parseCommandLine( auto options = std::make_shared(); #ifdef SAITHRIFT - const char* const optstring = "dp:t:g:x:b:uSUCsz:lrm:h"; + const char* const optstring = "dp:t:g:x:b:uSUCIsz:lrm:h"; #else - const char* const optstring = "dp:t:g:x:b:uSUCsz:lh"; + const char* const optstring = "dp:t:g:x:b:uSUCIsz:lh"; #endif // SAITHRIFT while (true) @@ -35,6 +35,7 @@ std::shared_ptr CommandLineOptionsParser::parseCommandLine( { "disableExitSleep", no_argument, 0, 'S' }, { "enableUnittests", no_argument, 0, 'U' }, { "enableConsistencyCheck", no_argument, 0, 'C' }, + { "enableIpcServer", no_argument, 0, 'I' }, { "syncMode", no_argument, 0, 's' }, { "redisCommunicationMode", required_argument, 0, 'z' }, { "enableSaiBulkSupport", no_argument, 0, 'l' }, @@ -94,6 +95,10 @@ std::shared_ptr CommandLineOptionsParser::parseCommandLine( options->m_enableConsistencyCheck = true; break; + case 'I': + options->m_enableIpcServer = true; + break; + case 's': SWSS_LOG_WARN("param -s is depreacated, use -z"); options->m_enableSyncMode = true; @@ -151,9 +156,9 @@ void CommandLineOptionsParser::printUsage() SWSS_LOG_ENTER(); #ifdef SAITHRIFT - std::cout << "Usage: syncd [-d] [-p profile] [-t type] [-u] [-S] [-U] [-C] [-s] [-z mode] [-l] [-g idx] [-x contextConfig] [-b breakConfig] [-r] [-m portmap] [-h]" << std::endl; + std::cout << "Usage: syncd [-d] [-p profile] [-t type] [-u] [-S] [-U] [-C] [-I] [-s] [-z mode] [-l] [-g idx] [-x contextConfig] [-b breakConfig] [-r] [-m portmap] [-h]" << std::endl; #else - std::cout << "Usage: syncd [-d] [-p profile] [-t type] [-u] [-S] [-U] [-C] [-s] [-z mode] [-l] [-g idx] [-x contextConfig] [-b breakConfig] [-h]" << std::endl; + std::cout << "Usage: syncd [-d] [-p profile] [-t type] [-u] [-S] [-U] [-C] [-I] [-s] [-z mode] [-l] [-g idx] [-x contextConfig] [-b breakConfig] [-h]" << std::endl; #endif // SAITHRIFT std::cout << " -d --diag" << std::endl; @@ -182,6 +187,8 @@ void CommandLineOptionsParser::printUsage() std::cout << " Context configuration file" << std::endl; std::cout << " -b --breakConfig" << std::endl; std::cout << " Comparison logic 'break before make' configuration file" << std::endl; + std::cout << " -I --enableIpcServer" << std::endl; + std::cout << " Enable IPC server" << std::endl; #ifdef SAITHRIFT diff --git a/syncd/Ipc.cpp b/syncd/Ipc.cpp new file mode 100644 index 000000000..8150766dc --- /dev/null +++ b/syncd/Ipc.cpp @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "swss/select.h" + +#include "Ipc.h" +#include "Mdio.h" + +using namespace swss; +using namespace syncd; + + +Ipc::Ipc(int pri) + :Selectable(pri), m_sock(-1) +{ + SWSS_LOG_ENTER(); + + registerRpc(std::make_shared()); +} + +std::shared_ptr Ipc::rpcAt(int rpc) const { + try { + return m_rpcMap.at(rpc); + } + catch (const std::out_of_range&) { + return nullptr; + } +} + +void Ipc::registerRpc(const std::shared_ptr &stub) { + m_rpcMap.insert({stub->rpc, stub}); +} + +int Ipc::getFd() +{ + SWSS_LOG_ENTER(); + + return m_sock; +} + +uint64_t Ipc::readData() +{ + SWSS_LOG_ENTER(); + + // Do nothing now, need to actively call recv/recvfrom later. + return 0; +} + +bool Ipc::hasData() +{ + SWSS_LOG_ENTER(); + + return true; +} + +bool Ipc::hasCachedData() +{ + SWSS_LOG_ENTER(); + + return false; +} + +bool Ipc::initializedWithData() +{ + SWSS_LOG_ENTER(); + + return false; +} + +void Ipc::updateAfterRead() +{ + SWSS_LOG_ENTER(); +} + +int Ipc::sendto(const IpcMsg *msg, const struct sockaddr *dest_addr, socklen_t addrlen) +{ + return (int)::sendto(m_sock, msg, msg->length, 0, dest_addr, addrlen); +} + +int Ipc::recvfrom(IpcMsg *msg, int size, struct sockaddr *src_addr, socklen_t *addrlen) +{ + return (int)::recvfrom(m_sock, msg, size, 0, src_addr, addrlen); +} + +int Ipc::send(const IpcMsg *msg) +{ + return sendto(msg, NULL, 0); +} + +int Ipc::recv(IpcMsg *msg, int size) +{ + return recvfrom(msg, size, NULL, NULL); +} + +IpcClient::IpcClient(const char *server_path) + :Ipc() +{ + SWSS_LOG_ENTER(); + + m_sock = create(server_path); +} + +int IpcClient::create(const char *server_path) +{ + SWSS_LOG_ENTER(); + + int sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) + { + SWSS_LOG_ERROR("Ipc client socket error: %s", strerror(errno)); + return -1; + } + + struct sockaddr_un name; + name.sun_family = AF_UNIX; + strncpy(name.sun_path, server_path, sizeof(name.sun_path) - 1); + if (connect(sock, (struct sockaddr *)&name, sizeof(name))) + { + SWSS_LOG_ERROR("Ipc client connect error: %s", strerror(errno)); + close(sock); + return -1; + } + + struct timeval timeout = {.tv_sec = IPC_TIMEOUT_SEC, .tv_usec = 0}; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + + return sock; +} + +IpcServer::IpcServer(const char *sock_path) + :Ipc(), m_thread(nullptr), m_switch_rid(SAI_NULL_OBJECT_ID), m_switch_api(0) +{ + SWSS_LOG_ENTER(); + + m_sock = create(sock_path); +} + +IpcServer::~IpcServer() +{ + SWSS_LOG_ENTER(); + + endThread(); +} + +int IpcServer::create(const char *sock_path) +{ + SWSS_LOG_ENTER(); + + int sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock == -1) + { + SWSS_LOG_ERROR("socket error: %s", strerror(errno)); + return -1; + } + + unlink(sock_path); + + struct sockaddr_un name; + name.sun_family = AF_UNIX; + strncpy(name.sun_path, sock_path, sizeof(name.sun_path) - 1); + if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) + { + SWSS_LOG_ERROR("bind error: %s", strerror(errno)); + close(sock); + return -1; + } + + int on = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + struct timeval timeout = {.tv_sec = IPC_TIMEOUT_SEC, .tv_usec = 0}; + setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + + return sock; +} + +void IpcServer::startThread() +{ + SWSS_LOG_ENTER(); + + if (m_thread == nullptr) + { + m_thread = std::make_shared(&IpcServer::threadProc, this); + SWSS_LOG_INFO("Ipc server thread started"); + } +} + +void IpcServer::endThread() +{ + SWSS_LOG_ENTER(); + + if (m_thread != nullptr) + { + auto thread = std::move(m_thread); + thread->join(); + SWSS_LOG_INFO("Ipc server thread ended"); + } +} + +void IpcServer::threadProc() +{ + SWSS_LOG_ENTER(); + + // Sleep a moment for ensuring m_thread OK + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + Select select; + select.addSelectable(this); + + while (m_thread) + { + Selectable *sel = nullptr; + int ret = select.select(&sel, IPC_TIMEOUT_SEC * 1000); + + if (ret == Select::ERROR) + { + SWSS_LOG_NOTICE("Ipc server select error %s", strerror(errno)); + continue; + } + + if (ret == Select::TIMEOUT) + { + SWSS_LOG_DEBUG("Ipc server select timeout"); + continue; + } + + assert(sel == this); + processMsg(); + } +} + +void IpcServer::processMsg() +{ + SWSS_LOG_ENTER(); + + union { + IpcMsg msg; + char buf[IPC_MSG_MAX_LEN]; + } m; + IpcMsg *msg = &m.msg; + + struct sockaddr_un peer; + socklen_t addrlen = sizeof(peer); + + ssize_t num = recvfrom(msg, IPC_MSG_MAX_LEN, (struct sockaddr *)&peer, &addrlen); + if (num < 0) + { + SWSS_LOG_NOTICE("Ipc server recv error %s", strerror(errno)); + return; + } + + if (num < IPC_MSG_MIN_LEN) + { + SWSS_LOG_NOTICE("Ipc server recv %d bytes, too small!", num); + return; + } + + auto stub = rpcAt(msg->subtype); + if (stub) + { + stub->process(this, msg, (struct sockaddr *)&peer, addrlen); + } + else + { + SWSS_LOG_NOTICE("Ipc server: unknown rpc %d", msg->subtype); + } +} diff --git a/syncd/Ipc.h b/syncd/Ipc.h new file mode 100644 index 000000000..002d34443 --- /dev/null +++ b/syncd/Ipc.h @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "sai.h" +} + +#include "swss/logger.h" +#include "swss/selectable.h" +#include "meta/SaiInterface.h" + +namespace syncd +{ + class RpcStub; + + enum { + IPC_TYPE_MIN = 0, + IPC_TYPE_REQ = IPC_TYPE_MIN, // request + IPC_TYPE_RESP, // response + IPC_TYPE_NOTIF, // notification + IPC_TYPE_MAX, + }; + + enum { + IPC_SUBTYPE_MIN = 0, + IPC_SUBTYPE_MDIO = IPC_SUBTYPE_MIN, // mdio rpc + IPC_SUBTYPE_MAX, + }; + + struct IpcMsg { + uint16_t type; + uint16_t subtype; + uint32_t length; + char data[0]; + }; + + static constexpr uint32_t IPC_MSG_MIN_LEN = sizeof(IpcMsg); + static constexpr uint32_t IPC_MSG_MAX_LEN = 1024; + static constexpr uint32_t IPC_TIMEOUT_SEC = 2; // in seconds + static constexpr char IPC_SERVER[] = "/var/run/redis/syncd.sock"; + + class Ipc: public swss::Selectable + { + public: + + Ipc(int pri = 0); + + virtual ~Ipc() { + if (m_sock >= 0) + { + close(m_sock); + } + } + + std::shared_ptr rpcAt(int rpc) const; + void registerRpc(const std::shared_ptr &stub); + + int sendto(const IpcMsg *msg, const struct sockaddr *dest_addr, socklen_t addrlen); + int recvfrom(IpcMsg *msg, int size, struct sockaddr *src_addr, socklen_t *addrlen); + int send(const IpcMsg *msg); + int recv(IpcMsg *msg, int size); + + public: // Selectable method + int getFd() override; + uint64_t readData() override; + bool hasData() override; + bool hasCachedData() override; + bool initializedWithData() override; + void updateAfterRead() override; + + protected: + int m_sock; + + private: + std::unordered_map> m_rpcMap; + }; + + class IpcClient: public Ipc + { + public: + IpcClient(const char *server_path = IPC_SERVER); + + private: + int create(const char *server_path); + }; + + class IpcServer: public Ipc + { + public: + IpcServer(const char *sock_path = IPC_SERVER); + ~IpcServer(); + + void startThread(); + void endThread(); + void threadProc(); + + void setSwitchId(sai_object_id_t switchRid) { + m_switch_rid = switchRid; + } + + sai_object_id_t getSwitchId() const { + return m_switch_rid; + } + + void setSwitchApi(const sai_switch_api_t* api) { + m_switch_api = api; + } + + const sai_switch_api_t* getSwitchApi(void) const { + return m_switch_api; + } + + private: + int create(const char *sock_path); + void processMsg(); + + private: + std::shared_ptr m_thread; + sai_object_id_t m_switch_rid; + const sai_switch_api_t* m_switch_api; + }; + + class RpcStub { + public: + uint16_t rpc; + virtual int call(IpcClient *client...) = 0; + virtual void process(Ipc *ipc, const IpcMsg *msg, struct sockaddr *peer, socklen_t addrlen) = 0; + }; +} diff --git a/syncd/Makefile.am b/syncd/Makefile.am index ddcdd04fc..a5c35643e 100644 --- a/syncd/Makefile.am +++ b/syncd/Makefile.am @@ -50,6 +50,8 @@ libSyncd_a_SOURCES = \ WatchdogScope.cpp \ Workaround.cpp \ ZeroMQNotificationProducer.cpp \ + Ipc.cpp \ + Mdio.cpp \ syncd_main.cpp libSyncd_a_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) diff --git a/syncd/Mdio.cpp b/syncd/Mdio.cpp new file mode 100644 index 000000000..348f951f6 --- /dev/null +++ b/syncd/Mdio.cpp @@ -0,0 +1,204 @@ +#include +#include +#include +#include + +#include "Ipc.h" +#include "Mdio.h" + +using namespace swss; +using namespace syncd; + +void RpcMdio::process(Ipc *ipc, const IpcMsg *msg, struct sockaddr *peer, socklen_t addrlen) +{ + if (msg->subtype != IPC_SUBTYPE_MDIO) + { + SWSS_LOG_NOTICE("mdio rpc process: type %u is not mine", msg->subtype); + return; + } + + if (msg->type == IPC_TYPE_REQ) + { + const IpcServer *ipcServer = dynamic_cast(ipc); + sai_object_id_t switch_id = ipcServer->getSwitchId(); + + if (switch_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_NOTICE("mdio rpc process: switch id null"); + return; + } + + union { + IpcMsg msg; + char buf[IPC_MSG_MAX_LEN]; + } m; + IpcMsg *ipcMsg = &m.msg; + IpcMsgMdioReply *mdioReply = (IpcMsgMdioReply*)(ipcMsg + 1); + + const IpcMsgMdioReq *mdioReq = (const IpcMsgMdioReq*)(msg + 1); + auto switch_api = ipcServer->getSwitchApi(); + sai_status_t status = switch_api->switch_mdio_read( + switch_id, + mdioReq->mdio_addr, + mdioReq->reg_addr, + mdioReq->reg_num, + mdioReply->reg_data); + + ipcMsg->type = IPC_TYPE_RESP; + ipcMsg->subtype = IPC_SUBTYPE_MDIO; + ipcMsg->length = sizeof(IpcMsg); + + mdioReply->status = status; + mdioReply->reg_num = 0; + ipcMsg->length += (uint32_t)sizeof(*mdioReply); + if (status == SAI_STATUS_SUCCESS) + { + mdioReply->reg_num = mdioReq->reg_num; + ipcMsg->length += mdioReply->reg_num * (uint32_t)sizeof(mdioReply->reg_data[0]); + } + + ipc->sendto(ipcMsg, peer, addrlen); + } + else if (msg->type == IPC_TYPE_NOTIF) + { + // Todo: Not support now + } +} + +int RpcMdio::call(IpcClient *client...) +{ + std::va_list args; + va_start(args, client); + uint32_t cmd = va_arg(args, uint32_t); + if (cmd < MDIO_CMD_MIN || cmd >= MDIO_CMD_MAX) + { + SWSS_LOG_NOTICE("mdio call: unknown command %u", cmd); + va_end(args); + return SAI_STATUS_FAILURE; + } + uint32_t device_addr = va_arg(args, uint32_t); + uint32_t start_reg_addr = va_arg(args, uint32_t); + uint32_t number_of_registers = va_arg(args, uint32_t); + uint32_t *reg_val = va_arg(args, uint32_t*); + va_end(args); + + union { + IpcMsg msg; + char buf[IPC_MSG_MAX_LEN]; + } m; + IpcMsg *ipcMsg = &m.msg; + IpcMsgMdioReq *mdioReq = (IpcMsgMdioReq*)(ipcMsg + 1); + + ipcMsg->type = IPC_TYPE_REQ; + ipcMsg->subtype = IPC_SUBTYPE_MDIO; + mdioReq->cmd = cmd; + mdioReq->mdio_addr = device_addr; + mdioReq->reg_addr = start_reg_addr; + mdioReq->reg_num = number_of_registers; + ipcMsg->length = sizeof(*ipcMsg) + sizeof(*mdioReq); + + if (cmd == MDIO_WRITE_CL22 || cmd == MDIO_WRITE_CL45) + { + uint32_t *reg_data = mdioReq->reg_data; + for (uint32_t i = 0; i < mdioReq->reg_num; i++) + { + reg_data[i] = reg_val[i]; + } + ipcMsg->length += mdioReq->reg_num * (uint32_t)sizeof(mdioReq->reg_data[0]); + } + + if (client->send(ipcMsg) < 0) + { + SWSS_LOG_NOTICE("mdio call: send request message failure: %s", strerror(errno)); + return SAI_STATUS_FAILURE; + } + + if (client->recv(ipcMsg, IPC_MSG_MAX_LEN) > 0) + { + assert(ipcMsg->type == IPC_TYPE_RESP); + assert(ipcMsg->length > sizeof(*ipcMsg)); + + IpcMsgMdioReply *mdioReply = (IpcMsgMdioReply*)(ipcMsg + 1); + if (mdioReply->status == SAI_STATUS_SUCCESS) + { + uint32_t *reg_data = mdioReply->reg_data; + for (uint32_t i = 0; i < mdioReply->reg_num; i++) + reg_val[i] = reg_data[i]; + } + + return mdioReply->status; + } + else + { + SWSS_LOG_NOTICE("mdio call: recv response failure: %s", strerror(errno)); + return SAI_STATUS_FAILURE; + } +} + +static sai_status_t switch_register_mdio_cmd( + _In_ uint64_t platform_context, + _In_ uint32_t cmd, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Inout_ uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + std::shared_ptr client = std::make_shared(); + auto stub = client->rpcAt(IPC_SUBTYPE_MDIO); + + return stub->call(client.get(), cmd, device_addr, start_reg_addr, number_of_registers, reg_val); +} + +sai_status_t switch_register_mdio_cl22_read( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return switch_register_mdio_cmd(platform_context, MDIO_READ_CL22, + device_addr, start_reg_addr, number_of_registers, reg_val); +} + +sai_status_t switch_register_mdio_cl22_write( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return switch_register_mdio_cmd(platform_context, MDIO_WRITE_CL22, + device_addr, start_reg_addr, number_of_registers, reg_val); +} + +sai_status_t switch_register_mdio_cl45_read( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return switch_register_mdio_cmd(platform_context, MDIO_READ_CL45, + device_addr, start_reg_addr, number_of_registers, reg_val); +} + +sai_status_t switch_register_mdio_cl45_write( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return switch_register_mdio_cmd(platform_context, MDIO_WRITE_CL45, + device_addr, start_reg_addr, number_of_registers, reg_val); +} diff --git a/syncd/Mdio.h b/syncd/Mdio.h new file mode 100644 index 000000000..d5793434b --- /dev/null +++ b/syncd/Mdio.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Ipc.h" + +extern "C" { +#include "sai.h" + +sai_status_t switch_register_mdio_cl22_read( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val); + +sai_status_t switch_register_mdio_cl22_write( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ uint32_t *reg_val); + + +sai_status_t switch_register_mdio_cl45_read( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val); + +sai_status_t switch_register_mdio_cl45_write( + _In_ uint64_t platform_context, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ uint32_t *reg_val); + +} + +namespace syncd +{ + enum { + MDIO_CMD_MIN = 1, + MDIO_READ_CL22 = MDIO_CMD_MIN, + MDIO_WRITE_CL22, + MDIO_READ_CL45, + MDIO_WRITE_CL45, + MDIO_CMD_MAX, + }; + + struct IpcMsgMdioReq { + uint32_t cmd; + uint32_t mdio_addr; + uint32_t reg_addr; + uint32_t reg_num; + uint32_t reg_data[0]; + }; + + struct IpcMsgMdioReply { + sai_status_t status; + uint32_t reg_num; + uint32_t reg_data[0]; + }; + + class RpcMdio: public RpcStub { + int call(IpcClient *client...) override; + void process(Ipc *ipc, const IpcMsg *msg, struct sockaddr *peer, socklen_t addrlen) override; + }; +} diff --git a/syncd/NotificationHandler.cpp b/syncd/NotificationHandler.cpp index 2e897a1fb..349dbfe85 100644 --- a/syncd/NotificationHandler.cpp +++ b/syncd/NotificationHandler.cpp @@ -1,4 +1,5 @@ #include "NotificationHandler.h" +#include "Mdio.h" #include "sairediscommon.h" #include "swss/logger.h" @@ -112,6 +113,20 @@ void NotificationHandler::updateNotificationsPointers( attr.value.ptr = (void*)m_switchNotifications.on_bfd_session_state_change; break; + case SAI_SWITCH_ATTR_REGISTER_READ: + if (attr.value.ptr == (void*)SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL22_READ) + attr.value.ptr = (void*)switch_register_mdio_cl22_read; + else if (attr.value.ptr == (void*)SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL45_READ) + attr.value.ptr = (void*)switch_register_mdio_cl45_read; + break; + + case SAI_SWITCH_ATTR_REGISTER_WRITE: + if (attr.value.ptr == (void*)SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL22_WRITE) + attr.value.ptr = (void*)switch_register_mdio_cl22_write; + else if (attr.value.ptr == (void*)SAI_REDIS_SWITCH_REGISTER_FN_MDIO_CL45_WRITE) + attr.value.ptr = (void*)switch_register_mdio_cl45_write; + break; + default: SWSS_LOG_ERROR("pointer for %s is not handled, FIXME!", meta->attridname); diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index 583ab893b..6b0c5296e 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -2612,6 +2612,16 @@ sai_status_t Syncd::processOidCreate( m_switches[switchVid] = std::make_shared(switchVid, objectRid, m_client, m_translator, m_vendorSai); + /* + * If IPC server is enabled, it needs to remember switch object rid and + * switch api, used by the calling of switch_mdio_read/write. + */ + if (m_ipcServer && m_switches.size() == 1) + { + m_ipcServer->setSwitchId(objectRid); + m_ipcServer->setSwitchApi(dynamic_cast(m_vendorSai.get())->get_switch_api()); + } + startDiagShell(objectRid); } @@ -4494,6 +4504,12 @@ void Syncd::run() // notification queue is created before we create switch m_processor->startNotificationsProcessingThread(); + if (m_commandLineOptions->m_enableIpcServer) + { + m_ipcServer = std::make_shared(); + m_ipcServer->startThread(); + } + SWSS_LOG_NOTICE("syncd listening for events"); s->addSelectable(m_selectableChannel.get()); diff --git a/syncd/Syncd.h b/syncd/Syncd.h index d84153703..3307fe8af 100644 --- a/syncd/Syncd.h +++ b/syncd/Syncd.h @@ -17,6 +17,7 @@ #include "BreakConfig.h" #include "NotificationProducerBase.h" #include "TimerWatchdog.h" +#include "Ipc.h" #include "meta/SaiAttributeList.h" #include "meta/SelectableChannel.h" @@ -494,5 +495,7 @@ namespace syncd TimerWatchdog m_timerWatchdog; std::set m_createdInInitView; + + std::shared_ptr m_ipcServer; }; } diff --git a/syncd/VendorSai.cpp b/syncd/VendorSai.cpp index f917a33cb..955fe3c5e 100644 --- a/syncd/VendorSai.cpp +++ b/syncd/VendorSai.cpp @@ -1270,3 +1270,10 @@ sai_status_t VendorSai::logSet( return sai_log_set(api, log_level); } + +const sai_switch_api_t* VendorSai::get_switch_api(void) const +{ + SWSS_LOG_ENTER(); + + return m_apis.switch_api; +} diff --git a/syncd/VendorSai.h b/syncd/VendorSai.h index 091a2afda..d64452cd5 100644 --- a/syncd/VendorSai.h +++ b/syncd/VendorSai.h @@ -30,6 +30,8 @@ namespace syncd sai_status_t uninitialize(void) override; + const sai_switch_api_t* get_switch_api(void) const; + public: // SAI interface overrides virtual sai_status_t create(