diff --git a/.azure-pipelines/build-template.yml b/.azure-pipelines/build-template.yml index 41bda68c0..addf51437 100644 --- a/.azure-pipelines/build-template.yml +++ b/.azure-pipelines/build-template.yml @@ -95,6 +95,7 @@ jobs: sudo sed -ri 's/^unixsocketperm .../unixsocketperm 777/' /etc/redis/redis.conf sudo sed -ri 's/redis-server.sock/redis.sock/' /etc/redis/redis.conf sudo service redis-server start + sudo mkdir -m 755 /var/run/sswsyncd sudo apt-get install -y rsyslog sudo service rsyslog start @@ -180,6 +181,8 @@ jobs: set -ex # Add SYS_TIME capability for settimeofday ok in syncd test sudo setcap "cap_sys_time=eip" syncd/.libs/syncd_tests + # Add CAP_DAC_OVERRIDE capability for system directory creation in syncd unittest + sudo setcap "cap_dac_override,cap_ipc_lock,cap_ipc_owner,cap_sys_time=eip" unittest/syncd/.libs/tests make check gcovr --version find SAI/meta -name "*.gc*" | xargs rm -vf diff --git a/debian/syncd.dirs b/debian/syncd.dirs index e77248175..527b78f2d 100644 --- a/debian/syncd.dirs +++ b/debian/syncd.dirs @@ -1 +1,2 @@ usr/bin +usr/lib diff --git a/debian/syncd.install b/debian/syncd.install index bdf0f4c8d..c559f1fea 100644 --- a/debian/syncd.install +++ b/debian/syncd.install @@ -5,3 +5,4 @@ usr/bin/saidiscovery usr/bin/saiasiccmp usr/bin/syncd* syncd/scripts/* usr/bin +usr/lib/*/libMdioIpcClient.so.* diff --git a/debian/syncd.links b/debian/syncd.links new file mode 100755 index 000000000..6f5af02f6 --- /dev/null +++ b/debian/syncd.links @@ -0,0 +1,2 @@ +#! /usr/bin/dh-exec +/usr/lib/${DEB_HOST_MULTIARCH}/libMdioIpcClient.so.0 /usr/lib/${DEB_HOST_MULTIARCH}/libMdioIpcClient.so diff --git a/meta/DummySaiInterface.cpp b/meta/DummySaiInterface.cpp index d09d8d233..8c86349ea 100644 --- a/meta/DummySaiInterface.cpp +++ b/meta/DummySaiInterface.cpp @@ -131,6 +131,54 @@ sai_status_t DummySaiInterface::flushFdbEntries( return m_status; } +sai_status_t DummySaiInterface::switchMdioRead( + _In_ sai_object_id_t switchId, + _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 m_status; +} + +sai_status_t DummySaiInterface::switchMdioWrite( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return m_status; +} + +sai_status_t DummySaiInterface::switchMdioCl22Read( + _In_ sai_object_id_t switchId, + _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 m_status; +} + +sai_status_t DummySaiInterface::switchMdioCl22Write( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + + return m_status; +} + sai_status_t DummySaiInterface::objectTypeGetAvailability( _In_ sai_object_id_t switchId, _In_ sai_object_type_t objectType, diff --git a/meta/DummySaiInterface.h b/meta/DummySaiInterface.h index 2cb9db43e..8cef2ecff 100644 --- a/meta/DummySaiInterface.h +++ b/meta/DummySaiInterface.h @@ -145,6 +145,34 @@ namespace saimeta _In_ uint32_t attrCount, _In_ const sai_attribute_t *attrList) override; + virtual sai_status_t switchMdioRead( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) override; + + virtual sai_status_t switchMdioWrite( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) override; + + virtual sai_status_t switchMdioCl22Read( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) override; + + virtual sai_status_t switchMdioCl22Write( + _In_ sai_object_id_t switch_id, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) override; + public: // SAI API virtual sai_status_t objectTypeGetAvailability( diff --git a/syncd/Makefile.am b/syncd/Makefile.am index 4b0acb829..62d5d8be0 100644 --- a/syncd/Makefile.am +++ b/syncd/Makefile.am @@ -10,7 +10,9 @@ endif bin_PROGRAMS = syncd syncd_request_shutdown syncd_tests -noinst_LIBRARIES = libSyncd.a libSyncdRequestShutdown.a +lib_LTLIBRARIES = libMdioIpcClient.la + +noinst_LIBRARIES = libSyncd.a libSyncdRequestShutdown.a libMdioIpcClient.a libSyncd_a_SOURCES = \ AsicOperation.cpp \ @@ -91,6 +93,17 @@ syncd_request_shutdown_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) syncd_request_shutdown_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) $(CODE_COVERAGE_CXXFLAGS) syncd_request_shutdown_LDADD = libSyncdRequestShutdown.a $(top_srcdir)/lib/libSaiRedis.a -lhiredis -lswsscommon -lpthread $(CODE_COVERAGE_LIBS) +libMdioIpcClient_a_SOURCES = MdioIpcClient.cpp + +libMdioIpcClient_la_SOURCES = MdioIpcClient.cpp + +libMdioIpcClient_a_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) -Wno-format-truncation +libMdioIpcClient_a_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) $(CODE_COVERAGE_CXXFLAGS) + +libMdioIpcClient_la_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) -Wno-format-truncation +libMdioIpcClient_la_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) $(CODE_COVERAGE_CXXFLAGS) +libMdioIpcClient_la_LIBADD = -lswsscommon $(CODE_COVERAGE_LIBS) + syncd_tests_SOURCES = tests.cpp syncd_tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) syncd_tests_LDFLAGS = -Wl,-rpath,$(top_srcdir)/lib/.libs -Wl,-rpath,$(top_srcdir)/meta/.libs diff --git a/syncd/MdioIpcClient.cpp b/syncd/MdioIpcClient.cpp new file mode 100644 index 000000000..015d6e4ae --- /dev/null +++ b/syncd/MdioIpcClient.cpp @@ -0,0 +1,251 @@ +/* Includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MdioIpcClient.h" +#include "MdioIpcCommon.h" + +#include "swss/logger.h" + +static std::mutex ipcMutex; + +/* Global variables */ + +static int syncd_mdio_ipc_command(char *cmd, char *resp) +{ + // SWSS_LOG_ENTER(); // disabled + + int fd; + ssize_t ret; + size_t len; + struct sockaddr_un saddr, caddr; + static int sock = 0; + static char path[128] = { 0 }; + static time_t timeout = 0; + + if (timeout < time(NULL)) + { + /* It might already be timed out at the server side, reconnect ... */ + if (sock > 0) + { + close(sock); + } + sock = 0; + } + + if (strlen(path) == 0) + { + strcpy(path, SYNCD_IPC_SOCK_SYNCD); + fd = open(path, O_DIRECTORY); + if (fd < 0) + { + SWSS_LOG_INFO("Program is not run on host\n"); + strcpy(path, SYNCD_IPC_SOCK_HOST); + fd = open(path, O_DIRECTORY); + if (fd < 0) + { + SWSS_LOG_ERROR("Unable to open the directory for IPC\n"); + return errno; + } + } + } + + if (sock <= 0) + { + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + SWSS_LOG_ERROR("socket() :%s", strerror(errno)); + return errno; + } + + caddr.sun_family = AF_UNIX; + snprintf(caddr.sun_path, sizeof(caddr.sun_path), "%s/%s.cli.%d", path, SYNCD_IPC_SOCK_FILE, getpid()); + unlink(caddr.sun_path); + if (bind(sock, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) + { + SWSS_LOG_ERROR("bind() :%s", strerror(errno)); + close(sock); + sock = 0; + return errno; + } + + saddr.sun_family = AF_UNIX; + snprintf(saddr.sun_path, sizeof(saddr.sun_path), "%s/%s.srv", path, SYNCD_IPC_SOCK_FILE); + if (connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) + { + SWSS_LOG_ERROR("connect() :%s", strerror(errno)); + close(sock); + sock = 0; + unlink(caddr.sun_path); + return errno; + } + } + + len = strlen(cmd); + ret = send(sock, cmd, len, 0); + if (ret < (ssize_t)len) + { + SWSS_LOG_ERROR("send failed, ret=%ld, expected=%ld\n", ret, len); + close(sock); + sock = 0; + unlink(caddr.sun_path); + return -EIO; + } + + ret = recv(sock, resp, SYNCD_IPC_BUFF_SIZE - 1, 0); + if (ret <= 0) + { + SWSS_LOG_ERROR("recv failed, ret=%ld\n", ret); + close(sock); + sock = 0; + unlink(caddr.sun_path); + return -EIO; + } + + timeout = time(NULL) + MDIO_CLIENT_TIMEOUT; + return (int)strtol(resp, NULL, 0); +} + + +/* Function to read data from MDIO interface */ +sai_status_t mdio_read(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, uint32_t *data) +{ + // SWSS_LOG_ENTER(); // disabled + + int rc = SAI_STATUS_FAILURE; + char cmd[SYNCD_IPC_BUFF_SIZE], resp[SYNCD_IPC_BUFF_SIZE]; + + if (number_of_registers > 1) + { + SWSS_LOG_ERROR("Multiple register reads are not supported, num_of_registers: %d\n", number_of_registers); + return SAI_STATUS_FAILURE; + } + + ipcMutex.lock(); + + sprintf(cmd, "mdio 0x%x 0x%x\n", mdio_addr, reg_addr); + rc = syncd_mdio_ipc_command(cmd, resp); + if (rc == 0) + { + *data = (uint32_t)strtoul(strchrnul(resp, ' ') + 1, NULL, 0); + rc = SAI_STATUS_SUCCESS; + } + else + { + SWSS_LOG_ERROR("syncd_mdio_ipc_command returns : %d\n", rc); + } + + ipcMutex.unlock(); + return rc; +} + +/* Function to write data to MDIO interface */ +sai_status_t mdio_write(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, const uint32_t *data) +{ + // SWSS_LOG_ENTER(); // disabled + + int rc = SAI_STATUS_FAILURE; + char cmd[SYNCD_IPC_BUFF_SIZE], resp[SYNCD_IPC_BUFF_SIZE]; + + if (number_of_registers > 1) + { + SWSS_LOG_ERROR("Multiple register reads are not supported, num_of_registers: %d\n", number_of_registers); + return SAI_STATUS_FAILURE; + } + + ipcMutex.lock(); + + sprintf(cmd, "mdio 0x%x 0x%x 0x%x\n", mdio_addr, reg_addr, *data); + rc = syncd_mdio_ipc_command(cmd, resp); + if (rc == 0) + { + rc = SAI_STATUS_SUCCESS; + } + else + { + SWSS_LOG_ERROR("syncd_mdio_ipc_command returns : %d\n", rc); + } + + ipcMutex.unlock(); + return rc; +} + +/* Function to read data using clause 22 from MDIO interface */ +sai_status_t mdio_read_cl22(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, uint32_t *data) +{ + // SWSS_LOG_ENTER(); // disabled + + int rc = SAI_STATUS_FAILURE; + char cmd[SYNCD_IPC_BUFF_SIZE], resp[SYNCD_IPC_BUFF_SIZE]; + + if (number_of_registers > 1) + { + SWSS_LOG_ERROR("Multiple register reads are not supported, num_of_registers: %d\n", number_of_registers); + return SAI_STATUS_FAILURE; + } + + ipcMutex.lock(); + + sprintf(cmd, "mdio-cl22 0x%x 0x%x\n", mdio_addr, reg_addr); + rc = syncd_mdio_ipc_command(cmd, resp); + if (rc == 0) + { + *data = (uint32_t)strtoul(strchrnul(resp, ' ') + 1, NULL, 0); + rc = SAI_STATUS_SUCCESS; + } + else + { + SWSS_LOG_ERROR("syncd_mdio_ipc_command returns : %d\n", rc); + } + + ipcMutex.unlock(); + return rc; +} + +/* Function to write data using clause 22 to MDIO interface */ +sai_status_t mdio_write_cl22(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, const uint32_t *data) +{ + // SWSS_LOG_ENTER(); // disabled + + int rc = SAI_STATUS_FAILURE; + char cmd[SYNCD_IPC_BUFF_SIZE], resp[SYNCD_IPC_BUFF_SIZE]; + + if (number_of_registers > 1) + { + SWSS_LOG_ERROR("Multiple register reads are not supported, num_of_registers: %d\n", number_of_registers); + return SAI_STATUS_FAILURE; + } + + ipcMutex.lock(); + + sprintf(cmd, "mdio-cl22 0x%x 0x%x 0x%x\n", mdio_addr, reg_addr, *data); + rc = syncd_mdio_ipc_command(cmd, resp); + if (rc == 0) + { + rc = SAI_STATUS_SUCCESS; + } + else + { + SWSS_LOG_ERROR("syncd_mdio_ipc_command returns : %d\n", rc); + } + + ipcMutex.unlock(); + return rc; +} diff --git a/syncd/MdioIpcClient.h b/syncd/MdioIpcClient.h new file mode 100644 index 000000000..908156203 --- /dev/null +++ b/syncd/MdioIpcClient.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +extern "C" { +#include "sai.h" +} + +/* Function declarations */ +extern "C" { +sai_status_t mdio_read(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, uint32_t *data); +sai_status_t mdio_write(uint64_t platform_context, uint32_t mdio_addr, + uint32_t reg_addr, uint32_t number_of_registers, const uint32_t *data); + +sai_status_t mdio_read_cl22(uint64_t platform_context, uint32_t mdio_addr, uint32_t reg_addr, + uint32_t number_of_registers, uint32_t *data); +sai_status_t mdio_write_cl22(uint64_t platform_context, uint32_t mdio_addr, + uint32_t reg_addr, uint32_t number_of_registers, const uint32_t *data); +} diff --git a/syncd/MdioIpcCommon.h b/syncd/MdioIpcCommon.h new file mode 100644 index 000000000..788de0e5e --- /dev/null +++ b/syncd/MdioIpcCommon.h @@ -0,0 +1,9 @@ +#define SYNCD_IPC_SOCK_SYNCD "/var/run/sswsyncd" +#define SYNCD_IPC_SOCK_HOST "/var/run/docker-syncd" +#define SYNCD_IPC_SOCK_FILE "mdio-ipc" +#define SYNCD_IPC_BUFF_SIZE 256 /* buffer size */ + +#define MDIO_SERVER_TIMEOUT 30 /* sec, connection timeout */ +#define MDIO_CLIENT_TIMEOUT 25 /* shorter than 30 sec on server side */ + +#define MDIO_CONN_MAX 18 /* max. number of connections */ diff --git a/syncd/MdioIpcServer.cpp b/syncd/MdioIpcServer.cpp index 452719055..7194332fb 100644 --- a/syncd/MdioIpcServer.cpp +++ b/syncd/MdioIpcServer.cpp @@ -13,6 +13,7 @@ #include #include "MdioIpcServer.h" +#include "MdioIpcCommon.h" #include "meta/sai_serialize.h" @@ -22,13 +23,6 @@ #include #include -#define SYNCD_IPC_SOCK_SYNCD "/var/run/sswsyncd" -#define SYNCD_IPC_SOCK_HOST "/var/run/docker-syncd" -#define SYNCD_IPC_SOCK_FILE "mdio-ipc" -#define SYNCD_IPC_BUFF_SIZE 256 /* buffer size */ - -#define CONN_TIMEOUT 30 /* sec, connection timeout */ -#define CONN_MAX 18 /* max. number of connections */ #ifndef COUNTOF #define COUNTOF(x) ((int)(sizeof((x)) / sizeof((x)[0]))) @@ -56,6 +50,11 @@ MdioIpcServer::MdioIpcServer( /* globalContext == 0 for syncd, globalContext > 0 for gbsyncd */ MdioIpcServer::m_syncdContext = (globalContext == 0); +#ifdef MDIO_ACCESS_USE_NPU + MdioIpcServer::m_accessUseNPU = true; +#else + MdioIpcServer::m_accessUseNPU = false; +#endif } MdioIpcServer::~MdioIpcServer() @@ -74,7 +73,12 @@ void MdioIpcServer::setSwitchId( { SWSS_LOG_ENTER(); -#ifdef MDIO_ACCESS_USE_NPU + /* Skip on any platform where MDIO access not using NPU */ + if (!m_accessUseNPU) + { + return; + } + /* MDIO switch id is only relevant in syncd but not in gbsyncd */ if (!MdioIpcServer::m_syncdContext) { @@ -91,6 +95,15 @@ void MdioIpcServer::setSwitchId( SWSS_LOG_NOTICE("Initialize mdio switch id with RID = %s", sai_serialize_object_id(m_switchRid).c_str()); +} + +void MdioIpcServer::setIpcTestMode() +{ + SWSS_LOG_ENTER(); + +#ifndef MDIO_ACCESS_USE_NPU + /* Allow unit test to start IPC server */ + MdioIpcServer::m_accessUseNPU = true; #endif } @@ -194,7 +207,7 @@ int MdioIpcServer::syncd_ipc_task_main() int sock_srv; int sock_cli; int sock_max; - syncd_mdio_ipc_conn_t conn[CONN_MAX]; + syncd_mdio_ipc_conn_t conn[MDIO_CONN_MAX]; struct sockaddr_un addr; char path[64]; fd_set rfds; @@ -236,7 +249,7 @@ int MdioIpcServer::syncd_ipc_task_main() } /* Listen for the upcoming client sockets */ - if (listen(sock_srv, CONN_MAX) < 0) + if (listen(sock_srv, MDIO_CONN_MAX) < 0) { SWSS_LOG_ERROR("listen() returns %d", errno); unlink(addr.sun_path); @@ -254,7 +267,7 @@ int MdioIpcServer::syncd_ipc_task_main() /* garbage collection */ now = time(NULL); - for (i = 0; i < CONN_MAX; ++i) + for (i = 0; i < MDIO_CONN_MAX; ++i) { if ((conn[i].fd > 0) && (conn[i].timeout < now)) { @@ -269,7 +282,7 @@ int MdioIpcServer::syncd_ipc_task_main() FD_ZERO(&rfds); FD_SET(sock_srv, &rfds); sock_max = sock_srv; - for (i = 0; i < CONN_MAX; ++i) + for (i = 0; i < MDIO_CONN_MAX; ++i) { if (conn[i].fd <= 0) { @@ -314,17 +327,17 @@ int MdioIpcServer::syncd_ipc_task_main() continue; } - for (i = 0; i < CONN_MAX; ++i) + for (i = 0; i < MDIO_CONN_MAX; ++i) { if (conn[i].fd <= 0) { break; } } - if (i < CONN_MAX) + if (i < MDIO_CONN_MAX) { conn[i].fd = sock_cli; - conn[i].timeout = now + CONN_TIMEOUT; + conn[i].timeout = now + MDIO_SERVER_TIMEOUT; } else { @@ -334,7 +347,7 @@ int MdioIpcServer::syncd_ipc_task_main() } /* Handle the client requests */ - for (i = 0; i < CONN_MAX; ++i) + for (i = 0; i < MDIO_CONN_MAX; ++i) { sai_status_t rc = SAI_STATUS_NOT_SUPPORTED; @@ -381,10 +394,18 @@ int MdioIpcServer::syncd_ipc_task_main() else if (strcmp("mdio", argv[0]) == 0) { rc = MdioIpcServer::syncd_ipc_cmd_mdio(resp, argc, argv); + if (rc != 0) + { + SWSS_LOG_ERROR("command %s returns %d", cmd, rc); + } } else if (strcmp("mdio-cl22", argv[0]) == 0) { rc = MdioIpcServer::syncd_ipc_cmd_mdio_cl22(resp, argc, argv); + if (rc != 0) + { + SWSS_LOG_ERROR("command %s returns %d", cmd, rc); + } } /* build the error message */ @@ -401,12 +422,12 @@ int MdioIpcServer::syncd_ipc_task_main() } /* update the connection timeout counter */ - conn[i].timeout = time(NULL) + CONN_TIMEOUT; + conn[i].timeout = time(NULL) + MDIO_SERVER_TIMEOUT; } } /* close socket descriptors */ - for (i = 0; i < CONN_MAX; ++i) + for (i = 0; i < MDIO_CONN_MAX; ++i) { if (conn[i].fd <= 0) { @@ -431,7 +452,12 @@ void MdioIpcServer::stopMdioThread(void) { SWSS_LOG_ENTER(); -#ifdef MDIO_ACCESS_USE_NPU + /* Skip on any platform where MDIO access not using NPU */ + if (!m_accessUseNPU) + { + return; + } + /* MDIO IPC server thread is only relevant in syncd but not in gbsyncd */ if (!MdioIpcServer::m_syncdContext) { @@ -441,14 +467,18 @@ void MdioIpcServer::stopMdioThread(void) m_taskAlive = 0; m_taskThread.join(); SWSS_LOG_NOTICE("IPC task thread is stopped\n"); -#endif } int MdioIpcServer::startMdioThread() { SWSS_LOG_ENTER(); -#ifdef MDIO_ACCESS_USE_NPU + /* Skip on any platform where MDIO access not using NPU */ + if (!m_accessUseNPU) + { + return SAI_STATUS_SUCCESS; + } + /* MDIO IPC server thread is only relevant in syncd but not in gbsyncd */ if (!MdioIpcServer::m_syncdContext) { @@ -467,6 +497,5 @@ int MdioIpcServer::startMdioThread() return SAI_STATUS_FAILURE; } } -#endif return SAI_STATUS_SUCCESS; } diff --git a/syncd/MdioIpcServer.h b/syncd/MdioIpcServer.h index 2da4e6c64..3e1dcac1a 100644 --- a/syncd/MdioIpcServer.h +++ b/syncd/MdioIpcServer.h @@ -25,6 +25,8 @@ namespace syncd void setSwitchId( _In_ sai_object_id_t switchRid); + void setIpcTestMode(); + int startMdioThread(); void stopMdioThread(); @@ -49,6 +51,8 @@ namespace syncd static bool m_syncdContext; + bool m_accessUseNPU; + std::shared_ptr m_vendorSai; sai_object_id_t m_switchRid; diff --git a/tests/aspell.en.pws b/tests/aspell.en.pws index 93bf80505..8368e2430 100644 --- a/tests/aspell.en.pws +++ b/tests/aspell.en.pws @@ -55,6 +55,7 @@ MCAST MTU Mellanox NHG +NPU OA OIDs ObjectAttrHash diff --git a/unittest/syncd/Makefile.am b/unittest/syncd/Makefile.am index 69ebd53f0..577614a19 100644 --- a/unittest/syncd/Makefile.am +++ b/unittest/syncd/Makefile.am @@ -14,9 +14,11 @@ tests_SOURCES = main.cpp \ TestNotificationQueue.cpp \ TestNotificationProcessor.cpp \ TestNotificationHandler.cpp \ + TestMdioIpcServer.cpp \ TestVendorSai.cpp tests_CXXFLAGS = $(DBGFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS_COMMON) -tests_LDADD = $(LDADD_GTEST) $(top_srcdir)/syncd/libSyncd.a $(top_srcdir)/vslib/libSaiVS.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_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 = tests diff --git a/unittest/syncd/MockableSaiInterface.cpp b/unittest/syncd/MockableSaiInterface.cpp index e52b1dc58..79dac43b1 100644 --- a/unittest/syncd/MockableSaiInterface.cpp +++ b/unittest/syncd/MockableSaiInterface.cpp @@ -1,7 +1,6 @@ #include "MockableSaiInterface.h" #include "swss/logger.h" - MockableSaiInterface::MockableSaiInterface() { SWSS_LOG_ENTER(); @@ -253,6 +252,70 @@ sai_status_t MockableSaiInterface::flushFdbEntries( return SAI_STATUS_SUCCESS; } +sai_status_t MockableSaiInterface::switchMdioRead( + _In_ sai_object_id_t switchId, + _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(); + if (mock_switchMdioRead) + { + return mock_switchMdioRead(switchId, device_addr, start_reg_addr, number_of_registers, reg_val); + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t MockableSaiInterface::switchMdioWrite( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + if (mock_switchMdioWrite) + { + return mock_switchMdioWrite(switchId, device_addr, start_reg_addr, number_of_registers, reg_val); + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t MockableSaiInterface::switchMdioCl22Read( + _In_ sai_object_id_t switchId, + _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(); + if (mock_switchMdioCl22Read) + { + return mock_switchMdioCl22Read(switchId, device_addr, start_reg_addr, number_of_registers, reg_val); + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t MockableSaiInterface::switchMdioCl22Write( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + if (mock_switchMdioCl22Write) + { + return mock_switchMdioCl22Write(switchId, device_addr, start_reg_addr, number_of_registers, reg_val); + } + + return SAI_STATUS_SUCCESS; +} + sai_status_t MockableSaiInterface::objectTypeGetAvailability( _In_ sai_object_id_t switchId, _In_ sai_object_type_t objectType, diff --git a/unittest/syncd/MockableSaiInterface.h b/unittest/syncd/MockableSaiInterface.h index 0a17e4b22..c01b51206 100644 --- a/unittest/syncd/MockableSaiInterface.h +++ b/unittest/syncd/MockableSaiInterface.h @@ -154,6 +154,42 @@ class MockableSaiInterface: public saimeta::DummySaiInterface std::function mock_flushFdbEntries; + virtual sai_status_t switchMdioRead( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) override; + + std::function mock_switchMdioRead; + + virtual sai_status_t switchMdioWrite( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) override; + + std::function mock_switchMdioWrite; + + virtual sai_status_t switchMdioCl22Read( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val) override; + + std::function mock_switchMdioCl22Read; + + virtual sai_status_t switchMdioCl22Write( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) override; + + std::function mock_switchMdioCl22Write; + public: // SAI API virtual sai_status_t objectTypeGetAvailability( diff --git a/unittest/syncd/TestMdioIpcServer.cpp b/unittest/syncd/TestMdioIpcServer.cpp new file mode 100644 index 000000000..2d99472fb --- /dev/null +++ b/unittest/syncd/TestMdioIpcServer.cpp @@ -0,0 +1,258 @@ +#include "MdioIpcServer.h" +#include "MdioIpcClient.h" +#include "MdioIpcCommon.h" +#include "MockableSaiInterface.h" +#include "swss/logger.h" + +#include +#include +#include +#include + +#include + +#define MDIO_MISSING_DEV_ADDR 0x1F +#define MDIO_MISSING_REG_ADDR 0xFFFF + +using namespace syncd; +using namespace std; + +static std::map mdioDevRegValMap; +static std::map mdioDevCl22RegValMap; + + +static sai_status_t MockMdioRead( + _In_ sai_object_id_t switchId, + _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(); + uint64_t key = device_addr; + key <<= 32; + key |= start_reg_addr; + auto it = mdioDevRegValMap.find(key); + if (it == mdioDevRegValMap.end()) + { + *reg_val = 0; + return SAI_STATUS_FAILURE; + } + else + { + *reg_val = it->second; + } + return SAI_STATUS_SUCCESS; +} + +static sai_status_t MockMdioWrite( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + if (MDIO_MISSING_DEV_ADDR == device_addr) + { + return SAI_STATUS_FAILURE; + } + uint64_t key = device_addr; + key <<= 32; + key |= start_reg_addr; + mdioDevRegValMap[key] = *reg_val; + return SAI_STATUS_SUCCESS; +} + +static sai_status_t MockMdioCl22Read( + _In_ sai_object_id_t switchId, + _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(); + uint64_t key = device_addr; + key <<= 32; + key |= start_reg_addr; + auto it = mdioDevCl22RegValMap.find(key); + if (it == mdioDevCl22RegValMap.end()) + { + *reg_val = 0; + return SAI_STATUS_FAILURE; + } + else + { + *reg_val = it->second; + } + return SAI_STATUS_SUCCESS; +} + +static sai_status_t MockMdioCl22Write( + _In_ sai_object_id_t switchId, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val) +{ + SWSS_LOG_ENTER(); + if (MDIO_MISSING_DEV_ADDR == device_addr) + { + return SAI_STATUS_FAILURE; + } + uint64_t key = device_addr; + key <<= 32; + key |= start_reg_addr; + mdioDevCl22RegValMap[key] = *reg_val; + return SAI_STATUS_SUCCESS; +} + +TEST(MdioIpcServer, mdioAccess) +{ + SWSS_LOG_ENTER(); + std::shared_ptr mdio_sai(new MockableSaiInterface()); + mdio_sai->mock_switchMdioRead = MockMdioRead; + mdio_sai->mock_switchMdioWrite = MockMdioWrite; + mdio_sai->mock_switchMdioCl22Read = MockMdioCl22Read; + mdio_sai->mock_switchMdioCl22Write = MockMdioCl22Write; + char path[64]; + strcpy(path, SYNCD_IPC_SOCK_SYNCD); + if (open(path, O_DIRECTORY) < 0) + { + SWSS_LOG_NOTICE("Directory %s does not exist", SYNCD_IPC_SOCK_SYNCD); + if (mkdir(SYNCD_IPC_SOCK_SYNCD, 0755) < 0) + { + SWSS_LOG_WARN("Can not create directory %s", SYNCD_IPC_SOCK_SYNCD); + } + } + std::shared_ptr mdio_server(new MdioIpcServer(mdio_sai, 0)); + mdio_server->setIpcTestMode(); + mdio_server->setSwitchId(0x21000000000000); + mdio_server->startMdioThread(); + sleep(1); + + uint32_t data; + uint64_t key; + sai_status_t rc; + uint32_t data2[2]; + + /* MDIO read */ + mdioDevRegValMap.clear(); + data = 0; + key = 0x4; + key <<= 32; + key |= 0x1A; + mdioDevRegValMap[key] = 0xC0DE; + rc = mdio_read(0xF0F0F0F0F0F0F0F0, 0x4, 0x1A, 1, &data); + SWSS_LOG_NOTICE("rc = %d, data = %x", rc, data); + EXPECT_EQ(rc, SAI_STATUS_SUCCESS); + EXPECT_EQ(data, 0xC0DE); + + rc = mdio_read(0xF0F0F0F0F0F0F0F0, MDIO_MISSING_DEV_ADDR, MDIO_MISSING_REG_ADDR, 1, &data); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + rc = mdio_read(0xF0F0F0F0F0F0F0F0, 0x4, 0x1A, 2, data2); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + /* MDIO write */ + mdioDevRegValMap.clear(); + data = 0xBEEF; + rc = mdio_write(0xF0F0F0F0F0F0F0F0, 0x3, 0x1B, 1, &data); + SWSS_LOG_NOTICE("rc = %d", rc); + EXPECT_EQ(rc, SAI_STATUS_SUCCESS); + key = 0x3; + key <<= 32; + key |= 0x1B; + SWSS_LOG_NOTICE("reg = %x", mdioDevRegValMap[key]); + EXPECT_EQ(mdioDevRegValMap[key], 0xBEEF); + + rc = mdio_write(0xF0F0F0F0F0F0F0F0, MDIO_MISSING_DEV_ADDR, MDIO_MISSING_REG_ADDR, 1, &data); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + rc = mdio_write(0xF0F0F0F0F0F0F0F0, 0x3, 0x1B, 2, data2); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + /* MDIO CL22 read */ + mdioDevCl22RegValMap.clear(); + data = 0x0; + key = 0x2; + key <<= 32; + key |= 0x1C; + mdioDevCl22RegValMap[key] = 0xFEED; + rc = mdio_read_cl22(0xF0F0F0F0F0F0F0F0, 0x2, 0x1C, 1, &data); + SWSS_LOG_NOTICE("rc = %d, data = %x", rc, data); + EXPECT_EQ(rc, SAI_STATUS_SUCCESS); + EXPECT_EQ(data, 0xFEED); + + rc = mdio_read_cl22(0xF0F0F0F0F0F0F0F0, MDIO_MISSING_DEV_ADDR, MDIO_MISSING_REG_ADDR, 1, &data); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + rc = mdio_read_cl22(0xF0F0F0F0F0F0F0F0, 0x2, 0x1C, 2, data2); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + /* MDIO CL22 write */ + mdioDevCl22RegValMap.clear(); + data = 0xCAFE; + rc = mdio_write_cl22(0xF0F0F0F0F0F0F0F0, 0x1, 0x1D, 1, &data); + SWSS_LOG_NOTICE("rc = %d", rc); + EXPECT_EQ(rc, SAI_STATUS_SUCCESS); + key = 0x1; + key <<= 32; + key |= 0x1D; + SWSS_LOG_NOTICE("cl22 reg = %x", mdioDevCl22RegValMap[key]); + EXPECT_EQ(mdioDevCl22RegValMap[key], 0xCAFE); + + rc = mdio_write_cl22(0xF0F0F0F0F0F0F0F0, MDIO_MISSING_DEV_ADDR, MDIO_MISSING_REG_ADDR, 1, &data); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + rc = mdio_write_cl22(0xF0F0F0F0F0F0F0F0, 0x1, 0x1D, 2, data2); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + /* Test ipc client timeout */ + sleep(MDIO_CLIENT_TIMEOUT+1); + rc = mdio_read_cl22(0xF0F0F0F0F0F0F0F0, 0x1, 0x1D, 1, &data); + EXPECT_EQ(rc, SAI_STATUS_SUCCESS); + + mdio_server->stopMdioThread(); + sleep(MDIO_CLIENT_TIMEOUT+1); +} + +TEST(MdioIpcServer, mdioConnect) +{ + SWSS_LOG_ENTER(); + std::shared_ptr mdio_sai(new MockableSaiInterface()); + mdio_sai->mock_switchMdioRead = MockMdioRead; + mdio_sai->mock_switchMdioWrite = MockMdioWrite; + mdio_sai->mock_switchMdioCl22Read = MockMdioCl22Read; + mdio_sai->mock_switchMdioCl22Write = MockMdioCl22Write; + char path[64]; + strcpy(path, SYNCD_IPC_SOCK_SYNCD); + if (open(path, O_DIRECTORY) < 0) + { + SWSS_LOG_NOTICE("Directory %s does not exist", SYNCD_IPC_SOCK_SYNCD); + if (mkdir(SYNCD_IPC_SOCK_SYNCD, 0755) < 0) + { + SWSS_LOG_WARN("Can not create directory %s", SYNCD_IPC_SOCK_SYNCD); + } + } + std::shared_ptr mdio_server(new MdioIpcServer(mdio_sai, 0)); + mdio_server->setSwitchId(0x21000000000000); + mdio_server->startMdioThread(); + sleep(1); + + uint32_t data; + uint64_t key; + sai_status_t rc; + + /* ipc connect fail without setIpcTestMode() on non broadcom platform */ + mdioDevRegValMap.clear(); + data = 0; + key = 0x4; + key <<= 32; + key |= 0x1A; + mdioDevRegValMap[key] = 0xC0DE; + rc = mdio_read(0xF0F0F0F0F0F0F0F0, 0x4, 0x1A, 1, &data); + EXPECT_NE(rc, SAI_STATUS_SUCCESS); + + mdio_server->stopMdioThread(); +}