diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index e11ec4635a..64a57a6e58 100644 --- a/cfgmgr/Makefile.am +++ b/cfgmgr/Makefile.am @@ -24,69 +24,69 @@ DBGFLAGS = -g endif vlanmgrd_SOURCES = vlanmgrd.cpp vlanmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -vlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vlanmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +vlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vlanmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) teammgrd_SOURCES = teammgrd.cpp teammgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -teammgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -teammgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -teammgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +teammgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +teammgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +teammgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) portmgrd_SOURCES = portmgrd.cpp portmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -portmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -portmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -portmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +portmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +portmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +portmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/lib/subintf.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -intfmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +intfmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) buffermgrd_SOURCES = buffermgrd.cpp buffermgr.cpp buffermgrdyn.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -buffermgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -buffermgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -buffermgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +buffermgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +buffermgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +buffermgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) vrfmgrd_SOURCES = vrfmgrd.cpp vrfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -vrfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vrfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vrfmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +vrfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vrfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vrfmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) nbrmgrd_SOURCES = nbrmgrd.cpp nbrmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -nbrmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(LIBNL_CFLAGS) -nbrmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(LIBNL_CPPFLAGS) -nbrmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) $(LIBNL_LIBS) +nbrmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(LIBNL_CFLAGS) $(CFLAGS_ASAN) +nbrmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(LIBNL_CPPFLAGS) $(CFLAGS_ASAN) +nbrmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) $(LIBNL_LIBS) vxlanmgrd_SOURCES = vxlanmgrd.cpp vxlanmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -vxlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vxlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -vxlanmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +vxlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vxlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +vxlanmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) sflowmgrd_SOURCES = sflowmgrd.cpp sflowmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -sflowmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -sflowmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -sflowmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +sflowmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +sflowmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +sflowmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) natmgrd_SOURCES = natmgrd.cpp natmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -natmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -natmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -natmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +natmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +natmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +natmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) coppmgrd_SOURCES = coppmgrd.cpp coppmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -coppmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -coppmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -coppmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +coppmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +coppmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +coppmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) tunnelmgrd_SOURCES = tunnelmgrd.cpp tunnelmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -tunnelmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -tunnelmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -tunnelmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +tunnelmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +tunnelmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +tunnelmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) macsecmgrd_SOURCES = macsecmgrd.cpp macsecmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp $(top_srcdir)/orchagent/response_publisher.cpp shellcmd.h -macsecmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -macsecmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -macsecmgrd_LDADD = $(COMMON_LIBS) $(SAIMETA_LIBS) +macsecmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +macsecmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +macsecmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) if GCOV_ENABLED vlanmgrd_LDADD += -lgcovpreload @@ -104,3 +104,19 @@ tunnelmgrd_LDADD += -lgcovpreload macsecmgrd_LDADD += -lgcovpreload endif +if ASAN_ENABLED +vlanmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +teammgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +portmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +intfmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +buffermgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +vrfmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +nbrmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +vxlanmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +sflowmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +natmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +coppmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +tunnelmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +macsecmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/cfgmgr/buffermgr.cpp b/cfgmgr/buffermgr.cpp index 0fb39a862a..5c7d6ae9e6 100644 --- a/cfgmgr/buffermgr.cpp +++ b/cfgmgr/buffermgr.cpp @@ -133,11 +133,11 @@ Create/update two tables: profile (in m_cfgBufferProfileTable) and port buffer ( } } */ -task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up) +task_process_status BufferMgr::doSpeedUpdateTask(string port) { - vector fvVectorPg, fvVectorProfile; string cable; string speed; + string pfc_enable; if (m_cableLenLookup.count(port) == 0) { @@ -152,32 +152,54 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up) return task_process_status::task_success; } - speed = m_speedLookup[port]; + if (m_portStatusLookup.count(port) == 0) + { + // admin_statue is not available yet. This can happen when notification of `PORT_QOS_MAP` table + // comes first. + SWSS_LOG_INFO("pfc_enable status is not available for port %s", port.c_str()); + return task_process_status::task_need_retry; + } + + if (m_portPfcStatus.count(port) == 0) + { + // PORT_QOS_MAP is not ready yet. The notification is cleared, and buffer pg + // will be handled when `pfc_enable` in `PORT_QOS_MAP` table is available + SWSS_LOG_INFO("pfc_enable status is not available for port %s", port.c_str()); + return task_process_status::task_success; + } + pfc_enable = m_portPfcStatus[port]; - string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + LOSSLESS_PGS; + speed = m_speedLookup[port]; // key format is pg_lossless___profile string buffer_profile_key = "pg_lossless_" + speed + "_" + cable + "_profile"; string profile_ref = buffer_profile_key; + + vector lossless_pgs = tokenize(pfc_enable, ','); - m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg); - - if (!admin_up && m_platform == "mellanox") + if (m_portStatusLookup[port] == "down" && m_platform == "mellanox") { - // Remove the entry in BUFFER_PG table if any - if (!fvVectorPg.empty()) + for (auto lossless_pg : lossless_pgs) { - for (auto &prop : fvVectorPg) + // Remove the entry in BUFFER_PG table if any + vector fvVectorPg; + string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + lossless_pg; + + m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg); + if (!fvVectorPg.empty()) { - if (fvField(prop) == "profile") + for (auto &prop : fvVectorPg) { - if (fvValue(prop) == profile_ref) + if (fvField(prop) == "profile") { - SWSS_LOG_NOTICE("Removing PG %s from port %s which is administrative down", buffer_pg_key.c_str(), port.c_str()); - m_cfgBufferPgTable.del(buffer_pg_key); - } - else - { - SWSS_LOG_NOTICE("Not default profile %s is configured on PG %s, won't reclaim buffer", fvValue(prop).c_str(), buffer_pg_key.c_str()); + if (fvValue(prop) == profile_ref) + { + SWSS_LOG_NOTICE("Removing PG %s from port %s which is administrative down", buffer_pg_key.c_str(), port.c_str()); + m_cfgBufferPgTable.del(buffer_pg_key); + } + else + { + SWSS_LOG_NOTICE("Not default profile %s is configured on PG %s, won't reclaim buffer", fvValue(prop).c_str(), buffer_pg_key.c_str()); + } } } } @@ -185,14 +207,15 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up) return task_process_status::task_success; } - + if (m_pgProfileLookup.count(speed) == 0 || m_pgProfileLookup[speed].count(cable) == 0) { - SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. No PG profile configured for speed %s and cable length %s", - port.c_str(), speed.c_str(), cable.c_str()); - return task_process_status::task_invalid_entry; + SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. No PG profile configured for speed %s and cable length %s", + port.c_str(), speed.c_str(), cable.c_str()); + return task_process_status::task_invalid_entry; } + vector fvVectorProfile; // check if profile already exists - if yes - skip creation m_cfgBufferProfileTable.get(buffer_profile_key, fvVectorProfile); // Create record in BUFFER_PROFILE table @@ -213,9 +236,10 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up) fvVectorProfile.push_back(make_pair("pool", INGRESS_LOSSLESS_PG_POOL_NAME)); fvVectorProfile.push_back(make_pair("xon", m_pgProfileLookup[speed][cable].xon)); - if (m_pgProfileLookup[speed][cable].xon_offset.length() > 0) { + if (m_pgProfileLookup[speed][cable].xon_offset.length() > 0) + { fvVectorProfile.push_back(make_pair("xon_offset", - m_pgProfileLookup[speed][cable].xon_offset)); + m_pgProfileLookup[speed][cable].xon_offset)); } fvVectorProfile.push_back(make_pair("xoff", m_pgProfileLookup[speed][cable].xoff)); fvVectorProfile.push_back(make_pair("size", m_pgProfileLookup[speed][cable].size)); @@ -227,20 +251,28 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up) SWSS_LOG_NOTICE("Reusing existing profile '%s'", buffer_profile_key.c_str()); } - /* Check if PG Mapping is already then log message and return. */ - for (auto& prop : fvVectorPg) + for (auto lossless_pg : lossless_pgs) { - if ((fvField(prop) == "profile") && (profile_ref == fvValue(prop))) + vector fvVectorPg; + string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + lossless_pg; + + m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg); + + /* Check if PG Mapping is already then log message and return. */ + for (auto& prop : fvVectorPg) { - SWSS_LOG_NOTICE("PG to Buffer Profile Mapping %s already present", buffer_pg_key.c_str()); - return task_process_status::task_success; + if ((fvField(prop) == "profile") && (profile_ref == fvValue(prop))) + { + SWSS_LOG_NOTICE("PG to Buffer Profile Mapping %s already present", buffer_pg_key.c_str()); + continue; + } } - } - fvVectorPg.clear(); + fvVectorPg.clear(); - fvVectorPg.push_back(make_pair("profile", profile_ref)); - m_cfgBufferPgTable.set(buffer_pg_key, fvVectorPg); + fvVectorPg.push_back(make_pair("profile", profile_ref)); + m_cfgBufferPgTable.set(buffer_pg_key, fvVectorPg); + } return task_process_status::task_success; } @@ -346,6 +378,47 @@ void BufferMgr::doBufferMetaTask(Consumer &consumer) } } +/* +Parse PORT_QOS_MAP to retrieve on which queue PFC is enable, and +cached in a map +*/ +void BufferMgr::doPortQosTableTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple tuple = it->second; + string port_name = kfvKey(tuple); + string op = kfvOp(tuple); + if (op == SET_COMMAND) + { + bool update_pfc_enable = false; + for (auto itp : kfvFieldsValues(tuple)) + { + if (fvField(itp) == "pfc_enable") + { + if (m_portPfcStatus.count(port_name) == 0 || m_portPfcStatus[port_name] != fvValue(itp)) + { + m_portPfcStatus[port_name] = fvValue(itp); + update_pfc_enable = true; + } + SWSS_LOG_INFO("Got pfc enable status for port %s status %s", port_name.c_str(), fvValue(itp).c_str()); + break; + } + } + if (update_pfc_enable) + { + // The return status is ignored + doSpeedUpdateTask(port_name); + } + } + it = consumer.m_toSync.erase(it); + } + +} + void BufferMgr::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -399,6 +472,12 @@ void BufferMgr::doTask(Consumer &consumer) return; } + if (table_name == CFG_PORT_QOS_MAP_TABLE_NAME) + { + doPortQosTableTask(consumer); + return; + } + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -422,7 +501,6 @@ void BufferMgr::doTask(Consumer &consumer) } else if (m_pgfile_processed && table_name == CFG_PORT_TABLE_NAME) { - bool admin_up = false; for (auto i : kfvFieldsValues(t)) { if (fvField(i) == "speed") @@ -431,39 +509,34 @@ void BufferMgr::doTask(Consumer &consumer) } if (fvField(i) == "admin_status") { - admin_up = ("up" == fvValue(i)); + m_portStatusLookup[port] = fvValue(i); } } if (m_speedLookup.count(port) != 0) { // create/update profile for port - task_status = doSpeedUpdateTask(port, admin_up); + task_status = doSpeedUpdateTask(port); } + } - if (task_status != task_process_status::task_success) - { + switch (task_status) + { + case task_process_status::task_failed: + SWSS_LOG_ERROR("Failed to process table update"); + return; + case task_process_status::task_need_retry: + SWSS_LOG_INFO("Unable to process table update. Will retry..."); + ++it; + break; + case task_process_status::task_invalid_entry: + SWSS_LOG_ERROR("Failed to process invalid entry, drop it"); + it = consumer.m_toSync.erase(it); + break; + default: + it = consumer.m_toSync.erase(it); break; - } } } - - switch (task_status) - { - case task_process_status::task_failed: - SWSS_LOG_ERROR("Failed to process table update"); - return; - case task_process_status::task_need_retry: - SWSS_LOG_INFO("Unable to process table update. Will retry..."); - ++it; - break; - case task_process_status::task_invalid_entry: - SWSS_LOG_ERROR("Failed to process invalid entry, drop it"); - it = consumer.m_toSync.erase(it); - break; - default: - it = consumer.m_toSync.erase(it); - break; - } } } diff --git a/cfgmgr/buffermgr.h b/cfgmgr/buffermgr.h index e7f04465ef..b9b3f2c496 100644 --- a/cfgmgr/buffermgr.h +++ b/cfgmgr/buffermgr.h @@ -11,7 +11,6 @@ namespace swss { #define INGRESS_LOSSLESS_PG_POOL_NAME "ingress_lossless_pool" -#define LOSSLESS_PGS "3-4" #define BUFFERMGR_TIMER_PERIOD 10 @@ -28,6 +27,8 @@ typedef std::map pg_profile_lookup_t; typedef std::map port_cable_length_t; typedef std::map port_speed_t; +typedef std::map port_pfc_status_t; +typedef std::map port_admin_status_t; class BufferMgr : public Orch { @@ -56,17 +57,22 @@ class BufferMgr : public Orch pg_profile_lookup_t m_pgProfileLookup; port_cable_length_t m_cableLenLookup; + port_admin_status_t m_portStatusLookup; port_speed_t m_speedLookup; std::string getPgPoolMode(); void readPgProfileLookupFile(std::string); task_process_status doCableTask(std::string port, std::string cable_length); - task_process_status doSpeedUpdateTask(std::string port, bool admin_up); + task_process_status doSpeedUpdateTask(std::string port); void doBufferTableTask(Consumer &consumer, ProducerStateTable &applTable); void transformSeperator(std::string &name); void doTask(Consumer &consumer); void doBufferMetaTask(Consumer &consumer); + + port_pfc_status_t m_portPfcStatus; + void doPortQosTableTask(Consumer &consumer); + }; } diff --git a/cfgmgr/buffermgrd.cpp b/cfgmgr/buffermgrd.cpp index 05932a9e3c..eb5de60b65 100644 --- a/cfgmgr/buffermgrd.cpp +++ b/cfgmgr/buffermgrd.cpp @@ -215,7 +215,8 @@ int main(int argc, char **argv) CFG_BUFFER_QUEUE_TABLE_NAME, CFG_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, - CFG_DEVICE_METADATA_TABLE_NAME + CFG_DEVICE_METADATA_TABLE_NAME, + CFG_PORT_QOS_MAP_TABLE_NAME }; cfgOrchList.emplace_back(new BufferMgr(&cfgDb, &applDb, pg_lookup_file, cfg_buffer_tables)); } diff --git a/cfgmgr/buffermgrdyn.cpp b/cfgmgr/buffermgrdyn.cpp index 322b5848bf..b3ce88c6f3 100644 --- a/cfgmgr/buffermgrdyn.cpp +++ b/cfgmgr/buffermgrdyn.cpp @@ -2853,7 +2853,7 @@ task_process_status BufferMgrDynamic::handleSingleBufferPgEntry(const string &ke // For del command: // 1. Removing it from APPL_DB // 2. Update internal caches - string &runningProfileName = bufferPg.running_profile_name; + string runningProfileName = bufferPg.running_profile_name; string &configProfileName = bufferPg.configured_profile_name; if (!m_supportRemoving) diff --git a/cfgmgr/intfmgr.cpp b/cfgmgr/intfmgr.cpp index 93281dbcd9..91ed762ef9 100644 --- a/cfgmgr/intfmgr.cpp +++ b/cfgmgr/intfmgr.cpp @@ -115,7 +115,21 @@ void IntfMgr::setIntfIp(const string &alias, const string &opCmd, int ret = swss::exec(cmd.str(), res); if (ret) { - SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret); + if (!ipPrefix.isV4() && opCmd == "add") + { + SWSS_LOG_NOTICE("Failed to assign IPv6 on interface %s with return code %d, trying to enable IPv6 and retry", alias.c_str(), ret); + if (!enableIpv6Flag(alias)) + { + SWSS_LOG_ERROR("Failed to enable IPv6 on interface %s", alias.c_str()); + return; + } + ret = swss::exec(cmd.str(), res); + } + + if (ret) + { + SWSS_LOG_ERROR("Command '%s' failed with rc %d", cmd.str().c_str(), ret); + } } } @@ -1139,3 +1153,13 @@ void IntfMgr::doPortTableTask(const string& key, vector data, s } } } + +bool IntfMgr::enableIpv6Flag(const string &alias) +{ + stringstream cmd; + string temp_res; + cmd << "sysctl -w net.ipv6.conf." << shellquote(alias) << ".disable_ipv6=0"; + int ret = swss::exec(cmd.str(), temp_res); + SWSS_LOG_INFO("disable_ipv6 flag is set to 0 for iface: %s, cmd: %s, ret: %d", alias.c_str(), cmd.str().c_str(), ret); + return (ret == 0) ? true : false; +} diff --git a/cfgmgr/intfmgr.h b/cfgmgr/intfmgr.h index 683e208c0e..65fd051200 100644 --- a/cfgmgr/intfmgr.h +++ b/cfgmgr/intfmgr.h @@ -75,6 +75,7 @@ class IntfMgr : public Orch void updateSubIntfAdminStatus(const std::string &alias, const std::string &admin); void updateSubIntfMtu(const std::string &alias, const std::string &mtu); + bool enableIpv6Flag(const std::string&); bool m_replayDone {false}; }; diff --git a/cfgmgr/macsecmgr.cpp b/cfgmgr/macsecmgr.cpp index 39cf9eae02..0edb86a5af 100644 --- a/cfgmgr/macsecmgr.cpp +++ b/cfgmgr/macsecmgr.cpp @@ -148,7 +148,7 @@ static void wpa_cli_commands( } if (!network_id.empty()) { - wpa_cli_commands(ostream, "set_network", port_name); + wpa_cli_commands(ostream, "set_network", network_id); } wpa_cli_commands(ostream, args...); } diff --git a/cfgmgr/natmgrd.cpp b/cfgmgr/natmgrd.cpp index c2baf7eb87..db5a77f9a6 100644 --- a/cfgmgr/natmgrd.cpp +++ b/cfgmgr/natmgrd.cpp @@ -62,15 +62,30 @@ NatMgr *natmgr = NULL; NotificationConsumer *timeoutNotificationsConsumer = NULL; NotificationConsumer *flushNotificationsConsumer = NULL; +static volatile sig_atomic_t gExit = 0; + std::shared_ptr cleanupNotifier; +static struct sigaction old_sigaction; + void sigterm_handler(int signo) +{ + SWSS_LOG_ENTER(); + + if (old_sigaction.sa_handler != SIG_IGN && old_sigaction.sa_handler != SIG_DFL) { + old_sigaction.sa_handler(signo); + } + + gExit = 1; +} + +void cleanup() { int ret = 0; std::string res; const std::string conntrackFlush = "conntrack -F"; - SWSS_LOG_NOTICE("Got SIGTERM"); + SWSS_LOG_ENTER(); /*If there are any conntrack entries, clean them */ ret = swss::exec(conntrackFlush, res); @@ -129,10 +144,12 @@ int main(int argc, char **argv) cleanupNotifier = std::make_shared(&appDb, "NAT_DB_CLEANUP_NOTIFICATION"); - if (signal(SIGTERM, sigterm_handler) == SIG_ERR) + struct sigaction sigact = {}; + sigact.sa_handler = sigterm_handler; + if (sigaction(SIGTERM, &sigact, &old_sigaction)) { SWSS_LOG_ERROR("failed to setup SIGTERM action handler"); - exit(1); + exit(EXIT_FAILURE); } natmgr = new NatMgr(&cfgDb, &appDb, &stateDb, cfg_tables); @@ -154,7 +171,7 @@ int main(int argc, char **argv) s.addSelectable(flushNotificationsConsumer); SWSS_LOG_NOTICE("starting main loop"); - while (true) + while (!gExit) { Selectable *sel; int ret; @@ -197,10 +214,14 @@ int main(int argc, char **argv) auto *c = (Executor *)sel; c->execute(); } + + cleanup(); } catch(const std::exception &e) { SWSS_LOG_ERROR("Runtime error: %s", e.what()); + return EXIT_FAILURE; } - return -1; + + return 0; } diff --git a/cfgmgr/teammgrd.cpp b/cfgmgr/teammgrd.cpp index 66bfa4b6d2..ff4151c921 100644 --- a/cfgmgr/teammgrd.cpp +++ b/cfgmgr/teammgrd.cpp @@ -23,9 +23,16 @@ ofstream gResponsePublisherRecordOfs; string gResponsePublisherRecordFile; bool received_sigterm = false; +static struct sigaction old_sigaction; void sig_handler(int signo) { + SWSS_LOG_ENTER(); + + if (old_sigaction.sa_handler != SIG_IGN && old_sigaction.sa_handler != SIG_DFL) { + old_sigaction.sa_handler(signo); + } + received_sigterm = true; return; } @@ -38,7 +45,13 @@ int main(int argc, char **argv) SWSS_LOG_NOTICE("--- Starting teammrgd ---"); /* Register the signal handler for SIGTERM */ - signal(SIGTERM, sig_handler); + struct sigaction sigact = {}; + sigact.sa_handler = sig_handler; + if (sigaction(SIGTERM, &sigact, &old_sigaction)) + { + SWSS_LOG_ERROR("failed to setup SIGTERM action handler"); + exit(EXIT_FAILURE); + } try { diff --git a/cfgmgr/vxlanmgr.cpp b/cfgmgr/vxlanmgr.cpp index b979149d25..4d41819053 100644 --- a/cfgmgr/vxlanmgr.cpp +++ b/cfgmgr/vxlanmgr.cpp @@ -392,8 +392,8 @@ bool VxlanMgr::doVxlanDeleteTask(const KeyOpFieldsValuesTuple & t) SWSS_LOG_WARN("Vxlan %s hasn't been created ", info.m_vxlan.c_str()); } - m_vnetCache.erase(it); SWSS_LOG_INFO("Delete vxlan %s", info.m_vxlan.c_str()); + m_vnetCache.erase(it); return true; } diff --git a/configure.ac b/configure.ac index 5e5ce44171..5efe0a67bd 100644 --- a/configure.ac +++ b/configure.ac @@ -121,6 +121,26 @@ fi AM_CONDITIONAL(GCOV_ENABLED, test x$enable_gcov = xyes) AC_MSG_RESULT($enable_gcov) +AC_ARG_ENABLE(asan, +[ --enable-asan Compile with address sanitizer], +[case "${enableval}" in + yes) asan_enabled=true ;; + no) asan_enabled=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-asan) ;; +esac],[asan_enabled=false]) + +if test "x$asan_enabled" = "xtrue"; then + CFLAGS_ASAN+=" -fsanitize=address" + CFLAGS_ASAN+=" -DASAN_ENABLED" + CFLAGS_ASAN+=" -ggdb -fno-omit-frame-pointer -U_FORTIFY_SOURCE" + AC_SUBST(CFLAGS_ASAN) + + LDFLAGS_ASAN+=" -lasan" + AC_SUBST(LDFLAGS_ASAN) +fi + +AM_CONDITIONAL(ASAN_ENABLED, test x$asan_enabled = xtrue) + AC_SUBST(CFLAGS_COMMON) AC_CONFIG_FILES([ diff --git a/debian/rules b/debian/rules index a594bb54d4..42e82b2f30 100755 --- a/debian/rules +++ b/debian/rules @@ -27,11 +27,18 @@ include /usr/share/dpkg/default.mk # dh_auto_configure -- \ # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) +configure_opts = +ifeq ($(ENABLE_ASAN), y) + configure_opts += --enable-asan +endif + ifeq ($(ENABLE_GCOV), y) -override_dh_auto_configure: - dh_auto_configure -- --enable-gcov CFLAGS="-g -O0" CXXFLAGS="-g -O0" + configure_opts += --enable-gcov CFLAGS="-g -O0" CXXFLAGS="-g -O0" endif +override_dh_auto_configure: + dh_auto_configure -- $(configure_opts) + override_dh_auto_install: dh_auto_install --destdir=debian/swss ifeq ($(ENABLE_GCOV), y) diff --git a/fdbsyncd/Makefile.am b/fdbsyncd/Makefile.am index 4ab2f5dddd..b35ee5f309 100644 --- a/fdbsyncd/Makefile.am +++ b/fdbsyncd/Makefile.am @@ -10,10 +10,15 @@ endif fdbsyncd_SOURCES = fdbsyncd.cpp fdbsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp -fdbsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) -fdbsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) -fdbsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) +fdbsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(CFLAGS_ASAN) +fdbsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(CFLAGS_ASAN) +fdbsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) if GCOV_ENABLED fdbsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +fdbsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/fpmsyncd/Makefile.am b/fpmsyncd/Makefile.am index ef709db876..29b81d7381 100644 --- a/fpmsyncd/Makefile.am +++ b/fpmsyncd/Makefile.am @@ -10,10 +10,15 @@ endif fpmsyncd_SOURCES = fpmsyncd.cpp fpmlink.cpp routesync.cpp $(top_srcdir)/warmrestart/warmRestartHelper.cpp -fpmsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -fpmsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -fpmsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon +fpmsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +fpmsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +fpmsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon if GCOV_ENABLED fpmsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +fpmsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/gearsyncd/Makefile.am b/gearsyncd/Makefile.am index c9df85853a..1a1d9983a2 100644 --- a/gearsyncd/Makefile.am +++ b/gearsyncd/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = -I $(top_srcdir)/lib -I $(top_srcdir) -I $(top_srcdir)/warmrestart -I $(top_srcdir)/cfgmgr -bin_PROGRAMS = gearsyncd +bin_PROGRAMS = gearsyncd if DEBUG DBGFLAGS = -ggdb -DDEBUG @@ -8,12 +8,17 @@ else DBGFLAGS = -g endif -gearsyncd_SOURCES = $(top_srcdir)/lib/gearboxutils.cpp gearsyncd.cpp gearparserbase.cpp gearboxparser.cpp phyparser.cpp $(top_srcdir)/cfgmgr/shellcmd.h +gearsyncd_SOURCES = $(top_srcdir)/lib/gearboxutils.cpp gearsyncd.cpp gearparserbase.cpp gearboxparser.cpp phyparser.cpp $(top_srcdir)/cfgmgr/shellcmd.h -gearsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) +gearsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(CFLAGS_ASAN) -gearsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) $(ASAN_LDFLAGS) +gearsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) if GCOV_ENABLED gearsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +gearsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/lib/asan.cpp b/lib/asan.cpp new file mode 100644 index 0000000000..053d1bd3c3 --- /dev/null +++ b/lib/asan.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +#include + +static void swss_asan_sigterm_handler(int signo) +{ + SWSS_LOG_ENTER(); + + __lsan_do_leak_check(); + + struct sigaction sigact; + if (sigaction(SIGTERM, NULL, &sigact)) + { + SWSS_LOG_ERROR("failed to get current SIGTERM action handler"); + _exit(EXIT_FAILURE); + } + + // Check the currently set signal handler. + // If it is ASAN's signal handler this means that the application didn't set its own handler. + // To preserve default behavior set the default signal handler and raise the signal to trigger its execution. + // Otherwise, the application installed its own signal handler. + // In this case, just trigger a leak check and do nothing else. + if (sigact.sa_handler == swss_asan_sigterm_handler) { + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = SIG_DFL; + if (sigaction(SIGTERM, &sigact, NULL)) + { + SWSS_LOG_ERROR("failed to setup SIGTERM action handler"); + _exit(EXIT_FAILURE); + } + + raise(signo); + } +} + +__attribute__((constructor)) +static void swss_asan_init() +{ + SWSS_LOG_ENTER(); + + struct sigaction sigact = {}; + sigact.sa_handler = swss_asan_sigterm_handler; + if (sigaction(SIGTERM, &sigact, NULL)) + { + SWSS_LOG_ERROR("failed to setup SIGTERM action handler"); + exit(EXIT_FAILURE); + } +} diff --git a/mclagsyncd/Makefile.am b/mclagsyncd/Makefile.am index e7bed8de7d..d4b4b03c40 100644 --- a/mclagsyncd/Makefile.am +++ b/mclagsyncd/Makefile.am @@ -10,10 +10,15 @@ endif mclagsyncd_SOURCES = mclagsyncd.cpp mclaglink.cpp -mclagsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -mclagsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -mclagsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon +mclagsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +mclagsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +mclagsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon if GCOV_ENABLED mclagsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +mclagsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/natsyncd/Makefile.am b/natsyncd/Makefile.am index d8212ee4b4..cdee9d52ae 100644 --- a/natsyncd/Makefile.am +++ b/natsyncd/Makefile.am @@ -10,11 +10,15 @@ endif natsyncd_SOURCES = natsyncd.cpp natsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp -natsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -natsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -natsyncd_LDADD = -lnl-3 -lnl-route-3 -lnl-nf-3 -lswsscommon +natsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +natsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +natsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lnl-nf-3 -lswsscommon if GCOV_ENABLED natsyncd_LDADD += -lgcovpreload endif +if ASAN_ENABLED +natsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/neighsyncd/Makefile.am b/neighsyncd/Makefile.am index 23e76b6cd2..cb61a83bbc 100644 --- a/neighsyncd/Makefile.am +++ b/neighsyncd/Makefile.am @@ -10,10 +10,15 @@ endif neighsyncd_SOURCES = neighsyncd.cpp neighsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp -neighsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -neighsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -neighsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon +neighsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +neighsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +neighsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon if GCOV_ENABLED neighsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +neighsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/neighsyncd/neighsync.cpp b/neighsyncd/neighsync.cpp index cb04371d41..4589e5c273 100644 --- a/neighsyncd/neighsync.cpp +++ b/neighsyncd/neighsync.cpp @@ -79,6 +79,16 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj) key+= ":"; nl_addr2str(rtnl_neigh_get_dst(neigh), ipStr, MAX_ADDR_SIZE); + + /* Ignore IPv4 link-local addresses as neighbors */ + IpAddress ipAddress(ipStr); + if (family == IPV4_NAME && ipAddress.getAddrScope() == IpAddress::AddrScope::LINK_SCOPE) + { + SWSS_LOG_INFO("Link Local address received, ignoring for %s", ipStr); + return; + } + + /* Ignore IPv6 link-local addresses as neighbors, if ipv6 link local mode is disabled */ if (family == IPV6_NAME && IN6_IS_ADDR_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh)))) { diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 6c7bbeb252..9524a61a19 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -111,21 +111,28 @@ orchagent_SOURCES += p4orch/p4orch.cpp \ p4orch/wcmp_manager.cpp \ p4orch/mirror_session_manager.cpp -orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) -orchagent_LDADD = -lnl-3 -lnl-route-3 -lpthread -lsairedis -lsaimeta -lsaimetadata -lswsscommon -lzmq +orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +orchagent_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lpthread -lsairedis -lsaimeta -lsaimetadata -lswsscommon -lzmq routeresync_SOURCES = routeresync.cpp -routeresync_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -routeresync_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -routeresync_LDADD = -lswsscommon +routeresync_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +routeresync_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +routeresync_LDADD = $(LDFLAGS_ASAN) -lswsscommon orchagent_restart_check_SOURCES = orchagent_restart_check.cpp -orchagent_restart_check_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) -orchagent_restart_check_LDADD = -lhiredis -lswsscommon -lpthread +orchagent_restart_check_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +orchagent_restart_check_LDADD = $(LDFLAGS_ASAN) -lhiredis -lswsscommon -lpthread if GCOV_ENABLED orchagent_LDADD += -lgcovpreload routeresync_LDADD += -lgcovpreload orchagent_restart_check_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +orchagent_SOURCES += $(top_srcdir)/lib/asan.cpp +routeresync_SOURCES += $(top_srcdir)/lib/asan.cpp +orchagent_restart_check_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index a373a6ac21..d4e0d8ffad 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -18,7 +18,6 @@ extern sai_fdb_api_t *sai_fdb_api; extern sai_object_id_t gSwitchId; -extern PortsOrch* gPortsOrch; extern CrmOrch * gCrmOrch; extern MlagOrch* gMlagOrch; extern Directory gDirectory; @@ -76,6 +75,7 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) string portName = port.m_alias; Port vlan; + oldFdbData.origin = FDB_ORIGIN_INVALID; if (!m_portsOrch->getPort(entry.bv_id, vlan)) { SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate \ @@ -174,6 +174,107 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) } } +/* +clears stateDb and decrements corresponding internal fdb counters +*/ +void FdbOrch::clearFdbEntry(const MacAddress& mac, + const sai_object_id_t& bv_id, + const string& port_alias) +{ + FdbUpdate update; + update.entry.mac = mac; + update.entry.bv_id = bv_id; + update.add = false; + + /* Fetch Vlan and decrement the counter */ + Port temp_vlan; + if (m_portsOrch->getPort(bv_id, temp_vlan)) + { + m_portsOrch->decrFdbCount(temp_vlan.m_alias, 1); + } + + /* Decrement port fdb_counter */ + m_portsOrch->decrFdbCount(port_alias, 1); + + /* Remove the FdbEntry from the internal cache, update state DB and CRM counter */ + storeFdbEntryState(update); + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + SWSS_LOG_INFO("FdbEntry removed from internal cache, MAC: %s , port: %s, BVID: 0x%" PRIx64, + mac.to_string().c_str(), port_alias.c_str(), bv_id); +} + +/* +Handles the SAI_FDB_EVENT_FLUSHED notification recieved from syncd +*/ +void FdbOrch::handleSyncdFlushNotif(const sai_object_id_t& bv_id, + const sai_object_id_t& bridge_port_id, + const MacAddress& mac) +{ + // Consolidated flush will have a zero mac + MacAddress flush_mac("00:00:00:00:00:00"); + + /* TODO: Read the SAI_FDB_FLUSH_ATTR_ENTRY_TYPE attr from the flush notif + and clear the entries accordingly, currently only non-static entries are flushed + */ + if (bridge_port_id == SAI_NULL_OBJECT_ID && bv_id == SAI_NULL_OBJECT_ID) + { + for (auto itr = m_entries.begin(); itr != m_entries.end();) + { + auto curr = itr++; + if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac)) + { + clearFdbEntry(curr->first.mac, curr->first.bv_id, curr->first.port_name); + } + } + } + else if (bv_id == SAI_NULL_OBJECT_ID) + { + /* FLUSH based on PORT */ + for (auto itr = m_entries.begin(); itr != m_entries.end();) + { + auto curr = itr++; + if (curr->second.bridge_port_id == bridge_port_id) + { + if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac)) + { + clearFdbEntry(curr->first.mac, curr->first.bv_id, curr->first.port_name); + } + } + } + } + else if (bridge_port_id == SAI_NULL_OBJECT_ID) + { + /* FLUSH based on BV_ID */ + for (auto itr = m_entries.begin(); itr != m_entries.end();) + { + auto curr = itr++; + if (curr->first.bv_id == bv_id) + { + if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac)) + { + clearFdbEntry(curr->first.mac, curr->first.bv_id, curr->first.port_name); + } + } + } + } + else + { + /* FLUSH based on port and VLAN */ + for (auto itr = m_entries.begin(); itr != m_entries.end();) + { + auto curr = itr++; + if (curr->first.bv_id == bv_id && curr->second.bridge_port_id == bridge_port_id) + { + if (curr->second.type != "static" && (curr->first.mac == mac || mac == flush_mac)) + { + clearFdbEntry(curr->first.mac, curr->first.bv_id, curr->first.port_name); + } + } + } + } +} + void FdbOrch::update(sai_fdb_event_t type, const sai_fdb_entry_t* entry, sai_object_id_t bridge_port_id) @@ -191,24 +292,29 @@ void FdbOrch::update(sai_fdb_event_t type, type, update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id); - if (bridge_port_id && !m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) { if (type == SAI_FDB_EVENT_FLUSHED) { - /* In case of flush - can be ignored due to a race. - There are notifications about FDB FLUSH (syncd/sai_redis) on port, - which was already removed by orchagent as a result of - removeVlanMember action (removeBridgePort) */ + /* There are notifications about FDB FLUSH (syncd/sai_redis) on port, + which was already removed by orchagent as a result of removeVlanMember + action (removeBridgePort). But the internal cleanup of statedb and + internal counters is yet to be performed, thus continue + */ SWSS_LOG_INFO("Flush event: Failed to get port by bridge port ID 0x%" PRIx64 ".", bridge_port_id); - } else { SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64 ".", bridge_port_id); - + return; } + } + + if (entry->bv_id && + !m_portsOrch->getPort(entry->bv_id, vlan)) + { + SWSS_LOG_NOTICE("FdbOrch notification type %d: Failed to locate vlan port from bv_id 0x%" PRIx64, type, entry->bv_id); return; } @@ -218,12 +324,6 @@ void FdbOrch::update(sai_fdb_event_t type, { SWSS_LOG_INFO("Received LEARN event for bvid=0x%" PRIx64 "mac=%s port=0x%" PRIx64, entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); - if (!m_portsOrch->getPort(entry->bv_id, vlan)) - { - SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); - return; - } - // we already have such entries auto existing_entry = m_entries.find(update.entry); if (existing_entry != m_entries.end()) @@ -318,11 +418,6 @@ void FdbOrch::update(sai_fdb_event_t type, SWSS_LOG_INFO("Received AGE event for bvid=0x%" PRIx64 " mac=%s port=0x%" PRIx64, entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); - if (!m_portsOrch->getPort(entry->bv_id, vlan)) - { - SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); - } - auto existing_entry = m_entries.find(update.entry); // we don't have such entries if (existing_entry == m_entries.end()) @@ -456,12 +551,6 @@ void FdbOrch::update(sai_fdb_event_t type, SWSS_LOG_INFO("Received MOVE event for bvid=0x%" PRIx64 " mac=%s port=0x%" PRIx64, entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); - if (!m_portsOrch->getPort(entry->bv_id, vlan)) - { - SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); - return; - } - // We should already have such entry if (existing_entry == m_entries.end()) { @@ -499,80 +588,15 @@ void FdbOrch::update(sai_fdb_event_t type, bridge_port_id); string vlanName = "-"; - if (entry->bv_id) { - Port vlan; - - if (!m_portsOrch->getPort(entry->bv_id, vlan)) - { - SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan\ - port from bv_id 0x%" PRIx64, entry->bv_id); - return; - } + if (!vlan.m_alias.empty()) { vlanName = "Vlan" + to_string(vlan.m_vlan_info.vlan_id); } + SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: %s }", update.entry.mac.to_string().c_str(), + vlanName.c_str(), update.port.m_alias.c_str()); - if (bridge_port_id == SAI_NULL_OBJECT_ID && - entry->bv_id == SAI_NULL_OBJECT_ID) - { - SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: - }", - update.entry.mac.to_string().c_str(), vlanName.c_str()); - for (auto itr = m_entries.begin(); itr != m_entries.end();) - { - /* - TODO: here should only delete the dynamic fdb entries, - but unfortunately in structure FdbEntry currently have - no member to indicate the fdb entry type, - if there is static mac added, here will have issue. - */ - update.entry.mac = itr->first.mac; - update.entry.bv_id = itr->first.bv_id; - update.add = false; - itr++; - - storeFdbEntryState(update); - - notify(SUBJECT_TYPE_FDB_CHANGE, &update); - - } - } - else if (entry->bv_id == SAI_NULL_OBJECT_ID) - { - /* FLUSH based on port */ - SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: %s }", - update.entry.mac.to_string().c_str(), - vlanName.c_str(), update.port.m_alias.c_str()); - - for (auto itr = m_entries.begin(); itr != m_entries.end();) - { - auto next_item = std::next(itr); - if (itr->first.port_name == update.port.m_alias) - { - update.entry.mac = itr->first.mac; - update.entry.bv_id = itr->first.bv_id; - update.add = false; + handleSyncdFlushNotif(entry->bv_id, bridge_port_id, update.entry.mac); - storeFdbEntryState(update); - notify(SUBJECT_TYPE_FDB_CHANGE, &update); - } - itr = next_item; - } - } - else if (bridge_port_id == SAI_NULL_OBJECT_ID) - { - /* FLUSH based on VLAN - unsupported */ - SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: - }", - update.entry.mac.to_string().c_str(), - vlanName.c_str()); - - } - else - { - /* FLUSH based on port and VLAN - unsupported */ - SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: %s }", - update.entry.mac.to_string().c_str(), - vlanName.c_str(), update.port.m_alias.c_str()); - } break; } @@ -648,7 +672,7 @@ void FdbOrch::doTask(Consumer& consumer) { SWSS_LOG_ENTER(); - if (!gPortsOrch->allPortsReady()) + if (!m_portsOrch->allPortsReady()) { return; } @@ -855,7 +879,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) { SWSS_LOG_ENTER(); - if (!gPortsOrch->allPortsReady()) + if (!m_portsOrch->allPortsReady()) { return; } @@ -891,7 +915,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) SWSS_LOG_ERROR("Receive wrong port to flush fdb!"); return; } - if (!gPortsOrch->getPort(alias, port)) + if (!m_portsOrch->getPort(alias, port)) { SWSS_LOG_ERROR("Get Port from port(%s) failed!", alias.c_str()); return; @@ -912,7 +936,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) SWSS_LOG_ERROR("Receive wrong vlan to flush fdb!"); return; } - if (!gPortsOrch->getPort(vlan, vlanPort)) + if (!m_portsOrch->getPort(vlan, vlanPort)) { SWSS_LOG_ERROR("Get Port from vlan(%s) failed!", vlan.c_str()); return; @@ -938,12 +962,12 @@ void FdbOrch::doTask(NotificationConsumer& consumer) SWSS_LOG_ERROR("Receive wrong port or vlan to flush fdb!"); return; } - if (!gPortsOrch->getPort(alias, port)) + if (!m_portsOrch->getPort(alias, port)) { SWSS_LOG_ERROR("Get Port from port(%s) failed!", alias.c_str()); return; } - if (!gPortsOrch->getPort(vlan, vlanPort)) + if (!m_portsOrch->getPort(vlan, vlanPort)) { SWSS_LOG_ERROR("Get Port from vlan(%s) failed!", vlan.c_str()); return; diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 82611e686f..3e53dcd394 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -122,6 +122,9 @@ class FdbOrch: public Orch, public Subject, public Observer bool storeFdbEntryState(const FdbUpdate& update); void notifyTunnelOrch(Port& port); + + void clearFdbEntry(const MacAddress&, const sai_object_id_t&, const string&); + void handleSyncdFlushNotif(const sai_object_id_t&, const sai_object_id_t&, const MacAddress& ); }; #endif /* SWSS_FDBORCH_H */ diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index 587e04e140..9bc36f7bb6 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -1204,6 +1204,7 @@ bool IntfsOrch::removeRouterIntfs(Port &port) const auto id = sai_serialize_object_id(port.m_rif_id); removeRifFromFlexCounter(id, port.m_alias); + cleanUpRifFromCounterDb(id, port.m_alias); sai_status_t status = sai_router_intfs_api->remove_router_interface(port.m_rif_id); if (status != SAI_STATUS_SUCCESS) @@ -1426,11 +1427,45 @@ void IntfsOrch::removeRifFromFlexCounter(const string &id, const string &name) SWSS_LOG_DEBUG("Unregistered interface %s from Flex counter", name.c_str()); } +/* + TODO A race condition can exist when swss removes the counter from COUNTERS DB + and at the same time syncd is inserting a new entry in COUNTERS DB. Therefore + all the rif counters cleanup code should move to syncd +*/ +void IntfsOrch::cleanUpRifFromCounterDb(const string &id, const string &name) +{ + SWSS_LOG_ENTER(); + string counter_key = getRifCounterTableKey(id); + string rate_key = getRifRateTableKey(id); + string rate_init_key = getRifRateInitTableKey(id); + m_counter_db->del(counter_key); + m_counter_db->del(rate_key); + m_counter_db->del(rate_init_key); + SWSS_LOG_NOTICE("CleanUp interface %s oid %s from counter db", name.c_str(),id.c_str()); +} + string IntfsOrch::getRifFlexCounterTableKey(string key) { return string(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP) + ":" + key; } +string IntfsOrch::getRifCounterTableKey(string key) +{ + return "COUNTERS:" + key; +} + +string IntfsOrch::getRifRateTableKey(string key) +{ + return "RATES:" + key; +} + +string IntfsOrch::getRifRateInitTableKey(string key) +{ + return "RATES:" + key + ":RIF"; +} + + + void IntfsOrch::generateInterfaceMap() { m_updateMapsTimer->start(); diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index 5605abf133..341675bac1 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -90,6 +90,10 @@ class IntfsOrch : public Orch unique_ptr m_flexCounterGroupTable; std::string getRifFlexCounterTableKey(std::string s); + std::string getRifCounterTableKey(std::string s); + std::string getRifRateTableKey(std::string s); + std::string getRifRateInitTableKey(std::string s); + void cleanUpRifFromCounterDb(const string &id, const string &name); bool addRouterIntfs(sai_object_id_t vrf_id, Port &port); bool removeRouterIntfs(Port &port); diff --git a/orchagent/macsecorch.cpp b/orchagent/macsecorch.cpp index a82882ed24..20b6057733 100644 --- a/orchagent/macsecorch.cpp +++ b/orchagent/macsecorch.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -13,6 +14,8 @@ #include #include #include +#include +#include /* Global Variables*/ @@ -218,6 +221,68 @@ static void lexical_convert(const std::string &buffer, MACsecAuthKey &auth_key) } } +class MACsecSCI +{ +public: + operator sai_uint64_t () const + { + SWSS_LOG_ENTER(); + + return m_sci; + } + + std::string str() const + { + SWSS_LOG_ENTER(); + + return boost::algorithm::to_lower_copy(swss::binary_to_hex(&m_sci, sizeof(m_sci))); + } + + MACsecSCI& operator= (const std::string &buffer) + { + SWSS_LOG_ENTER(); + + if (!swss::hex_to_binary(buffer, reinterpret_cast(&m_sci), sizeof(m_sci))) + { + SWSS_LOG_THROW("Invalid SCI %s", buffer.c_str()); + } + + return *this; + } + + MACsecSCI() = default; + + MACsecSCI(const sai_uint64_t sci) + { + SWSS_LOG_ENTER(); + + this->m_sci = sci; + } + +private: + sai_uint64_t m_sci; +}; + +namespace swss { + +template<> +inline void lexical_convert(const std::string &buffer, MACsecSCI &sci) +{ + SWSS_LOG_ENTER(); + + sci = buffer; +} + +} + +std::ostream& operator<<(std::ostream& stream, const MACsecSCI& sci) +{ + SWSS_LOG_ENTER(); + + stream << sci.str(); + return stream; +} + /* Recover from a fail action by a serial of pre-defined recover actions */ class RecoverStack { @@ -805,7 +870,7 @@ task_process_status MACsecOrch::taskUpdateEgressSA( { SWSS_LOG_ENTER(); std::string port_name; - sai_uint64_t sci = 0; + MACsecSCI sci; macsec_an_t an = 0; if (!extract_variables(port_sci_an, ':', port_name, sci, an) || an > MAX_SA_NUMBER) { @@ -816,12 +881,35 @@ task_process_status MACsecOrch::taskUpdateEgressSA( MACsecOrchContext ctx(this, port_name, SAI_MACSEC_DIRECTION_EGRESS, sci, an); if (ctx.get_macsec_sc() == nullptr) { - SWSS_LOG_INFO("The MACsec SC 0x%" PRIx64 " hasn't been created at the port %s.", sci, port_name.c_str()); + SWSS_LOG_INFO("The MACsec SC %s hasn't been created at the port %s.", sci.str().c_str(), port_name.c_str()); return task_need_retry; } if (ctx.get_macsec_sc()->m_encoding_an == an) { - return createMACsecSA(port_sci_an, sa_attr, SAI_MACSEC_DIRECTION_EGRESS); + if (ctx.get_macsec_sa() == nullptr) + { + // The MACsec SA hasn't been created + return createMACsecSA(port_sci_an, sa_attr, SAI_MACSEC_DIRECTION_EGRESS); + } + else + { + // The MACsec SA has enabled, update SA's attributes + sai_uint64_t pn; + + if (get_value(sa_attr, "next_pn", pn)) + { + sai_attribute_t attr; + attr.id = SAI_MACSEC_SA_ATTR_CONFIGURED_EGRESS_XPN; + attr.value.u64 = pn; + if (!this->updateMACsecAttr(SAI_OBJECT_TYPE_MACSEC_SA, *(ctx.get_macsec_sa()), attr)) + { + SWSS_LOG_WARN("Fail to update next pn (%" PRIu64 ") of egress MACsec SA %s", pn, port_sci_an.c_str()); + return task_failed; + } + } + + return task_success; + } } return task_need_retry; } @@ -841,7 +929,7 @@ task_process_status MACsecOrch::taskUpdateIngressSA( SWSS_LOG_ENTER(); swss::AlphaBoolean alpha_boolean = false; - get_value(sa_attr, "active", alpha_boolean); + bool has_active_field = get_value(sa_attr, "active", alpha_boolean); bool active = alpha_boolean.operator bool(); if (active) { @@ -851,7 +939,7 @@ task_process_status MACsecOrch::taskUpdateIngressSA( { std::string port_name; - sai_uint64_t sci = 0; + MACsecSCI sci; macsec_an_t an = 0; if (!extract_variables(port_sci_an, ':', port_name, sci, an) || an > MAX_SA_NUMBER) { @@ -863,7 +951,29 @@ task_process_status MACsecOrch::taskUpdateIngressSA( if (ctx.get_macsec_sa() != nullptr) { - return deleteMACsecSA(port_sci_an, SAI_MACSEC_DIRECTION_INGRESS); + if (has_active_field) + { + // Delete MACsec SA explicitly by set active to false + return deleteMACsecSA(port_sci_an, SAI_MACSEC_DIRECTION_INGRESS); + } + else + { + sai_uint64_t pn; + + if (get_value(sa_attr, "lowest_acceptable_pn", pn)) + { + sai_attribute_t attr; + attr.id = SAI_MACSEC_SA_ATTR_MINIMUM_INGRESS_XPN; + attr.value.u64 = pn; + if (!this->updateMACsecAttr(SAI_OBJECT_TYPE_MACSEC_SA, *(ctx.get_macsec_sa()), attr)) + { + SWSS_LOG_WARN("Fail to update lowest acceptable PN (%" PRIu64 ") of ingress MACsec SA %s", pn, port_sci_an.c_str()); + return task_failed; + } + } + + return task_success; + } } else { @@ -874,6 +984,8 @@ task_process_status MACsecOrch::taskUpdateIngressSA( return task_need_retry; } } + + return task_success; } task_process_status MACsecOrch::taskDeleteIngressSA( @@ -970,6 +1082,32 @@ bool MACsecOrch::initMACsecObject(sai_object_id_t switch_id) } macsec_obj.first->second.m_sci_in_ingress_macsec_acl = attrs.front().value.booldata; + attrs.clear(); + attr.id = SAI_MACSEC_ATTR_MAX_SECURE_ASSOCIATIONS_PER_SC; + attrs.push_back(attr); + status = sai_macsec_api->get_macsec_attribute( + macsec_obj.first->second.m_ingress_id, + static_cast(attrs.size()), + attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + // Default to 4 if SAI_MACSEC_ATTR_MAX_SECURE_ASSOCIATION_PER_SC isn't supported + macsec_obj.first->second.m_max_sa_per_sc = 4; + } else { + switch (attrs.front().value.s32) + { + case SAI_MACSEC_MAX_SECURE_ASSOCIATIONS_PER_SC_TWO: + macsec_obj.first->second.m_max_sa_per_sc = 2; + break; + case SAI_MACSEC_MAX_SECURE_ASSOCIATIONS_PER_SC_FOUR: + macsec_obj.first->second.m_max_sa_per_sc = 4; + break; + default: + SWSS_LOG_WARN( "Unsupported value returned from SAI_MACSEC_ATTR_MAX_SECURE_ASSOCIATION_PER_SC" ); + return false; + } + } + recover.clear(); return true; } @@ -1154,6 +1292,7 @@ bool MACsecOrch::createMACsecPort( SWSS_LOG_NOTICE("MACsec port %s is created.", port_name.c_str()); std::vector fvVector; + fvVector.emplace_back("max_sa_per_sc", std::to_string(macsec_obj.m_max_sa_per_sc)); fvVector.emplace_back("state", "ok"); m_state_macsec_port.set(port_name, fvVector); @@ -1335,7 +1474,7 @@ bool MACsecOrch::deleteMACsecPort( auto sc = macsec_port.m_egress_scs.begin(); while (sc != macsec_port.m_egress_scs.end()) { - const std::string port_sci = swss::join(':', port_name, sc->first); + const std::string port_sci = swss::join(':', port_name, MACsecSCI(sc->first)); sc ++; if (deleteMACsecSC(port_sci, SAI_MACSEC_DIRECTION_EGRESS) != task_success) { @@ -1345,7 +1484,7 @@ bool MACsecOrch::deleteMACsecPort( sc = macsec_port.m_ingress_scs.begin(); while (sc != macsec_port.m_ingress_scs.end()) { - const std::string port_sci = swss::join(':', port_name, sc->first); + const std::string port_sci = swss::join(':', port_name, MACsecSCI(sc->first)); sc ++; if (deleteMACsecSC(port_sci, SAI_MACSEC_DIRECTION_INGRESS) != task_success) { @@ -1485,7 +1624,7 @@ task_process_status MACsecOrch::updateMACsecSC( SWSS_LOG_ENTER(); std::string port_name; - sai_uint64_t sci = {0}; + MACsecSCI sci; if (!extract_variables(port_sci, ':', port_name, sci)) { SWSS_LOG_WARN("The key %s isn't correct.", port_sci.c_str()); @@ -1564,7 +1703,7 @@ bool MACsecOrch::createMACsecSC( RecoverStack recover; - const std::string port_sci = swss::join(':', port_name, sci); + const std::string port_sci = swss::join(':', port_name, MACsecSCI(sci)); auto scs = (direction == SAI_MACSEC_DIRECTION_EGRESS) @@ -1657,11 +1796,11 @@ bool MACsecOrch::createMACsecSC( fvVector.emplace_back("state", "ok"); if (direction == SAI_MACSEC_DIRECTION_EGRESS) { - m_state_macsec_egress_sc.set(swss::join('|', port_name, sci), fvVector); + m_state_macsec_egress_sc.set(swss::join('|', port_name, MACsecSCI(sci)), fvVector); } else { - m_state_macsec_ingress_sc.set(swss::join('|', port_name, sci), fvVector); + m_state_macsec_ingress_sc.set(swss::join('|', port_name, MACsecSCI(sci)), fvVector); } recover.clear(); @@ -1709,7 +1848,7 @@ bool MACsecOrch::createMACsecSC( attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN("Cannot create MACsec egress SC 0x%" PRIx64, sci); + SWSS_LOG_WARN("Cannot create MACsec egress SC %s", MACsecSCI(sci).str().c_str()); task_process_status handle_status = handleSaiCreateStatus(SAI_API_MACSEC, status); if (handle_status != task_success) { @@ -1726,7 +1865,7 @@ task_process_status MACsecOrch::deleteMACsecSC( SWSS_LOG_ENTER(); std::string port_name; - sai_uint64_t sci = 0; + MACsecSCI sci; if (!extract_variables(port_sci, ':', port_name, sci)) { SWSS_LOG_WARN("The key %s isn't correct.", port_sci.c_str()); @@ -1779,11 +1918,11 @@ task_process_status MACsecOrch::deleteMACsecSC( if (direction == SAI_MACSEC_DIRECTION_EGRESS) { - m_state_macsec_egress_sc.del(swss::join('|', port_name, sci)); + m_state_macsec_egress_sc.del(swss::join('|', port_name, MACsecSCI(sci))); } else { - m_state_macsec_ingress_sc.del(swss::join('|', port_name, sci)); + m_state_macsec_ingress_sc.del(swss::join('|', port_name, MACsecSCI(sci))); } return result; @@ -1849,7 +1988,7 @@ task_process_status MACsecOrch::createMACsecSA( SWSS_LOG_ENTER(); std::string port_name; - sai_uint64_t sci = 0; + MACsecSCI sci; macsec_an_t an = 0; if (!extract_variables(port_sci_an, ':', port_name, sci, an) || an > MAX_SA_NUMBER) { @@ -1867,7 +2006,7 @@ task_process_status MACsecOrch::createMACsecSA( if (ctx.get_macsec_sc() == nullptr) { - SWSS_LOG_INFO("The MACsec SC 0x%" PRIx64 " hasn't been created at the port %s.", sci, port_name.c_str()); + SWSS_LOG_INFO("The MACsec SC %s hasn't been created at the port %s.", sci.str().c_str(), port_name.c_str()); return task_need_retry; } auto sc = ctx.get_macsec_sc(); @@ -2010,7 +2149,7 @@ task_process_status MACsecOrch::deleteMACsecSA( SWSS_LOG_ENTER(); std::string port_name = ""; - sai_uint64_t sci = 0; + MACsecSCI sci; macsec_an_t an = 0; if (!extract_variables(port_sci_an, ':', port_name, sci, an) || an > MAX_SA_NUMBER) { diff --git a/orchagent/macsecorch.h b/orchagent/macsecorch.h index 33f7b7082e..b59984a3a6 100644 --- a/orchagent/macsecorch.h +++ b/orchagent/macsecorch.h @@ -110,6 +110,7 @@ class MACsecOrch : public Orch sai_object_id_t m_ingress_id; map > m_macsec_ports; bool m_sci_in_ingress_macsec_acl; + sai_uint8_t m_max_sa_per_sc; }; map m_macsec_objs; map > m_macsec_ports; diff --git a/orchagent/main.cpp b/orchagent/main.cpp index 6f397cb42e..5a074450da 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -177,7 +177,7 @@ void getCfgSwitchType(DBConnector *cfgDb, string &switch_type) switch_type = "switch"; } - if (switch_type != "voq" && switch_type != "fabric" && switch_type != "switch") + if (switch_type != "voq" && switch_type != "fabric" && switch_type != "chassis-packet" && switch_type != "switch") { SWSS_LOG_ERROR("Invalid switch type %s configured", switch_type.c_str()); //If configured switch type is none of the supported, assume regular switch @@ -570,7 +570,7 @@ int main(int argc, char **argv) attr.value.u64 = gSwitchId; attrs.push_back(attr); - if (gMySwitchType == "voq" || gMySwitchType == "fabric") + if (gMySwitchType == "voq" || gMySwitchType == "fabric" || gMySwitchType == "chassis-packet") { /* We set this long timeout in order for orchagent to wait enough time for * response from syncd. It is needed since switch create takes more time @@ -578,7 +578,7 @@ int main(int argc, char **argv) * and systems ports to initialize */ - if (gMySwitchType == "voq") + if (gMySwitchType == "voq" || gMySwitchType == "chassis-packet") { attr.value.u64 = (5 * SAI_REDIS_DEFAULT_SYNC_OPERATION_RESPONSE_TIMEOUT); } @@ -608,7 +608,7 @@ int main(int argc, char **argv) } SWSS_LOG_NOTICE("Create a switch, id:%" PRIu64, gSwitchId); - if (gMySwitchType == "voq" || gMySwitchType == "fabric") + if (gMySwitchType == "voq" || gMySwitchType == "fabric" || gMySwitchType == "chassis-packet") { /* Set syncd response timeout back to the default value */ attr.id = SAI_REDIS_SWITCH_ATTR_SYNC_OPERATION_RESPONSE_TIMEOUT; diff --git a/orchagent/mirrororch.cpp b/orchagent/mirrororch.cpp index fca324e5fb..75ff671fc8 100644 --- a/orchagent/mirrororch.cpp +++ b/orchagent/mirrororch.cpp @@ -797,8 +797,7 @@ bool MirrorOrch::setUnsetPortMirror(Port port, if (set) { port_attr.value.objlist.count = 1; - port_attr.value.objlist.list = reinterpret_cast(calloc(port_attr.value.objlist.count, sizeof(sai_object_id_t))); - port_attr.value.objlist.list[0] = sessionId; + port_attr.value.objlist.list = &sessionId; } else { diff --git a/orchagent/pfcwdorch.cpp b/orchagent/pfcwdorch.cpp index be4c1e51c4..62765ab0a1 100644 --- a/orchagent/pfcwdorch.cpp +++ b/orchagent/pfcwdorch.cpp @@ -399,9 +399,9 @@ void PfcWdSwOrch::enableBigRedSwitchMode() continue; } - if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) + if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); + SWSS_LOG_ERROR("Failed to get PFC watchdog mask on port %s", port.m_alias.c_str()); return; } @@ -443,9 +443,9 @@ void PfcWdSwOrch::enableBigRedSwitchMode() continue; } - if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) + if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); + SWSS_LOG_ERROR("Failed to get PFC watchdog mask on port %s", port.m_alias.c_str()); return; } @@ -489,7 +489,7 @@ bool PfcWdSwOrch::registerInWdDb(const Port& port, uint8_t pfcMask = 0; - if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) + if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask)) { SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); return false; diff --git a/orchagent/port.h b/orchagent/port.h index 83f61e1b1c..db9f2b7bff 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -139,7 +139,8 @@ class Port std::vector m_queue_ids; std::vector m_priority_group_ids; sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED; - uint8_t m_pfc_bitmask = 0; + uint8_t m_pfc_bitmask = 0; // PFC enable bit mask + uint8_t m_pfcwd_sw_bitmask = 0; // PFC software watchdog enable uint16_t m_tpid = DEFAULT_TPID; uint32_t m_nat_zone_id = 0; uint32_t m_vnid = VNID_NONE; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index d394b53f46..5a6ba61e5c 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -118,12 +118,16 @@ static map interface_type_map = { "none", SAI_PORT_INTERFACE_TYPE_NONE }, { "cr", SAI_PORT_INTERFACE_TYPE_CR }, { "cr4", SAI_PORT_INTERFACE_TYPE_CR4 }, + { "cr8", SAI_PORT_INTERFACE_TYPE_CR8 }, { "sr", SAI_PORT_INTERFACE_TYPE_SR }, { "sr4", SAI_PORT_INTERFACE_TYPE_SR4 }, + { "sr8", SAI_PORT_INTERFACE_TYPE_SR8 }, { "lr", SAI_PORT_INTERFACE_TYPE_LR }, { "lr4", SAI_PORT_INTERFACE_TYPE_LR4 }, + { "lr8", SAI_PORT_INTERFACE_TYPE_LR8 }, { "kr", SAI_PORT_INTERFACE_TYPE_KR }, - { "kr4", SAI_PORT_INTERFACE_TYPE_KR4 } + { "kr4", SAI_PORT_INTERFACE_TYPE_KR4 }, + { "kr8", SAI_PORT_INTERFACE_TYPE_KR8 } }; // Interface type map used for auto negotiation @@ -133,13 +137,17 @@ static map interface_type_map_for_an = { "cr", SAI_PORT_INTERFACE_TYPE_CR }, { "cr2", SAI_PORT_INTERFACE_TYPE_CR2 }, { "cr4", SAI_PORT_INTERFACE_TYPE_CR4 }, + { "cr8", SAI_PORT_INTERFACE_TYPE_CR8 }, { "sr", SAI_PORT_INTERFACE_TYPE_SR }, { "sr2", SAI_PORT_INTERFACE_TYPE_SR2 }, { "sr4", SAI_PORT_INTERFACE_TYPE_SR4 }, + { "sr8", SAI_PORT_INTERFACE_TYPE_SR8 }, { "lr", SAI_PORT_INTERFACE_TYPE_LR }, { "lr4", SAI_PORT_INTERFACE_TYPE_LR4 }, + { "lr8", SAI_PORT_INTERFACE_TYPE_LR8 }, { "kr", SAI_PORT_INTERFACE_TYPE_KR }, { "kr4", SAI_PORT_INTERFACE_TYPE_KR4 }, + { "kr8", SAI_PORT_INTERFACE_TYPE_KR8 }, { "caui", SAI_PORT_INTERFACE_TYPE_CAUI }, { "gmii", SAI_PORT_INTERFACE_TYPE_GMII }, { "sfi", SAI_PORT_INTERFACE_TYPE_SFI }, @@ -1193,6 +1201,43 @@ bool PortsOrch::setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask) return true; } +bool PortsOrch::setPortPfcWatchdogStatus(sai_object_id_t portId, uint8_t pfcwd_bitmask) +{ + SWSS_LOG_ENTER(); + + Port p; + + if (!getPort(portId, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, portId); + return false; + } + + p.m_pfcwd_sw_bitmask = pfcwd_bitmask; + + m_portList[p.m_alias] = p; + + SWSS_LOG_INFO("Set PFC watchdog port id=0x%" PRIx64 ", bitmast=0x%x", portId, pfcwd_bitmask); + return true; +} + +bool PortsOrch::getPortPfcWatchdogStatus(sai_object_id_t portId, uint8_t *pfcwd_bitmask) +{ + SWSS_LOG_ENTER(); + + Port p; + + if (!pfcwd_bitmask || !getPort(portId, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, portId); + return false; + } + + *pfcwd_bitmask = p.m_pfcwd_sw_bitmask; + + return true; +} + bool PortsOrch::setPortPfcAsym(Port &port, string pfc_asym) { SWSS_LOG_ENTER(); @@ -4528,9 +4573,10 @@ bool PortsOrch::removeVlan(Port vlan) return false for retry */ if (vlan.m_fdb_count > 0) { - SWSS_LOG_NOTICE("VLAN %s still has assiciated FDB entries", vlan.m_alias.c_str()); + SWSS_LOG_NOTICE("VLAN %s still has %d FDB entries", vlan.m_alias.c_str(), vlan.m_fdb_count); return false; } + if (m_port_ref_count[vlan.m_alias] > 0) { SWSS_LOG_ERROR("Failed to remove ref count %d VLAN %s", @@ -6883,3 +6929,17 @@ std::unordered_set PortsOrch::generateCounterStats(const string& ty } return counter_stats; } + +bool PortsOrch::decrFdbCount(const std::string& alias, int count) +{ + auto itr = m_portList.find(alias); + if (itr == m_portList.end()) + { + return false; + } + else + { + itr->second.m_fdb_count -= count; + } + return true; +} diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index bdfcf47ad0..2848cdcb91 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -124,6 +124,9 @@ class PortsOrch : public Orch, public Subject bool getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask); bool setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask); + bool setPortPfcWatchdogStatus(sai_object_id_t portId, uint8_t pfc_bitmask); + bool getPortPfcWatchdogStatus(sai_object_id_t portId, uint8_t *pfc_bitmask); + void generateQueueMap(); void generatePriorityGroupMap(); void generatePortCounterMap(); @@ -165,6 +168,7 @@ class PortsOrch : public Orch, public Subject bool getPortOperStatus(const Port& port, sai_port_oper_status_t& status) const; + bool decrFdbCount(const string& alias, int count); private: unique_ptr m_counterTable; unique_ptr
m_counterLagTable; diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp index 24814c3710..5cb9d8ad2e 100644 --- a/orchagent/qosorch.cpp +++ b/orchagent/qosorch.cpp @@ -1779,6 +1779,7 @@ task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer, KeyOpFiel } sai_uint8_t pfc_enable = 0; + sai_uint8_t pfcwd_sw_enable = 0; map> update_list; for (auto it = kfvFieldsValues(tuple).begin(); it != kfvFieldsValues(tuple).end(); it++) { @@ -1800,14 +1801,24 @@ task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer, KeyOpFiel setObjectReference(m_qos_maps, CFG_PORT_QOS_MAP_TABLE_NAME, key, map_type_name, object_name); } - if (fvField(*it) == pfc_enable_name) + else if (fvField(*it) == pfc_enable_name || fvField(*it) == pfcwd_sw_enable_name) { + sai_uint8_t bitmask = 0; vector queue_indexes; queue_indexes = tokenize(fvValue(*it), list_item_delimiter); for(string q_ind : queue_indexes) { sai_uint8_t q_val = (uint8_t)stoi(q_ind); - pfc_enable |= (uint8_t)(1 << q_val); + bitmask |= (uint8_t)(1 << q_val); + } + + if (fvField(*it) == pfc_enable_name) + { + pfc_enable = bitmask; + } + else + { + pfcwd_sw_enable = bitmask; } } } @@ -1876,6 +1887,9 @@ task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer, KeyOpFiel SWSS_LOG_INFO("Applied PFC bits 0x%x to port %s", pfc_enable, port_name.c_str()); } + + // Save pfd_wd bitmask unconditionally + gPortsOrch->setPortPfcWatchdogStatus(port.m_port_id, pfcwd_sw_enable); } SWSS_LOG_NOTICE("Applied QoS maps to ports"); @@ -1981,3 +1995,21 @@ sai_object_id_t QosOrch::resolveTunnelQosMap(std::string referencing_table_name, return SAI_NULL_OBJECT_ID; } } + +/** + * Function Description: + * @brief Remove the reference from tunnel object. Called after tunnel is removed + * + * Arguments: + * @param[in] referencing_table_name - The name of table that is referencing the QoS map + * @param[in] tunnle_name - The name of tunnel + * + * Return Values: + * @return no return + */ +void QosOrch::removeTunnelReference(std::string referencing_table_name, std::string tunnel_name) +{ + removeObject(m_qos_maps, referencing_table_name, tunnel_name); + SWSS_LOG_INFO("Freed QoS objects referenced by %s:%s", referencing_table_name.c_str(), tunnel_name.c_str()); +} + diff --git a/orchagent/qosorch.h b/orchagent/qosorch.h index d0429f119d..2b348cc030 100644 --- a/orchagent/qosorch.h +++ b/orchagent/qosorch.h @@ -14,6 +14,7 @@ const string dot1p_to_tc_field_name = "dot1p_to_tc_map"; const string pfc_to_pg_map_name = "pfc_to_pg_map"; const string pfc_to_queue_map_name = "pfc_to_queue_map"; const string pfc_enable_name = "pfc_enable"; +const string pfcwd_sw_enable_name = "pfcwd_sw_enable"; const string tc_to_pg_map_field_name = "tc_to_pg_map"; const string tc_to_queue_field_name = "tc_to_queue_map"; const string scheduler_field_name = "scheduler"; @@ -168,6 +169,7 @@ class QosOrch : public Orch static type_map m_qos_maps; sai_object_id_t resolveTunnelQosMap(std::string referencing_table_name, std::string tunnel_name, std::string map_type_name, KeyOpFieldsValuesTuple& tuple); + void removeTunnelReference(std::string referencing_table_name, std::string tunnel_name); private: void doTask() override; virtual void doTask(Consumer& consumer); diff --git a/orchagent/tunneldecaporch.cpp b/orchagent/tunneldecaporch.cpp index ed3820bde6..91744f3323 100644 --- a/orchagent/tunneldecaporch.cpp +++ b/orchagent/tunneldecaporch.cpp @@ -50,13 +50,14 @@ void TunnelDecapOrch::doTask(Consumer& consumer) string ecn_mode; string encap_ecn_mode; string ttl_mode; - sai_object_id_t dscp_to_dc_map_id = SAI_NULL_OBJECT_ID; + sai_object_id_t dscp_to_tc_map_id = SAI_NULL_OBJECT_ID; sai_object_id_t tc_to_pg_map_id = SAI_NULL_OBJECT_ID; // The tc_to_dscp_map_id and tc_to_queue_map_id are parsed here for muxorch to retrieve sai_object_id_t tc_to_dscp_map_id = SAI_NULL_OBJECT_ID; sai_object_id_t tc_to_queue_map_id = SAI_NULL_OBJECT_ID; bool valid = true; + task_process_status task_status = task_process_status::task_success; sai_object_id_t tunnel_id = SAI_NULL_OBJECT_ID; @@ -176,16 +177,28 @@ void TunnelDecapOrch::doTask(Consumer& consumer) } else if (fvField(i) == decap_dscp_to_tc_field_name) { - dscp_to_dc_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, decap_dscp_to_tc_field_name, t); - if (exists && dscp_to_dc_map_id != SAI_NULL_OBJECT_ID) + dscp_to_tc_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, decap_dscp_to_tc_field_name, t); + if (dscp_to_tc_map_id == SAI_NULL_OBJECT_ID) { - setTunnelAttribute(fvField(i), dscp_to_dc_map_id, tunnel_id); + SWSS_LOG_NOTICE("QoS map %s is not ready yet", decap_dscp_to_tc_field_name.c_str()); + task_status = task_process_status::task_need_retry; + break; + } + if (exists) + { + setTunnelAttribute(fvField(i), dscp_to_tc_map_id, tunnel_id); } } else if (fvField(i) == decap_tc_to_pg_field_name) { - tc_to_pg_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, decap_tc_to_pg_field_name, t); - if (exists && tc_to_pg_map_id != SAI_NULL_OBJECT_ID) + tc_to_pg_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, decap_tc_to_pg_field_name, t); + if (tc_to_pg_map_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_NOTICE("QoS map %s is not ready yet", decap_tc_to_pg_field_name.c_str()); + task_status = task_process_status::task_need_retry; + break; + } + if (exists) { setTunnelAttribute(fvField(i), tc_to_pg_map_id, tunnel_id); } @@ -193,6 +206,12 @@ void TunnelDecapOrch::doTask(Consumer& consumer) else if (fvField(i) == encap_tc_to_dscp_field_name) { tc_to_dscp_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, encap_tc_to_dscp_field_name, t); + if (tc_to_dscp_map_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_NOTICE("QoS map %s is not ready yet", encap_tc_to_dscp_field_name.c_str()); + task_status = task_process_status::task_need_retry; + break; + } if (exists) { // Record only @@ -202,6 +221,12 @@ void TunnelDecapOrch::doTask(Consumer& consumer) else if (fvField(i) == encap_tc_to_queue_field_name) { tc_to_queue_map_id = gQosOrch->resolveTunnelQosMap(table_name, key, encap_tc_to_queue_field_name, t); + if (tc_to_queue_map_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_NOTICE("QoS map %s is not ready yet", encap_tc_to_queue_field_name.c_str()); + task_status = task_process_status::task_need_retry; + break; + } if (exists) { // Record only @@ -210,12 +235,18 @@ void TunnelDecapOrch::doTask(Consumer& consumer) } } + if (task_status == task_process_status::task_need_retry) + { + ++it; + continue; + } + //create new tunnel if it doesn't exists already if (valid && !exists) { if (addDecapTunnel(key, tunnel_type, ip_addresses, p_src_ip, dscp_mode, ecn_mode, encap_ecn_mode, ttl_mode, - dscp_to_dc_map_id, tc_to_pg_map_id)) + dscp_to_tc_map_id, tc_to_pg_map_id)) { // Record only tunnelTable[key].encap_tc_to_dscp_map_id = tc_to_dscp_map_id; @@ -233,7 +264,7 @@ void TunnelDecapOrch::doTask(Consumer& consumer) { if (exists) { - removeDecapTunnel(key); + removeDecapTunnel(table_name, key); } else { @@ -717,12 +748,13 @@ bool TunnelDecapOrch::setIpAttribute(string key, IpAddresses new_ip_addresses, s * @brief remove decap tunnel * * Arguments: + * @param[in] table_name - name of the table in APP_DB * @param[in] key - key of the tunnel from APP_DB * * Return Values: * @return true on success and false if there's an error */ -bool TunnelDecapOrch::removeDecapTunnel(string key) +bool TunnelDecapOrch::removeDecapTunnel(string table_name, string key) { sai_status_t status; TunnelEntry *tunnel_info = &tunnelTable.find(key)->second; @@ -764,6 +796,7 @@ bool TunnelDecapOrch::removeDecapTunnel(string key) } tunnelTable.erase(key); + gQosOrch->removeTunnelReference(table_name, key); return true; } @@ -996,4 +1029,4 @@ bool TunnelDecapOrch::getQosMapId(const std::string &tunnelKey, const std::strin return false; } return true; -} \ No newline at end of file +} diff --git a/orchagent/tunneldecaporch.h b/orchagent/tunneldecaporch.h index 04d7928e37..18cf4f8856 100644 --- a/orchagent/tunneldecaporch.h +++ b/orchagent/tunneldecaporch.h @@ -78,7 +78,7 @@ class TunnelDecapOrch : public Orch bool addDecapTunnel(std::string key, std::string type, swss::IpAddresses dst_ip, swss::IpAddress* p_src_ip, std::string dscp, std::string ecn, std::string encap_ecn, std::string ttl, sai_object_id_t dscp_to_tc_map_id, sai_object_id_t tc_to_pg_map_id); - bool removeDecapTunnel(std::string key); + bool removeDecapTunnel(std::string table_name, std::string key); bool addDecapTunnelTermEntries(std::string tunnelKey, swss::IpAddress src_ip, swss::IpAddresses dst_ip, sai_object_id_t tunnel_id, TunnelTermType type); bool removeDecapTunnelTermEntry(sai_object_id_t tunnel_term_id, std::string ip); diff --git a/orchagent/vnetorch.cpp b/orchagent/vnetorch.cpp index 5f51de167d..45ba120ee6 100644 --- a/orchagent/vnetorch.cpp +++ b/orchagent/vnetorch.cpp @@ -1539,6 +1539,8 @@ void VNetRouteOrch::createBfdSession(const string& vnet, const NextHopKey& endpo FieldValueTuple fvTuple("local_addr", src_ip.to_string()); data.push_back(fvTuple); + data.emplace_back("multihop", "true"); + bfd_session_producer_.set(key, data); bfd_sessions_[monitor_addr].bfd_state = SAI_BFD_SESSION_STATE_DOWN; diff --git a/portsyncd/Makefile.am b/portsyncd/Makefile.am index cedc779ae8..cc4987f579 100644 --- a/portsyncd/Makefile.am +++ b/portsyncd/Makefile.am @@ -10,10 +10,15 @@ endif portsyncd_SOURCES = $(top_srcdir)/lib/gearboxutils.cpp portsyncd.cpp linksync.cpp portsyncd_helper.cpp $(top_srcdir)/cfgmgr/shellcmd.h -portsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -portsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -portsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon +portsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +portsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +portsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lswsscommon if GCOV_ENABLED portsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +portsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/portsyncd/linksync.cpp b/portsyncd/linksync.cpp index 4224e464ce..08c28eb837 100644 --- a/portsyncd/linksync.cpp +++ b/portsyncd/linksync.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include "logger.h" #include "netmsg.h" @@ -38,10 +38,10 @@ LinkSync::LinkSync(DBConnector *appl_db, DBConnector *state_db) : m_statePortTable(state_db, STATE_PORT_TABLE_NAME), m_stateMgmtPortTable(state_db, STATE_MGMT_PORT_TABLE_NAME) { - struct if_nameindex *if_ni, *idx_p; - if_ni = if_nameindex(); + std::shared_ptr if_ni(if_nameindex(), if_freenameindex); + struct if_nameindex *idx_p; - for (idx_p = if_ni; + for (idx_p = if_ni.get(); idx_p != NULL && idx_p->if_index != 0 && idx_p->if_name != NULL; idx_p++) { @@ -112,7 +112,7 @@ LinkSync::LinkSync(DBConnector *appl_db, DBConnector *state_db) : } } - for (idx_p = if_ni; + for (idx_p = if_ni.get(); idx_p != NULL && idx_p->if_index != 0 && idx_p->if_name != NULL; idx_p++) { diff --git a/swssconfig/Makefile.am b/swssconfig/Makefile.am index 590e7d9f56..3cfc0b9629 100644 --- a/swssconfig/Makefile.am +++ b/swssconfig/Makefile.am @@ -10,17 +10,23 @@ endif swssconfig_SOURCES = swssconfig.cpp -swssconfig_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -swssconfig_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -swssconfig_LDADD = -lswsscommon +swssconfig_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +swssconfig_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +swssconfig_LDADD = $(LDFLAGS_ASAN) -lswsscommon swssplayer_SOURCES = swssplayer.cpp -swssplayer_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -swssplayer_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -swssplayer_LDADD = -lswsscommon +swssplayer_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +swssplayer_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +swssplayer_LDADD = $(LDFLAGS_ASAN) -lswsscommon if GCOV_ENABLED swssconfig_LDADD += -lgcovpreload swssplayer_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +swssconfig_SOURCES += $(top_srcdir)/lib/asan.cpp +swssplayer_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/teamsyncd/Makefile.am b/teamsyncd/Makefile.am index 2939a52f2a..a13573bf25 100644 --- a/teamsyncd/Makefile.am +++ b/teamsyncd/Makefile.am @@ -10,10 +10,15 @@ endif teamsyncd_SOURCES = teamsyncd.cpp teamsync.cpp -teamsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -teamsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -teamsyncd_LDADD = -lnl-3 -lnl-route-3 -lhiredis -lswsscommon -lteam +teamsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +teamsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +teamsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lhiredis -lswsscommon -lteam if GCOV_ENABLED teamsyncd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +teamsyncd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif + diff --git a/teamsyncd/teamsyncd.cpp b/teamsyncd/teamsyncd.cpp index c5190f46b1..95890be406 100644 --- a/teamsyncd/teamsyncd.cpp +++ b/teamsyncd/teamsyncd.cpp @@ -11,9 +11,16 @@ using namespace std; using namespace swss; bool received_sigterm = false; +static struct sigaction old_sigaction; void sig_handler(int signo) { + SWSS_LOG_ENTER(); + + if (old_sigaction.sa_handler != SIG_IGN && old_sigaction.sa_handler != SIG_DFL) { + old_sigaction.sa_handler(signo); + } + received_sigterm = true; return; } @@ -30,7 +37,13 @@ int main(int argc, char **argv) NetDispatcher::getInstance().registerMessageHandler(RTM_DELLINK, &sync); /* Register the signal handler for SIGTERM */ - signal(SIGTERM, sig_handler); + struct sigaction sigact = {}; + sigact.sa_handler = sig_handler; + if (sigaction(SIGTERM, &sigact, &old_sigaction)) + { + SWSS_LOG_ERROR("failed to setup SIGTERM action handler"); + exit(EXIT_FAILURE); + } try { diff --git a/tests/conftest.py b/tests/conftest.py index 39706295af..e2e3bbcf77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1196,6 +1196,94 @@ def warm_restart_swss(self, enable): fvs = swsscommon.FieldValuePairs([("enable",enable)]) tbl.set("swss", fvs) + # nat + def nat_mode_set(self, value): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "NAT_GLOBAL") + fvs = swsscommon.FieldValuePairs([("admin_mode", value)]) + tbl.set("Values", fvs) + time.sleep(1) + + def nat_timeout_set(self, value): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "NAT_GLOBAL") + fvs = swsscommon.FieldValuePairs([("nat_timeout", value)]) + tbl.set("Values", fvs) + time.sleep(1) + + def nat_udp_timeout_set(self, value): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "NAT_GLOBAL") + fvs = swsscommon.FieldValuePairs([("nat_udp_timeout", value)]) + tbl.set("Values", fvs) + time.sleep(1) + + def nat_tcp_timeout_set(self, value): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "NAT_GLOBAL") + fvs = swsscommon.FieldValuePairs([("nat_tcp_timeout", value)]) + tbl.set("Values", fvs) + time.sleep(1) + + def add_nat_basic_entry(self, external, internal): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAT") + fvs = swsscommon.FieldValuePairs([("local_ip", internal)]) + tbl.set(external, fvs) + time.sleep(1) + + def del_nat_basic_entry(self, external): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAT") + tbl._del(external) + time.sleep(1) + + def add_nat_udp_entry(self, external, extport, internal, intport): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAPT") + fvs = swsscommon.FieldValuePairs([("local_ip", internal), ("local_port", intport)]) + tbl.set(external + "|UDP|" + extport, fvs) + time.sleep(1) + + def del_nat_udp_entry(self, external, extport): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAPT") + tbl._del(external + "|UDP|" + extport) + time.sleep(1) + + def add_twice_nat_basic_entry(self, external, internal, nat_type, twice_nat_id): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAT") + fvs = swsscommon.FieldValuePairs([("local_ip", internal), ("nat_type", nat_type), ("twice_nat_id", twice_nat_id)]) + tbl.set(external, fvs) + time.sleep(1) + + def del_twice_nat_basic_entry(self, external): + self.del_nat_basic_entry(external) + + def add_twice_nat_udp_entry(self, external, extport, internal, intport, nat_type, twice_nat_id): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + tbl = swsscommon.Table(cdb, "STATIC_NAPT") + fvs = swsscommon.FieldValuePairs([("local_ip", internal), ("local_port", intport), ("nat_type", nat_type), ("twice_nat_id", twice_nat_id)]) + tbl.set(external + "|UDP|" + extport, fvs) + time.sleep(1) + + def del_twice_nat_udp_entry(self, external, extport): + self.del_nat_udp_entry(external, extport) + + def set_nat_zone(self, interface, nat_zone): + cdb = swsscommon.DBConnector(4, self.redis_sock, 0) + if interface.startswith("PortChannel"): + tbl_name = "PORTCHANNEL_INTERFACE" + elif interface.startswith("Vlan"): + tbl_name = "VLAN_INTERFACE" + else: + tbl_name = "INTERFACE" + tbl = swsscommon.Table(cdb, tbl_name) + fvs = swsscommon.FieldValuePairs([("nat_zone", nat_zone)]) + tbl.set(interface, fvs) + time.sleep(1) + # deps: acl, crm, fdb def setReadOnlyAttr(self, obj, attr, val): db = swsscommon.DBConnector(swsscommon.ASIC_DB, self.redis_sock, 0) diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index c7a7a83592..a32c32c149 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -4,9 +4,9 @@ P4_ORCH_DIR = $(top_srcdir)/orchagent/p4orch CFLAGS_SAI = -I /usr/include/sai -TESTS = tests tests_portsyncd +TESTS = tests tests_intfmgrd tests_portsyncd -noinst_PROGRAMS = tests tests_portsyncd +noinst_PROGRAMS = tests tests_intfmgrd tests_portsyncd LDADD_SAI = -lsaimeta -lsaimetadata -lsaivs -lsairedis @@ -28,6 +28,8 @@ tests_SOURCES = aclorch_ut.cpp \ routeorch_ut.cpp \ qosorch_ut.cpp \ bufferorch_ut.cpp \ + fdborch/flush_syncd_notif_ut.cpp \ + copporch_ut.cpp \ saispy_ut.cpp \ consumer_ut.cpp \ ut_saihelper.cpp \ @@ -41,6 +43,7 @@ tests_SOURCES = aclorch_ut.cpp \ bulker_ut.cpp \ fake_response_publisher.cpp \ swssnet_ut.cpp \ + flowcounterrouteorch_ut.cpp \ $(top_srcdir)/lib/gearboxutils.cpp \ $(top_srcdir)/lib/subintf.cpp \ $(top_srcdir)/orchagent/orchdaemon.cpp \ @@ -129,8 +132,27 @@ tests_portsyncd_SOURCES = portsyncd/portsyncd_ut.cpp \ mock_redisreply.cpp tests_portsyncd_INCLUDES = -I $(top_srcdir)/portsyncd -I $(top_srcdir)/cfgmgr -tests_portsyncd_CXXFLAGS = -Wl,-wrap,if_nameindex +tests_portsyncd_CXXFLAGS = -Wl,-wrap,if_nameindex -Wl,-wrap,if_freenameindex tests_portsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) tests_portsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(tests_portsyncd_INCLUDES) tests_portsyncd_LDADD = $(LDADD_GTEST) -lnl-genl-3 -lhiredis -lhiredis \ -lswsscommon -lswsscommon -lgtest -lgtest_main -lnl-3 -lnl-route-3 -lpthread + +## intfmgrd unit tests + +tests_intfmgrd_SOURCES = intfmgrd/add_ipv6_prefix_ut.cpp \ + $(top_srcdir)/cfgmgr/intfmgr.cpp \ + $(top_srcdir)/orchagent/orch.cpp \ + $(top_srcdir)/orchagent/request_parser.cpp \ + $(top_srcdir)/lib/subintf.cpp \ + mock_orchagent_main.cpp \ + mock_dbconnector.cpp \ + mock_table.cpp \ + mock_hiredis.cpp \ + fake_response_publisher.cpp \ + mock_redisreply.cpp + +tests_intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) +tests_intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) -I $(top_srcdir)/cfgmgr -I $(top_srcdir)/orchagent/ +tests_intfmgrd_LDADD = $(LDADD_GTEST) $(LDADD_SAI) -lnl-genl-3 -lhiredis -lhiredis \ + -lswsscommon -lswsscommon -lgtest -lgtest_main -lzmq -lnl-3 -lnl-route-3 -lpthread diff --git a/tests/mock_tests/copporch_ut.cpp b/tests/mock_tests/copporch_ut.cpp new file mode 100644 index 0000000000..36ba71bc67 --- /dev/null +++ b/tests/mock_tests/copporch_ut.cpp @@ -0,0 +1,501 @@ +#include +#include +#include +#include +#include + +#include "ut_helper.h" +#include "mock_orchagent_main.h" + +using namespace swss; + +namespace copporch_test +{ + class MockCoppOrch final + { + public: + MockCoppOrch() + { + this->appDb = std::make_shared("APPL_DB", 0); + this->coppOrch = std::make_shared(this->appDb.get(), APP_COPP_TABLE_NAME); + } + ~MockCoppOrch() = default; + + void doCoppTableTask(const std::deque &entries) + { + // ConsumerStateTable is used for APP DB + auto consumer = std::unique_ptr(new Consumer( + new ConsumerStateTable(this->appDb.get(), APP_COPP_TABLE_NAME, 1, 1), + this->coppOrch.get(), APP_COPP_TABLE_NAME + )); + + consumer->addToSync(entries); + static_cast(this->coppOrch.get())->doTask(*consumer); + } + + CoppOrch& get() + { + return *coppOrch; + } + + private: + std::shared_ptr coppOrch; + std::shared_ptr appDb; + }; + + class CoppOrchTest : public ::testing::Test + { + public: + CoppOrchTest() + { + this->initDb(); + } + virtual ~CoppOrchTest() = default; + + void SetUp() override + { + this->initSaiApi(); + this->initSwitch(); + this->initOrch(); + this->initPorts(); + } + + void TearDown() override + { + this->deinitOrch(); + this->deinitSwitch(); + this->deinitSaiApi(); + } + + private: + void initSaiApi() + { + std::map profileMap = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + auto status = ut_helper::initSaiApi(profileMap); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void deinitSaiApi() + { + auto status = ut_helper::uninitSaiApi(); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void initSwitch() + { + sai_status_t status; + sai_attribute_t attr; + + // Create switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + // Get switch default virtual router ID + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + } + + void deinitSwitch() + { + // Remove switch + auto status = sai_switch_api->remove_switch(gSwitchId); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gSwitchId = SAI_NULL_OBJECT_ID; + gVirtualRouterId = SAI_NULL_OBJECT_ID; + } + + void initOrch() + { + // + // SwitchOrch + // + + TableConnector switchCapTableStateDb(this->stateDb.get(), "SWITCH_CAPABILITY"); + TableConnector asicSensorsTableCfgDb(this->configDb.get(), CFG_ASIC_SENSORS_TABLE_NAME); + TableConnector switchTableAppDb(this->appDb.get(), APP_SWITCH_TABLE_NAME); + + std::vector switchTableList = { + asicSensorsTableCfgDb, + switchTableAppDb + }; + + gSwitchOrch = new SwitchOrch(this->appDb.get(), switchTableList, switchCapTableStateDb); + gDirectory.set(gSwitchOrch); + resourcesList.push_back(gSwitchOrch); + + // + // PortsOrch + // + + const int portsorchBasePri = 40; + + std::vector portTableList = { + { APP_PORT_TABLE_NAME, portsorchBasePri + 5 }, + { APP_VLAN_TABLE_NAME, portsorchBasePri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorchBasePri }, + { APP_LAG_TABLE_NAME, portsorchBasePri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorchBasePri } + }; + + gPortsOrch = new PortsOrch(this->appDb.get(), this->stateDb.get(), portTableList, this->chassisAppDb.get()); + gDirectory.set(gPortsOrch); + resourcesList.push_back(gPortsOrch); + + // + // QosOrch + // + + std::vector qosTableList = { + CFG_TC_TO_QUEUE_MAP_TABLE_NAME, + CFG_SCHEDULER_TABLE_NAME, + CFG_DSCP_TO_TC_MAP_TABLE_NAME, + CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, + CFG_DOT1P_TO_TC_MAP_TABLE_NAME, + CFG_QUEUE_TABLE_NAME, + CFG_PORT_QOS_MAP_TABLE_NAME, + CFG_WRED_PROFILE_TABLE_NAME, + CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, + CFG_DSCP_TO_FC_MAP_TABLE_NAME, + CFG_EXP_TO_FC_MAP_TABLE_NAME + }; + gQosOrch = new QosOrch(this->configDb.get(), qosTableList); + gDirectory.set(gQosOrch); + resourcesList.push_back(gQosOrch); + + // + // BufferOrch + // + + std::vector bufferTableList = { + APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME + }; + gBufferOrch = new BufferOrch(this->appDb.get(), this->configDb.get(), this->stateDb.get(), bufferTableList); + gDirectory.set(gBufferOrch); + resourcesList.push_back(gBufferOrch); + + // + // PolicerOrch + // + + auto policerOrch = new PolicerOrch(this->configDb.get(), CFG_POLICER_TABLE_NAME); + gDirectory.set(policerOrch); + resourcesList.push_back(policerOrch); + + // + // FlexCounterOrch + // + + std::vector flexCounterTableList = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + + auto flexCounterOrch = new FlexCounterOrch(this->configDb.get(), flexCounterTableList); + gDirectory.set(flexCounterOrch); + resourcesList.push_back(flexCounterOrch); + } + + void deinitOrch() + { + std::reverse(this->resourcesList.begin(), this->resourcesList.end()); + for (auto &it : this->resourcesList) + { + delete it; + } + + gSwitchOrch = nullptr; + gPortsOrch = nullptr; + gQosOrch = nullptr; + gBufferOrch = nullptr; + + Portal::DirectoryInternal::clear(gDirectory); + EXPECT_TRUE(Portal::DirectoryInternal::empty(gDirectory)); + } + + void initPorts() + { + auto portTable = Table(this->appDb.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate port table with SAI ports + for (const auto &cit : ports) + { + portTable.set(cit.first, cit.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + // Set PortInitDone + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + } + + void initDb() + { + this->appDb = std::make_shared("APPL_DB", 0); + this->configDb = std::make_shared("CONFIG_DB", 0); + this->stateDb = std::make_shared("STATE_DB", 0); + this->chassisAppDb = std::make_shared("CHASSIS_APP_DB", 0); + } + + std::shared_ptr appDb; + std::shared_ptr configDb; + std::shared_ptr stateDb; + std::shared_ptr chassisAppDb; + + std::vector resourcesList; + }; + + TEST_F(CoppOrchTest, TrapGroup_AddRemove) + { + const std::string trapGroupName = "queue4_group1"; + + MockCoppOrch coppOrch; + + // Create CoPP Trap Group + { + auto tableKofvt = std::deque( + { + { + trapGroupName, + SET_COMMAND, + { + { copp_trap_action_field, "trap" }, + { copp_trap_priority_field, "4" }, + { copp_queue_field, "4" } + } + } + } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit != trapGroupMap.end()); + } + + // Delete CoPP Trap Group + { + auto tableKofvt = std::deque( + { { trapGroupName, DEL_COMMAND, { } } } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit == trapGroupMap.end()); + } + } + + TEST_F(CoppOrchTest, TrapGroupWithPolicer_AddRemove) + { + const std::string trapGroupName = "queue4_group2"; + + MockCoppOrch coppOrch; + + // Create CoPP Trap Group + { + auto tableKofvt = std::deque( + { + { + trapGroupName, + SET_COMMAND, + { + { copp_trap_action_field, "copy" }, + { copp_trap_priority_field, "4" }, + { copp_queue_field, "4" }, + { copp_policer_meter_type_field, "packets" }, + { copp_policer_mode_field, "sr_tcm" }, + { copp_policer_cir_field, "600" }, + { copp_policer_cbs_field, "600" }, + { copp_policer_action_red_field, "drop" } + } + } + } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit1 = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit1 != trapGroupMap.end()); + + const auto &trapGroupPolicerMap = Portal::CoppOrchInternal::getTrapGroupPolicerMap(coppOrch.get()); + const auto &trapGroupOid = cit1->second; + const auto &cit2 = trapGroupPolicerMap.find(trapGroupOid); + EXPECT_TRUE(cit2 != trapGroupPolicerMap.end()); + } + + // Delete CoPP Trap Group + { + auto tableKofvt = std::deque( + { { trapGroupName, DEL_COMMAND, { } } } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit == trapGroupMap.end()); + + const auto &trapGroupPolicerMap = Portal::CoppOrchInternal::getTrapGroupPolicerMap(coppOrch.get()); + EXPECT_TRUE(trapGroupPolicerMap.empty()); + } + } + + TEST_F(CoppOrchTest, Trap_AddRemove) + { + const std::string trapGroupName = "queue4_group1"; + const std::string trapNameList = "bgp,bgpv6"; + const std::set trapIDSet = { + SAI_HOSTIF_TRAP_TYPE_BGP, + SAI_HOSTIF_TRAP_TYPE_BGPV6 + }; + + MockCoppOrch coppOrch; + + // Create CoPP Trap + { + auto tableKofvt = std::deque( + { + { + trapGroupName, + SET_COMMAND, + { + { copp_trap_action_field, "trap" }, + { copp_trap_priority_field, "4" }, + { copp_queue_field, "4" }, + { copp_trap_id_list, trapNameList } + } + } + } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit != trapGroupMap.end()); + + const auto &tgOid = cit->second; + const auto &tidList = Portal::CoppOrchInternal::getTrapIdsFromTrapGroup(coppOrch.get(), tgOid); + const auto &tidSet = std::set(tidList.begin(), tidList.end()); + EXPECT_TRUE(trapIDSet == tidSet); + } + + // Delete CoPP Trap + { + auto tableKofvt = std::deque( + { { trapGroupName, DEL_COMMAND, { } } } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit1 = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit1 == trapGroupMap.end()); + + const auto &trapGroupIdMap = Portal::CoppOrchInternal::getTrapGroupIdMap(coppOrch.get()); + const auto &cit2 = trapGroupIdMap.find(SAI_HOSTIF_TRAP_TYPE_TTL_ERROR); + EXPECT_TRUE(cit2 != trapGroupIdMap.end()); + ASSERT_EQ(trapGroupIdMap.size(), 1); + } + } + + TEST_F(CoppOrchTest, TrapWithPolicer_AddRemove) + { + const std::string trapGroupName = "queue4_group2"; + const std::string trapNameList = "arp_req,arp_resp,neigh_discovery"; + const std::set trapIDSet = { + SAI_HOSTIF_TRAP_TYPE_ARP_REQUEST, + SAI_HOSTIF_TRAP_TYPE_ARP_RESPONSE, + SAI_HOSTIF_TRAP_TYPE_IPV6_NEIGHBOR_DISCOVERY + }; + + MockCoppOrch coppOrch; + + // Create CoPP Trap + { + auto tableKofvt = std::deque( + { + { + trapGroupName, + SET_COMMAND, + { + { copp_trap_action_field, "copy" }, + { copp_trap_priority_field, "4" }, + { copp_queue_field, "4" }, + { copp_policer_meter_type_field, "packets" }, + { copp_policer_mode_field, "sr_tcm" }, + { copp_policer_cir_field, "600" }, + { copp_policer_cbs_field, "600" }, + { copp_policer_action_red_field, "drop" }, + { copp_trap_id_list, trapNameList } + } + } + } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit1 = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit1 != trapGroupMap.end()); + + const auto &trapGroupPolicerMap = Portal::CoppOrchInternal::getTrapGroupPolicerMap(coppOrch.get()); + const auto &trapGroupOid = cit1->second; + const auto &cit2 = trapGroupPolicerMap.find(trapGroupOid); + EXPECT_TRUE(cit2 != trapGroupPolicerMap.end()); + + const auto &tidList = Portal::CoppOrchInternal::getTrapIdsFromTrapGroup(coppOrch.get(), trapGroupOid); + const auto &tidSet = std::set(tidList.begin(), tidList.end()); + EXPECT_TRUE(trapIDSet == tidSet); + } + + // Delete CoPP Trap + { + auto tableKofvt = std::deque( + { { trapGroupName, DEL_COMMAND, { } } } + ); + coppOrch.doCoppTableTask(tableKofvt); + + const auto &trapGroupMap = coppOrch.get().getTrapGroupMap(); + const auto &cit1 = trapGroupMap.find(trapGroupName); + EXPECT_TRUE(cit1 == trapGroupMap.end()); + + const auto &trapGroupPolicerMap = Portal::CoppOrchInternal::getTrapGroupPolicerMap(coppOrch.get()); + EXPECT_TRUE(trapGroupPolicerMap.empty()); + + const auto &trapGroupIdMap = Portal::CoppOrchInternal::getTrapGroupIdMap(coppOrch.get()); + const auto &cit2 = trapGroupIdMap.find(SAI_HOSTIF_TRAP_TYPE_TTL_ERROR); + EXPECT_TRUE(cit2 != trapGroupIdMap.end()); + ASSERT_EQ(trapGroupIdMap.size(), 1); + } + } +} diff --git a/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp b/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp new file mode 100644 index 0000000000..7bf22373c1 --- /dev/null +++ b/tests/mock_tests/fdborch/flush_syncd_notif_ut.cpp @@ -0,0 +1,424 @@ +#include "../ut_helper.h" +#include "../mock_orchagent_main.h" +#include "../mock_table.h" +#include "port.h" +#define private public // Need to modify internal cache +#include "portsorch.h" +#include "fdborch.h" +#include "crmorch.h" +#undef private + +#define ETH0 "Ethernet0" +#define VLAN40 "Vlan40" + +extern redisReply *mockReply; +extern CrmOrch* gCrmOrch; + +/* +Test Fixture +*/ +namespace fdb_syncd_flush_test +{ + struct FdbOrchTest : public ::testing::Test + { + std::shared_ptr m_config_db; + std::shared_ptr m_app_db; + std::shared_ptr m_state_db; + std::shared_ptr m_asic_db; + std::shared_ptr m_chassis_app_db; + std::shared_ptr m_portsOrch; + std::shared_ptr m_fdborch; + + virtual void SetUp() override + { + + testing_db::reset(); + + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); + + /* Create Switch */ + sai_attribute_t attr; + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + auto status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + m_config_db = std::make_shared("CONFIG_DB", 0); + m_app_db = std::make_shared("APPL_DB", 0); + m_state_db = make_shared("STATE_DB", 0); + m_asic_db = std::make_shared("ASIC_DB", 0); + + // Construct dependencies + // 1) Portsorch + const int portsorch_base_pri = 40; + + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + m_portsOrch = std::make_shared(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + + // 2) Crmorch + ASSERT_EQ(gCrmOrch, nullptr); + gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); + + // Construct fdborch + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, FdbOrch::fdborch_pri} + }; + + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); + + m_fdborch = std::make_shared(m_app_db.get(), + app_fdb_tables, + stateDbFdb, + stateMclagDbFdb, + m_portsOrch.get()); + } + + virtual void TearDown() override { + delete gCrmOrch; + gCrmOrch = nullptr; + + ut_helper::uninitSaiApi(); + } + }; + + /* Helper Methods */ + void setUpVlan(PortsOrch* m_portsOrch){ + /* Updates portsOrch internal cache for Vlan40 */ + std::string alias = VLAN40; + sai_object_id_t oid = 0x26000000000796; + + Port vlan(alias, Port::VLAN); + vlan.m_vlan_info.vlan_oid = oid; + vlan.m_vlan_info.vlan_id = 40; + vlan.m_members = set(); + + m_portsOrch->m_portList[alias] = vlan; + m_portsOrch->m_port_ref_count[alias] = 0; + m_portsOrch->saiOidToAlias[oid] = alias; + } + + void setUpPort(PortsOrch* m_portsOrch){ + /* Updates portsOrch internal cache for Ethernet0 */ + std::string alias = ETH0; + sai_object_id_t oid = 0x10000000004a4; + + Port port(alias, Port::PHY); + port.m_index = 1; + port.m_port_id = oid; + port.m_hif_id = 0xd00000000056e; + + m_portsOrch->m_portList[alias] = port; + m_portsOrch->saiOidToAlias[oid] = alias; + } + + void setUpVlanMember(PortsOrch* m_portsOrch){ + /* Updates portsOrch internal cache for adding Ethernet0 into Vlan40 */ + sai_object_id_t bridge_port_id = 0x3a000000002c33; + + /* Add Bridge Port */ + m_portsOrch->m_portList[ETH0].m_bridge_port_id = bridge_port_id; + m_portsOrch->saiOidToAlias[bridge_port_id] = ETH0; + m_portsOrch->m_portList[VLAN40].m_members.insert(ETH0); + } + + void triggerUpdate(FdbOrch* m_fdborch, + sai_fdb_event_t type, + vector mac_addr, + sai_object_id_t bridge_port_id, + sai_object_id_t bv_id){ + sai_fdb_entry_t entry; + for (int i = 0; i < (int)mac_addr.size(); i++){ + *(entry.mac_address+i) = mac_addr[i]; + } + entry.bv_id = bv_id; + m_fdborch->update(type, &entry, bridge_port_id); + } +} + +namespace fdb_syncd_flush_test +{ + /* Test Consolidated Flush Per Vlan and Per Port */ + TEST_F(FdbOrchTest, ConsolidatedFlushVlanandPort) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + /* Event 2: Generate a FDB Flush per port and per vlan */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } + + /* Test Consolidated Flush All */ + TEST_F(FdbOrchTest, ConsolidatedFlushAll) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + /* Event2: Send a Consolidated Flush response from syncd */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, SAI_NULL_OBJECT_ID, + SAI_NULL_OBJECT_ID); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } + + /* Test Consolidated Flush per VLAN BV_ID */ + TEST_F(FdbOrchTest, ConsolidatedFlushVlan) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + /* Event2: Send a Consolidated Flush response from syncd for vlan */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, SAI_NULL_OBJECT_ID, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } + + /* Test Consolidated Flush per bridge port id */ + TEST_F(FdbOrchTest, ConsolidatedFlushPort) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + /* Event2: Send a Consolidated Flush response from syncd for a port */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + SAI_NULL_OBJECT_ID); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } + + //* Test Consolidated Flush Per Vlan and Per Port, but the bridge_port_id from the internal cache is already deleted */ + TEST_F(FdbOrchTest, ConsolidatedFlushVlanandPortBridgeportDeleted) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + auto bridge_port_oid = m_portsOrch->m_portList[ETH0].m_bridge_port_id; + + /* Delete the bridge_port_oid in the internal OA cache */ + m_portsOrch->m_portList[ETH0].m_bridge_port_id = SAI_NULL_OBJECT_ID; + m_portsOrch->saiOidToAlias.erase(bridge_port_oid); + + /* Event 2: Generate a FDB Flush per port and per vlan */ + vector flush_mac_addr = {0, 0, 0, 0, 0, 0}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, bridge_port_oid, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + /* make sure fdb_counter for Vlan is decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } + + /* Test Flush Per Vlan and Per Port */ + TEST_F(FdbOrchTest, NonConsolidatedFlushVlanandPort) + { + ASSERT_NE(m_portsOrch, nullptr); + setUpVlan(m_portsOrch.get()); + setUpPort(m_portsOrch.get()); + ASSERT_NE(m_portsOrch->m_portList.find(VLAN40), m_portsOrch->m_portList.end()); + ASSERT_NE(m_portsOrch->m_portList.find(ETH0), m_portsOrch->m_portList.end()); + setUpVlanMember(m_portsOrch.get()); + + /* Event 1: Learn a dynamic FDB Entry */ + // 7c:fe:90:12:22:ec + vector mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_LEARNED, mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + string port; + string entry_type; + + /* Make sure fdb_count is incremented as expected */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 1); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 1); + + /* Make sure state db is updated as expected */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), true); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), true); + + ASSERT_EQ(port, "Ethernet0"); + ASSERT_EQ(entry_type, "dynamic"); + + /* Event 2: Generate a non-consilidated FDB Flush per port and per vlan */ + vector flush_mac_addr = {124, 254, 144, 18, 34, 236}; + triggerUpdate(m_fdborch.get(), SAI_FDB_EVENT_FLUSHED, flush_mac_addr, m_portsOrch->m_portList[ETH0].m_bridge_port_id, + m_portsOrch->m_portList[VLAN40].m_vlan_info.vlan_oid); + + /* make sure fdb_counters are decremented */ + ASSERT_EQ(m_portsOrch->m_portList[VLAN40].m_fdb_count, 0); + ASSERT_EQ(m_portsOrch->m_portList[ETH0].m_fdb_count, 0); + + /* Make sure state db is cleared */ + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "port", port), false); + ASSERT_EQ(m_fdborch->m_fdbStateTable.hget("Vlan40:7c:fe:90:12:22:ec", "type", entry_type), false); + } +} diff --git a/tests/mock_tests/flowcounterrouteorch_ut.cpp b/tests/mock_tests/flowcounterrouteorch_ut.cpp new file mode 100644 index 0000000000..25ed95cb1e --- /dev/null +++ b/tests/mock_tests/flowcounterrouteorch_ut.cpp @@ -0,0 +1,361 @@ +#define private public +#include "directory.h" +#undef private +#define protected public +#include "orch.h" +#undef protected +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_table.h" + +extern string gMySwitchType; + +namespace flowcounterrouteorch_test +{ + using namespace std; + shared_ptr m_app_db; + shared_ptr m_config_db; + shared_ptr m_state_db; + shared_ptr m_chassis_app_db; + + int num_created_counter; + sai_counter_api_t ut_sai_counter_api; + sai_counter_api_t *pold_sai_counter_api; + sai_create_counter_fn old_create_counter; + sai_remove_counter_fn old_remove_counter; + + sai_status_t _ut_stub_create_counter( + _Out_ sai_object_id_t *counter_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) + { + num_created_counter ++; + return old_create_counter(counter_id, switch_id, attr_count, attr_list); + } + + sai_status_t _ut_stub_remove_counter(_In_ sai_object_id_t counter_id) + { + num_created_counter --; + return old_remove_counter(counter_id); + } + + struct FlowcounterRouteOrchTest : public ::testing::Test + { + FlowcounterRouteOrchTest() + { + return; + } + + void SetUp() override + { + ASSERT_EQ(sai_route_api, nullptr); + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); + + old_create_counter = sai_counter_api->create_counter; + old_remove_counter = sai_counter_api->remove_counter; + + pold_sai_counter_api = sai_counter_api; + ut_sai_counter_api = *sai_counter_api; + sai_counter_api = &ut_sai_counter_api; + + // Mock sai API + sai_counter_api->create_counter = _ut_stub_create_counter; + sai_counter_api->remove_counter = _ut_stub_remove_counter; + + // Init switch and create dependencies + m_app_db = make_shared("APPL_DB", 0); + m_config_db = make_shared("CONFIG_DB", 0); + m_state_db = make_shared("STATE_DB", 0); + if(gMySwitchType == "voq") + m_chassis_app_db = make_shared("CHASSIS_APP_DB", 0); + + sai_attribute_t attr; + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + auto status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + // Get the default virtual router ID + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + + + ASSERT_EQ(gCrmOrch, nullptr); + gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); + + TableConnector stateDbSwitchTable(m_state_db.get(), "SWITCH_CAPABILITY"); + TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); + TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); + + vector switch_tables = { + conf_asic_sensors, + app_switch_table + }; + + ASSERT_EQ(gSwitchOrch, nullptr); + gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); + + // Create dependencies ... + TableConnector stateDbBfdSessionTable(m_state_db.get(), STATE_BFD_SESSION_TABLE_NAME); + gBfdOrch = new BfdOrch(m_app_db.get(), APP_BFD_SESSION_TABLE_NAME, stateDbBfdSessionTable); + + const int portsorch_base_pri = 40; + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + auto* flexCounterOrch = new FlexCounterOrch(m_config_db.get(), flex_counter_tables); + gDirectory.set(flexCounterOrch); + + ASSERT_EQ(gPortsOrch, nullptr); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + + vector vnet_tables = { + APP_VNET_RT_TABLE_NAME, + APP_VNET_RT_TUNNEL_TABLE_NAME + }; + + vector cfg_vnet_tables = { + CFG_VNET_RT_TABLE_NAME, + CFG_VNET_RT_TUNNEL_TABLE_NAME + }; + + auto* vnet_orch = new VNetOrch(m_app_db.get(), APP_VNET_TABLE_NAME); + gDirectory.set(vnet_orch); + auto* cfg_vnet_rt_orch = new VNetCfgRouteOrch(m_config_db.get(), m_app_db.get(), cfg_vnet_tables); + gDirectory.set(cfg_vnet_rt_orch); + auto* vnet_rt_orch = new VNetRouteOrch(m_app_db.get(), vnet_tables, vnet_orch); + gDirectory.set(vnet_rt_orch); + ASSERT_EQ(gVrfOrch, nullptr); + gVrfOrch = new VRFOrch(m_app_db.get(), APP_VRF_TABLE_NAME, m_state_db.get(), STATE_VRF_OBJECT_TABLE_NAME); + gDirectory.set(gVrfOrch); + + ASSERT_EQ(gIntfsOrch, nullptr); + gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch, m_chassis_app_db.get()); + + const int fdborch_pri = 20; + + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} + }; + + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); + ASSERT_EQ(gFdbOrch, nullptr); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); + + ASSERT_EQ(gNeighOrch, nullptr); + gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch, m_chassis_app_db.get()); + + auto* tunnel_decap_orch = new TunnelDecapOrch(m_app_db.get(), APP_TUNNEL_DECAP_TABLE_NAME); + vector mux_tables = { + CFG_MUX_CABLE_TABLE_NAME, + CFG_PEER_SWITCH_TABLE_NAME + }; + auto* mux_orch = new MuxOrch(m_config_db.get(), mux_tables, tunnel_decap_orch, gNeighOrch, gFdbOrch); + gDirectory.set(mux_orch); + + ASSERT_EQ(gFgNhgOrch, nullptr); + const int fgnhgorch_pri = 15; + + vector fgnhg_tables = { + { CFG_FG_NHG, fgnhgorch_pri }, + { CFG_FG_NHG_PREFIX, fgnhgorch_pri }, + { CFG_FG_NHG_MEMBER, fgnhgorch_pri } + }; + gFgNhgOrch = new FgNhgOrch(m_config_db.get(), m_app_db.get(), m_state_db.get(), fgnhg_tables, gNeighOrch, gIntfsOrch, gVrfOrch); + + ASSERT_EQ(gSrv6Orch, nullptr); + vector srv6_tables = { + APP_SRV6_SID_LIST_TABLE_NAME, + APP_SRV6_MY_SID_TABLE_NAME + }; + gSrv6Orch = new Srv6Orch(m_app_db.get(), srv6_tables, gSwitchOrch, gVrfOrch, gNeighOrch); + + ASSERT_EQ(gRouteOrch, nullptr); + const int routeorch_pri = 5; + vector route_tables = { + { APP_ROUTE_TABLE_NAME, routeorch_pri }, + { APP_LABEL_ROUTE_TABLE_NAME, routeorch_pri } + }; + gRouteOrch = new RouteOrch(m_app_db.get(), route_tables, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch, gFgNhgOrch, gSrv6Orch); + gNhgOrch = new NhgOrch(m_app_db.get(), APP_NEXTHOP_GROUP_TABLE_NAME); + + // Recreate buffer orch to read populated data + vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME }; + + gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); + + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate pot table with SAI ports + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + // Prepare interface table + Table intfTable = Table(m_app_db.get(), APP_INTF_TABLE_NAME); + intfTable.set("Ethernet0", { {"NULL", "NULL" }, + {"mac_addr", "00:00:00:00:00:00" }}); + intfTable.set("Ethernet0:10.0.0.1/24", { { "scope", "global" }, + { "family", "IPv4" }}); + gIntfsOrch->addExistingData(&intfTable); + static_cast(gIntfsOrch)->doTask(); + + // Prepare neighbor table + Table neighborTable = Table(m_app_db.get(), APP_NEIGH_TABLE_NAME); + + map neighborIp2Mac = {{"10.0.0.2", "00:00:0a:00:00:02" }, + {"10.0.0.3", "00:00:0a:00:00:03" } }; + neighborTable.set("Ethernet0:10.0.0.2", { {"neigh", neighborIp2Mac["10.0.0.2"]}, + {"family", "IPv4" }}); + neighborTable.set("Ethernet0:10.0.0.3", { {"neigh", neighborIp2Mac["10.0.0.3"]}, + {"family", "IPv4" }}); + gNeighOrch->addExistingData(&neighborTable); + static_cast(gNeighOrch)->doTask(); + + //Prepare route table + Table routeTable = Table(m_app_db.get(), APP_ROUTE_TABLE_NAME); + routeTable.set("1.1.1.1/32", { {"ifname", "Ethernet0" }, + {"nexthop", "10.0.0.2" }}); + routeTable.set("0.0.0.0/0", { {"ifname", "Ethernet0" }, + {"nexthop", "10.0.0.2" }}); + gRouteOrch->addExistingData(&routeTable); + static_cast(gRouteOrch)->doTask(); + + // Enable flow counter + std::deque entries; + entries.push_back({"FLOW_CNT_ROUTE", "SET", { {"FLEX_COUNTER_STATUS", "enable"}, {"POLL_INTERVAL", "10000"}}}); + auto consumer = dynamic_cast(flexCounterOrch->getExecutor(CFG_FLEX_COUNTER_TABLE_NAME)); + consumer->addToSync(entries); + static_cast(flexCounterOrch)->doTask(); + + // Start FlowCounterRouteOrch + static const vector route_pattern_tables = { + CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME, + }; + gFlowCounterRouteOrch = new FlowCounterRouteOrch(m_config_db.get(), route_pattern_tables); + + static_cast(gFlowCounterRouteOrch)->doTask(); + + return; + } + + void TearDown() override + { + gDirectory.m_values.clear(); + + delete gCrmOrch; + gCrmOrch = nullptr; + + delete gSwitchOrch; + gSwitchOrch = nullptr; + + delete gBfdOrch; + gBfdOrch = nullptr; + + delete gNeighOrch; + gNeighOrch = nullptr; + + delete gFdbOrch; + gFdbOrch = nullptr; + + delete gPortsOrch; + gPortsOrch = nullptr; + + delete gIntfsOrch; + gIntfsOrch = nullptr; + + delete gFgNhgOrch; + gFgNhgOrch = nullptr; + + delete gSrv6Orch; + gSrv6Orch = nullptr; + + delete gRouteOrch; + gRouteOrch = nullptr; + + delete gNhgOrch; + gNhgOrch = nullptr; + + delete gBufferOrch; + gBufferOrch = nullptr; + + delete gVrfOrch; + gVrfOrch = nullptr; + + delete gFlowCounterRouteOrch; + gFlowCounterRouteOrch = nullptr; + + sai_counter_api = pold_sai_counter_api; + ut_helper::uninitSaiApi(); + return; + } + }; + + TEST_F(FlowcounterRouteOrchTest, FlowcounterRouteOrchTestPatternAddDel) + { + std::deque entries; + // Setting route pattern + auto current_counter_num = num_created_counter; + entries.push_back({"1.1.1.0/24", "SET", { {"max_match_count", "10"}}}); + auto consumer = dynamic_cast(gFlowCounterRouteOrch->getExecutor(CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME)); + consumer->addToSync(entries); + static_cast(gFlowCounterRouteOrch)->doTask(); + ASSERT_TRUE(num_created_counter - current_counter_num == 1); + + // Deleting route pattern + current_counter_num = num_created_counter; + entries.push_back({"1.1.1.0/24", "DEL", { {"max_match_count", "10"}}}); + consumer->addToSync(entries); + static_cast(gFlowCounterRouteOrch)->doTask(); + ASSERT_TRUE(current_counter_num - num_created_counter == 1); + + } +} \ No newline at end of file diff --git a/tests/mock_tests/intfmgrd/add_ipv6_prefix_ut.cpp b/tests/mock_tests/intfmgrd/add_ipv6_prefix_ut.cpp new file mode 100644 index 0000000000..f07fa9ccbd --- /dev/null +++ b/tests/mock_tests/intfmgrd/add_ipv6_prefix_ut.cpp @@ -0,0 +1,117 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include +#include "../mock_table.h" +#include "warm_restart.h" +#define private public +#include "intfmgr.h" +#undef private + +/* Override this pointer for custom behavior */ +int (*callback)(const std::string &cmd, std::string &stdout) = nullptr; +std::vector mockCallArgs; + +namespace swss { + int exec(const std::string &cmd, std::string &stdout) + { + mockCallArgs.push_back(cmd); + return callback(cmd, stdout); + } +} + +bool Ethernet0IPv6Set = false; + +int cb(const std::string &cmd, std::string &stdout){ + if (cmd == "sysctl -w net.ipv6.conf.\"Ethernet0\".disable_ipv6=0") Ethernet0IPv6Set = true; + else if (cmd.find("/sbin/ip -6 address \"add\"") == 0) { + return Ethernet0IPv6Set ? 0 : 2; + } + else { + return 0; + } + return 0; +} + +// Test Fixture +namespace add_ipv6_prefix_ut +{ + struct IntfMgrTest : public ::testing::Test + { + std::shared_ptr m_config_db; + std::shared_ptr m_app_db; + std::shared_ptr m_state_db; + std::vector cfg_intf_tables; + + virtual void SetUp() override + { + testing_db::reset(); + m_config_db = std::make_shared("CONFIG_DB", 0); + m_app_db = std::make_shared("APPL_DB", 0); + m_state_db = std::make_shared("STATE_DB", 0); + + swss::WarmStart::initialize("intfmgrd", "swss"); + + std::vector tables = { + CFG_INTF_TABLE_NAME, + CFG_LAG_INTF_TABLE_NAME, + CFG_VLAN_INTF_TABLE_NAME, + CFG_LOOPBACK_INTERFACE_TABLE_NAME, + CFG_VLAN_SUB_INTF_TABLE_NAME, + CFG_VOQ_INBAND_INTERFACE_TABLE_NAME, + }; + cfg_intf_tables = tables; + mockCallArgs.clear(); + callback = cb; + } + }; + + TEST_F(IntfMgrTest, testSettingIpv6Flag){ + Ethernet0IPv6Set = false; + swss::IntfMgr intfmgr(m_config_db.get(), m_app_db.get(), m_state_db.get(), cfg_intf_tables); + /* Set portStateTable */ + std::vector values; + values.emplace_back("state", "ok"); + intfmgr.m_statePortTable.set("Ethernet0", values, "SET", ""); + /* Set m_stateIntfTable */ + values.clear(); + values.emplace_back("vrf", ""); + intfmgr.m_stateIntfTable.set("Ethernet0", values, "SET", ""); + /* Set Ipv6 prefix */ + const std::vector& keys = {"Ethernet0", "2001::8/64"}; + const std::vector data; + intfmgr.doIntfAddrTask(keys, data, "SET"); + int ip_cmd_called = 0; + for (auto cmd : mockCallArgs){ + if (cmd.find("/sbin/ip -6 address \"add\"") == 0){ + ip_cmd_called++; + } + } + ASSERT_EQ(ip_cmd_called, 2); + } + + TEST_F(IntfMgrTest, testNoSettingIpv6Flag){ + Ethernet0IPv6Set = true; // Assuming it is already set by SDK + swss::IntfMgr intfmgr(m_config_db.get(), m_app_db.get(), m_state_db.get(), cfg_intf_tables); + /* Set portStateTable */ + std::vector values; + values.emplace_back("state", "ok"); + intfmgr.m_statePortTable.set("Ethernet0", values, "SET", ""); + /* Set m_stateIntfTable */ + values.clear(); + values.emplace_back("vrf", ""); + intfmgr.m_stateIntfTable.set("Ethernet0", values, "SET", ""); + /* Set Ipv6 prefix */ + const std::vector& keys = {"Ethernet0", "2001::8/64"}; + const std::vector data; + intfmgr.doIntfAddrTask(keys, data, "SET"); + int ip_cmd_called = 0; + for (auto cmd : mockCallArgs){ + if (cmd.find("/sbin/ip -6 address \"add\"") == 0){ + ip_cmd_called++; + } + } + ASSERT_EQ(ip_cmd_called, 1); + } +} diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index ceaa2f553f..57df931cb5 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -23,6 +23,7 @@ #include "tunneldecaporch.h" #include "muxorch.h" #include "nhgorch.h" +#include "copporch.h" #include "directory.h" extern int gBatchSize; @@ -55,6 +56,7 @@ extern QosOrch *gQosOrch; extern VRFOrch *gVrfOrch; extern NhgOrch *gNhgOrch; extern Srv6Orch *gSrv6Orch; +extern BfdOrch *gBfdOrch; extern Directory gDirectory; extern sai_acl_api_t *sai_acl_api; @@ -70,6 +72,7 @@ extern sai_neighbor_api_t *sai_neighbor_api; extern sai_tunnel_api_t *sai_tunnel_api; extern sai_next_hop_api_t *sai_next_hop_api; extern sai_hostif_api_t *sai_hostif_api; +extern sai_policer_api_t *sai_policer_api; extern sai_buffer_api_t *sai_buffer_api; extern sai_qos_map_api_t *sai_qos_map_api; extern sai_scheduler_api_t *sai_scheduler_api; @@ -78,3 +81,4 @@ extern sai_wred_api_t *sai_wred_api; extern sai_queue_api_t *sai_queue_api; extern sai_udf_api_t* sai_udf_api; extern sai_mpls_api_t* sai_mpls_api; +extern sai_counter_api_t* sai_counter_api; diff --git a/tests/mock_tests/mock_table.cpp b/tests/mock_tests/mock_table.cpp index 732bac54a6..fb98ed301b 100644 --- a/tests/mock_tests/mock_table.cpp +++ b/tests/mock_tests/mock_table.cpp @@ -119,4 +119,4 @@ namespace swss auto &table = gDB[m_pipe->getDbId()][getTableName()]; table.erase(key); } -} \ No newline at end of file +} diff --git a/tests/mock_tests/portal.h b/tests/mock_tests/portal.h index c2438e8e1c..94b2051211 100644 --- a/tests/mock_tests/portal.h +++ b/tests/mock_tests/portal.h @@ -5,6 +5,8 @@ #include "aclorch.h" #include "crmorch.h" +#include "copporch.h" +#include "directory.h" #undef protected #undef private @@ -59,4 +61,39 @@ struct Portal crmOrch->getResAvailableCounters(); } }; + + struct CoppOrchInternal + { + static TrapGroupPolicerTable getTrapGroupPolicerMap(CoppOrch &obj) + { + return obj.m_trap_group_policer_map; + } + + static TrapIdTrapObjectsTable getTrapGroupIdMap(CoppOrch &obj) + { + return obj.m_syncdTrapIds; + } + + static std::vector getTrapIdsFromTrapGroup(CoppOrch &obj, sai_object_id_t trapGroupOid) + { + std::vector trapIdList; + obj.getTrapIdsFromTrapGroup(trapGroupOid, trapIdList); + return trapIdList; + } + }; + + struct DirectoryInternal + { + template + static void clear(Directory &obj) + { + obj.m_values.clear(); + } + + template + static bool empty(Directory &obj) + { + return obj.m_values.empty(); + } + }; }; diff --git a/tests/mock_tests/ut_helper.h b/tests/mock_tests/ut_helper.h index baaf8184d8..f8f411d025 100644 --- a/tests/mock_tests/ut_helper.h +++ b/tests/mock_tests/ut_helper.h @@ -13,7 +13,7 @@ namespace ut_helper { sai_status_t initSaiApi(const std::map &profile); - void uninitSaiApi(); + sai_status_t uninitSaiApi(); map> getInitialSaiPorts(); } diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index 70eb96c99f..80a2d6ee38 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -76,6 +76,7 @@ namespace ut_helper sai_api_query(SAI_API_NEXT_HOP, (void **)&sai_next_hop_api); sai_api_query(SAI_API_ACL, (void **)&sai_acl_api); sai_api_query(SAI_API_HOSTIF, (void **)&sai_hostif_api); + sai_api_query(SAI_API_POLICER, (void **)&sai_policer_api); sai_api_query(SAI_API_BUFFER, (void **)&sai_buffer_api); sai_api_query(SAI_API_QOS_MAP, (void **)&sai_qos_map_api); sai_api_query(SAI_API_SCHEDULER_GROUP, (void **)&sai_scheduler_group_api); @@ -83,13 +84,18 @@ namespace ut_helper sai_api_query(SAI_API_WRED, (void **)&sai_wred_api); sai_api_query(SAI_API_QUEUE, (void **)&sai_queue_api); sai_api_query(SAI_API_MPLS, (void**)&sai_mpls_api); + sai_api_query(SAI_API_COUNTER, (void**)&sai_counter_api); return SAI_STATUS_SUCCESS; } - void uninitSaiApi() + sai_status_t uninitSaiApi() { - sai_api_uninitialize(); + auto status = sai_api_uninitialize(); + if (status != SAI_STATUS_SUCCESS) + { + return status; + } sai_switch_api = nullptr; sai_bridge_api = nullptr; @@ -104,8 +110,12 @@ namespace ut_helper sai_next_hop_api = nullptr; sai_acl_api = nullptr; sai_hostif_api = nullptr; + sai_policer_api = nullptr; sai_buffer_api = nullptr; sai_queue_api = nullptr; + sai_counter_api = nullptr; + + return SAI_STATUS_SUCCESS; } map> getInitialSaiPorts() diff --git a/tests/test_buffer_dynamic.py b/tests/test_buffer_dynamic.py index 2b4367f00d..69c577bd26 100644 --- a/tests/test_buffer_dynamic.py +++ b/tests/test_buffer_dynamic.py @@ -737,6 +737,7 @@ def test_autoNegPort(self, dvs, testlog): self.cleanup_db(dvs) + @pytest.mark.skip(reason="Failing. Under investigation") def test_removeBufferPool(self, dvs, testlog): self.setup_db(dvs) # Initialize additional databases that are used by this test only diff --git a/tests/test_buffer_traditional.py b/tests/test_buffer_traditional.py index e955390fde..3d2285fd7b 100644 --- a/tests/test_buffer_traditional.py +++ b/tests/test_buffer_traditional.py @@ -3,7 +3,7 @@ class TestBuffer(object): - LOSSLESS_PGS = [3, 4] + lossless_pgs = [] INTF = "Ethernet0" def setup_db(self, dvs): @@ -15,6 +15,10 @@ def setup_db(self, dvs): # enable PG watermark self.set_pg_wm_status('enable') + def get_pfc_enable_queues(self): + qos_map = self.config_db.get_entry("PORT_QOS_MAP", self.INTF) + return qos_map['pfc_enable'].split(',') + def get_pg_oid(self, pg): fvs = dict() fvs = self.counter_db.get_entry("COUNTERS_PG_NAME_MAP", "") @@ -51,19 +55,32 @@ def get_asic_buf_pg_profiles(self): buf_pg_entries = self.asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP", self.pg_name_map[pg]) self.buf_pg_profile[pg] = buf_pg_entries["SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE"] - def change_cable_len(self, cable_len): + def change_cable_len(self, cable_len, extra_port=None): fvs = dict() fvs[self.INTF] = cable_len + if extra_port: + fvs[extra_port] = cable_len self.config_db.update_entry("CABLE_LENGTH", "AZURE", fvs) + def set_port_qos_table(self, port, pfc_enable_flag): + fvs=dict() + fvs['pfc_enable'] = pfc_enable_flag + self.config_db.update_entry("PORT_QOS_MAP", port, fvs) + self.lossless_pgs = pfc_enable_flag.split(',') + + def get_pg_name_map(self): + pg_name_map = dict() + for pg in self.lossless_pgs: + pg_name = "{}:{}".format(self.INTF, pg) + pg_name_map[pg_name] = self.get_pg_oid(pg_name) + return pg_name_map + @pytest.fixture def setup_teardown_test(self, dvs): try: self.setup_db(dvs) - pg_name_map = dict() - for pg in self.LOSSLESS_PGS: - pg_name = "{}:{}".format(self.INTF, pg) - pg_name_map[pg_name] = self.get_pg_oid(pg_name) + self.set_port_qos_table(self.INTF, '2,3,4,6') + pg_name_map = self.get_pg_name_map() yield pg_name_map finally: self.teardown() @@ -119,7 +136,8 @@ def test_zero_cable_len_profile_update(self, dvs, setup_teardown_test): self.app_db.wait_for_deleted_entry("BUFFER_PROFILE_TABLE", test_lossless_profile) # buffer pgs should still point to the original buffer profile - self.app_db.wait_for_field_match("BUFFER_PG_TABLE", self.INTF + ":3-4", {"profile": orig_lossless_profile}) + for pg in self.lossless_pgs: + self.app_db.wait_for_field_match("BUFFER_PG_TABLE", self.INTF + ":" + pg, {"profile": orig_lossless_profile}) fvs = dict() for pg in self.pg_name_map: fvs["SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE"] = self.buf_pg_profile[pg] @@ -152,3 +170,77 @@ def test_zero_cable_len_profile_update(self, dvs, setup_teardown_test): if orig_speed: dvs.port_field_set(self.INTF, "speed", orig_speed) dvs.port_admin_set(self.INTF, "down") + + # To verify the BUFFER_PG is not hardcoded to 3,4 + # buffermgrd will read 'pfc_enable' entry and apply lossless profile to that queue + def test_buffer_pg_update(self, dvs, setup_teardown_test): + self.pg_name_map = setup_teardown_test + orig_cable_len = None + orig_speed = None + test_speed = None + extra_port = "Ethernet4" + try: + # Retrieve cable len + fvs_cable_len = self.config_db.get_entry("CABLE_LENGTH", "AZURE") + orig_cable_len = fvs_cable_len[self.INTF] + if orig_cable_len == "0m": + cable_len_for_test = "300m" + fvs_cable_len[self.INTF] = cable_len_for_test + fvs_cable_len[extra_port] = cable_len_for_test + + self.config_db.update_entry("CABLE_LENGTH", "AZURE", fvs_cable_len) + else: + cable_len_for_test = orig_cable_len + # Ethernet4 is set to up, while no 'pfc_enable' available. `Ethernet0` is not supposed to be impacted + dvs.port_admin_set(extra_port, "up") + + dvs.port_admin_set(self.INTF, "up") + + # Retrieve port speed + fvs_port = self.config_db.get_entry("PORT", self.INTF) + orig_speed = fvs_port["speed"] + + # Make sure the buffer PG has been created + orig_lossless_profile = "pg_lossless_{}_{}_profile".format(orig_speed, cable_len_for_test) + self.app_db.wait_for_entry("BUFFER_PROFILE_TABLE", orig_lossless_profile) + self.orig_profiles = self.get_asic_buf_profile() + + # get the orig buf profiles attached to the pgs + self.get_asic_buf_pg_profiles() + + # Update port speed + if orig_speed == "100000": + test_speed = "40000" + elif orig_speed == "40000": + test_speed = "100000" + # change intf speed to 'test_speed' + dvs.port_field_set(self.INTF, "speed", test_speed) + dvs.port_field_set(extra_port, "speed", test_speed) + # Verify new profile is generated + new_lossless_profile = "pg_lossless_{}_{}_profile".format(test_speed, cable_len_for_test) + self.app_db.wait_for_entry("BUFFER_PROFILE_TABLE", new_lossless_profile) + + # Verify BUFFER_PG is updated + for pg in self.lossless_pgs: + self.app_db.wait_for_field_match("BUFFER_PG_TABLE", self.INTF + ":" + pg, {"profile": new_lossless_profile}) + + fvs_negative = {} + for pg in self.pg_name_map: + # verify that buffer pgs do not point to the old profile since we cannot deduce the new profile oid + fvs_negative["SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE"] = self.buf_pg_profile[pg] + self.asic_db.wait_for_field_negative_match("ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP", self.pg_name_map[pg], fvs_negative) + + # Add pfc_enable field for extra port + self.set_port_qos_table(extra_port, '2,3,4,6') + time.sleep(1) + # Verify BUFFER_PG is updated when pfc_enable is available + for pg in self.lossless_pgs: + self.app_db.wait_for_field_match("BUFFER_PG_TABLE", extra_port + ":" + pg, {"profile": new_lossless_profile}) + finally: + if orig_cable_len: + self.change_cable_len(orig_cable_len, extra_port) + if orig_speed: + dvs.port_field_set(self.INTF, "speed", orig_speed) + dvs.port_field_set(extra_port, "speed", orig_speed) + dvs.port_admin_set(self.INTF, "down") + dvs.port_admin_set(extra_port, "down") diff --git a/tests/test_macsec.py b/tests/test_macsec.py index f74f31c008..61c90d84a8 100644 --- a/tests/test_macsec.py +++ b/tests/test_macsec.py @@ -1,11 +1,9 @@ from swsscommon import swsscommon import conftest -import sys import functools import typing import re -import time def to_string(value): @@ -94,11 +92,8 @@ def gen_sci(macsec_system_identifier: str, macsec_port_identifier: int) -> str: str.maketrans("", "", ":.-")) sci = "{}{}".format( macsec_system_identifier, - str(macsec_port_identifier).zfill(4)) - sci = int(sci, 16) - if sys.byteorder == "little": - sci = int.from_bytes(sci.to_bytes(8, 'big'), 'little', signed=False) - return str(sci) + str(macsec_port_identifier).zfill(4)).lower() + return sci def gen_sc_key( @@ -321,6 +316,13 @@ def delete_transmit_sa(self, sai: str): del self.app_transmit_sa_table[sai] self.state_transmit_sa_table.wait_delete(sai) + @macsec_sa() + def set_macsec_pn( + self, + sai: str, + pn: int): + self.app_transmit_sa_table[sai] = {"next_pn": pn} + @macsec_sc() def set_enable_transmit_sa(self, sci: str, an: int, enable: bool): if enable: @@ -475,6 +477,12 @@ def rekey_macsec( auth_key: str, ssci: int, salt: str): + wpa.set_macsec_pn( + port_name, + local_mac_address, + macsec_port_identifier, + an, + 0x00000000C0000000) wpa.create_receive_sa( port_name, peer_mac_address, diff --git a/tests/test_nat.py b/tests/test_nat.py index 9e87b5f54c..1c509e464f 100644 --- a/tests/test_nat.py +++ b/tests/test_nat.py @@ -15,13 +15,10 @@ def setup_db(self, dvs): self.config_db = dvs.get_config_db() def set_interfaces(self, dvs): - fvs = {"NULL": "NULL"} - self.config_db.create_entry("INTERFACE", "Ethernet0|67.66.65.1/24", fvs) - self.config_db.create_entry("INTERFACE", "Ethernet4|18.18.18.1/24", fvs) - self.config_db.create_entry("INTERFACE", "Ethernet0", fvs) - self.config_db.create_entry("INTERFACE", "Ethernet4", fvs) - dvs.runcmd("config interface startup Ethernet0") - dvs.runcmd("config interface startup Ethernet4") + dvs.interface_ip_add("Ethernet0", "67.66.65.1/24") + dvs.interface_ip_add("Ethernet4", "18.18.18.1/24") + dvs.port_admin_set("Ethernet0", "up") + dvs.port_admin_set("Etherent4", "up") dvs.servers[0].runcmd("ip link set down dev eth0") dvs.servers[0].runcmd("ip link set up dev eth0") @@ -33,7 +30,7 @@ def set_interfaces(self, dvs): dvs.servers[1].runcmd("ifconfig eth0 18.18.18.2/24") dvs.servers[1].runcmd("ip route add default via 18.18.18.1") - dvs.runcmd("config nat add interface Ethernet0 -nat_zone 1") + dvs.set_nat_zone("Ethernet0", "1") time.sleep(1) @@ -48,10 +45,10 @@ def test_NatGlobalTable(self, dvs, testlog): self.setup_db(dvs) # enable NAT feature - dvs.runcmd("config nat feature enable") - dvs.runcmd("config nat set timeout 450") - dvs.runcmd("config nat set udp-timeout 360") - dvs.runcmd("config nat set tcp-timeout 900") + dvs.nat_mode_set("enabled") + dvs.nat_timeout_set("450") + dvs.nat_udp_timeout_set("360") + dvs.nat_tcp_timeout_set("900") # check NAT global values in appdb self.app_db.wait_for_n_keys("NAT_GLOBAL_TABLE", 1) @@ -82,7 +79,7 @@ def test_AddNatStaticEntry(self, dvs, testlog): dvs.servers[0].runcmd("ping -c 1 18.18.18.2") # add a static nat entry - dvs.runcmd("config nat add static basic 67.66.65.1 18.18.18.2") + dvs.add_nat_basic_entry("67.66.65.1", "18.18.18.2") # check the entry in the config db self.config_db.wait_for_n_keys("STATIC_NAT", 1) @@ -115,7 +112,7 @@ def test_DelNatStaticEntry(self, dvs, testlog): self.setup_db(dvs) # delete a static nat entry - dvs.runcmd("config nat remove static basic 67.66.65.1 18.18.18.2") + dvs.del_nat_basic_entry("67.66.65.1") # check the entry is no there in the config db self.config_db.wait_for_n_keys("STATIC_NAT", 0) @@ -134,7 +131,7 @@ def test_AddNaPtStaticEntry(self, dvs, testlog): dvs.servers[0].runcmd("ping -c 1 18.18.18.2") # add a static nat entry - dvs.runcmd("config nat add static udp 67.66.65.1 670 18.18.18.2 180") + dvs.add_nat_udp_entry("67.66.65.1", "670", "18.18.18.2", "180") # check the entry in the config db self.config_db.wait_for_n_keys("STATIC_NAPT", 1) @@ -165,7 +162,7 @@ def test_DelNaPtStaticEntry(self, dvs, testlog): self.setup_db(dvs) # delete a static nat entry - dvs.runcmd("config nat remove static udp 67.66.65.1 670 18.18.18.2 180") + dvs.del_nat_udp_entry("67.66.65.1", "670") # check the entry is no there in the config db self.config_db.wait_for_n_keys("STATIC_NAPT", 0) @@ -186,8 +183,8 @@ def test_AddTwiceNatEntry(self, dvs, testlog): dvs.servers[1].runcmd("ping -c 1 67.66.65.2") # add a twice nat entry - dvs.runcmd("config nat add static basic 67.66.65.2 18.18.18.1 -nat_type snat -twice_nat_id 9") - dvs.runcmd("config nat add static basic 67.66.65.1 18.18.18.2 -nat_type dnat -twice_nat_id 9") + dvs.add_twice_nat_basic_entry("67.66.65.2", "18.18.18.1", "snat", "9") + dvs.add_twice_nat_basic_entry("67.66.65.1", "18.18.18.2", "dnat", "9") # check the entry in the config db self.config_db.wait_for_n_keys("STATIC_NAT", 2) @@ -220,8 +217,8 @@ def test_DelTwiceNatStaticEntry(self, dvs, testlog): self.setup_db(dvs) # delete a static nat entry - dvs.runcmd("config nat remove static basic 67.66.65.2 18.18.18.1") - dvs.runcmd("config nat remove static basic 67.66.65.1 18.18.18.2") + dvs.del_twice_nat_basic_entry("67.66.65.2") + dvs.del_twice_nat_basic_entry("67.66.65.1") # check the entry is no there in the config db self.config_db.wait_for_n_keys("STATIC_NAT", 0) @@ -241,8 +238,8 @@ def test_AddTwiceNaPtEntry(self, dvs, testlog): dvs.servers[1].runcmd("ping -c 1 67.66.65.2") # add a twice nat entry - dvs.runcmd("config nat add static udp 67.66.65.2 670 18.18.18.1 181 -nat_type snat -twice_nat_id 7") - dvs.runcmd("config nat add static udp 67.66.65.1 660 18.18.18.2 182 -nat_type dnat -twice_nat_id 7") + dvs.add_twice_nat_udp_entry("67.66.65.2", "670", "18.18.18.1", "181", "snat", "7") + dvs.add_twice_nat_udp_entry("67.66.65.1", "660", "18.18.18.2", "182", "dnat", "7") # check the entry in the config db self.config_db.wait_for_n_keys("STATIC_NAPT", 2) @@ -277,8 +274,8 @@ def test_DelTwiceNaPtStaticEntry(self, dvs, testlog): self.setup_db(dvs) # delete a static nat entry - dvs.runcmd("config nat remove static udp 67.66.65.2 670 18.18.18.1 181") - dvs.runcmd("config nat remove static udp 67.66.65.1 660 18.18.18.2 182") + dvs.del_twice_nat_udp_entry("67.66.65.2", "670") + dvs.del_twice_nat_udp_entry("67.66.65.1", "660") # check the entry is not there in the config db self.config_db.wait_for_n_keys("STATIC_NAPT", 0) @@ -294,7 +291,7 @@ def test_VerifyConntrackTimeoutForNatEntry(self, dvs, testlog): dvs.servers[0].runcmd("ping -c 1 18.18.18.2") # add a static nat entry - dvs.runcmd("config nat add static basic 67.66.65.1 18.18.18.2") + dvs.add_nat_basic_entry("67.66.65.1", "18.18.18.2") # check the conntrack timeout for static entry def _check_conntrack_for_static_entry(): @@ -321,7 +318,7 @@ def _check_conntrack_for_static_entry(): wait_for_result(_check_conntrack_for_static_entry) # delete a static nat entry - dvs.runcmd("config nat remove static basic 67.66.65.1 18.18.18.2") + dvs.del_nat_basic_entry("67.66.65.1") def test_DoNotNatAclAction(self, dvs_acl, testlog): @@ -360,7 +357,7 @@ def test_CrmSnatAndDnatEntryUsedCount(self, dvs, testlog): dvs.servers[0].runcmd("ping -c 1 18.18.18.2") # set pooling interval to 1 - dvs.runcmd("crm config polling interval 1") + dvs.crm_poll_set("1") dvs.setReadOnlyAttr('SAI_OBJECT_TYPE_SWITCH', 'SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY', '1000') dvs.setReadOnlyAttr('SAI_OBJECT_TYPE_SWITCH', 'SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY', '1000') @@ -376,7 +373,7 @@ def test_CrmSnatAndDnatEntryUsedCount(self, dvs, testlog): avail_dnat_counter = dvs.getCrmCounterValue('STATS', 'crm_stats_dnat_entry_available') # add a static nat entry - dvs.runcmd("config nat add static basic 67.66.65.1 18.18.18.2") + dvs.add_nat_basic_entry("67.66.65.1", "18.18.18.2") #check the entry in asic db, 3 keys = SNAT, DNAT and DNAT_Pool keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_NAT_ENTRY", 3) @@ -405,7 +402,7 @@ def test_CrmSnatAndDnatEntryUsedCount(self, dvs, testlog): assert avail_dnat_counter - new_avail_dnat_counter == 1 # delete a static nat entry - dvs.runcmd("config nat remove static basic 67.66.65.1 18.18.18.2") + dvs.del_nat_basic_entry("67.66.65.1") dvs.setReadOnlyAttr('SAI_OBJECT_TYPE_SWITCH', 'SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY', '1000') dvs.setReadOnlyAttr('SAI_OBJECT_TYPE_SWITCH', 'SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY', '1000') diff --git a/tests/test_neighbor.py b/tests/test_neighbor.py index 4893faeb21..741ce9a71a 100644 --- a/tests/test_neighbor.py +++ b/tests/test_neighbor.py @@ -413,6 +413,53 @@ def test_FlushResolveNeighborIpv4(self, dvs, testlog): (exitcode, output) = dvs.runcmd(['sh', '-c', "supervisorctl status nbrmgrd | awk '{print $2}'"]) assert output == "RUNNING\n" + def test_Ipv4LinkLocalNeighbor(self, dvs, testlog): + self.setup_db(dvs) + + # bring up interface + self.set_admin_status("Ethernet8", "up") + + # create interface + self.create_l3_intf("Ethernet8", "") + + # assign IP to interface + self.add_ip_address("Ethernet8", "10.0.0.1/24") + + # add neighbor + self.add_neighbor("Ethernet8", "169.254.0.0", "00:01:02:03:04:05") + + # check application database + tbl = swsscommon.Table(self.pdb, "NEIGH_TABLE:Ethernet8") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 0 + + # check ASIC neighbor database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_NEIGHBOR_ENTRY") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 0 + + # remove neighbor + self.remove_neighbor("Ethernet8", "169.254.0.0") + + # remove IP from interface + self.remove_ip_address("Ethernet8", "10.0.0.1/24") + + # remove interface + self.remove_l3_intf("Ethernet8") + + # bring down interface + self.set_admin_status("Ethernet8", "down") + + # check application database + tbl = swsscommon.Table(self.pdb, "NEIGH_TABLE:Ethernet8") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 0 + + # check ASIC neighbor database + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_NEIGHBOR_ENTRY") + intf_entries = tbl.getKeys() + assert len(intf_entries) == 0 + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying diff --git a/tests/test_pfcwd.py b/tests/test_pfcwd.py index 2707588580..c88b6f6e96 100644 --- a/tests/test_pfcwd.py +++ b/tests/test_pfcwd.py @@ -148,9 +148,11 @@ def _get_bitmask(self, queues): return str(mask) def set_ports_pfc(self, status='enable', pfc_queues=[3,4]): + keyname = 'pfcwd_sw_enable' for port in self.test_ports: if 'enable' in status: - fvs = {'pfc_enable': ",".join([str(q) for q in pfc_queues])} + queues = ",".join([str(q) for q in pfc_queues]) + fvs = {keyname: queues, 'pfc_enable': queues} self.config_db.create_entry("PORT_QOS_MAP", port, fvs) else: self.config_db.delete_entry("PORT_QOS_MAP", port) @@ -212,7 +214,7 @@ def set_storm_state(self, queues, state="enabled"): queue_name = port + ":" + str(queue) self.counters_db.update_entry("COUNTERS", self.queue_oids[queue_name], fvs) - def test_pfcwd_single_queue(self, dvs, setup_teardown_test): + def test_pfcwd_software_single_queue(self, dvs, setup_teardown_test): try: # enable PFC on queues test_queues = [3, 4] @@ -253,7 +255,7 @@ def test_pfcwd_single_queue(self, dvs, setup_teardown_test): self.reset_pfcwd_counters(storm_queue) self.stop_pfcwd_on_ports() - def test_pfcwd_multi_queue(self, dvs, setup_teardown_test): + def test_pfcwd_software_multi_queue(self, dvs, setup_teardown_test): try: # enable PFC on queues test_queues = [3, 4] diff --git a/tests/test_route.py b/tests/test_route.py index 9c56ef52a8..ed96a34bde 100644 --- a/tests/test_route.py +++ b/tests/test_route.py @@ -604,6 +604,7 @@ def test_RouteAddRemoveIpv6RouteUnresolvedNeigh(self, dvs, testlog): dvs.servers[1].runcmd("ip -6 route del default dev eth0") dvs.servers[1].runcmd("ip -6 address del 2001::2/64 dev eth0") + @pytest.mark.skip(reason="Failing. Under investigation") def test_RouteAddRemoveIpv4RouteWithVrf(self, dvs, testlog): self.setup_db(dvs) diff --git a/tests/test_tunnel.py b/tests/test_tunnel.py index 8c4f8d7408..4b96eb5060 100644 --- a/tests/test_tunnel.py +++ b/tests/test_tunnel.py @@ -83,6 +83,7 @@ def create_and_test_tunnel(self, db, asicdb, tunnel_name, **kwargs): decap_dscp_to_tc_map_oid = None decap_tc_to_pg_map_oid = None + skip_tunnel_creation = False if "decap_dscp_to_tc_map_oid" in kwargs: decap_dscp_to_tc_map_oid = kwargs.pop("decap_dscp_to_tc_map_oid") @@ -90,11 +91,14 @@ def create_and_test_tunnel(self, db, asicdb, tunnel_name, **kwargs): if "decap_tc_to_pg_map_oid" in kwargs: decap_tc_to_pg_map_oid = kwargs.pop("decap_tc_to_pg_map_oid") - fvs = create_fvs(**kwargs) - - # create tunnel entry in DB - ps = swsscommon.ProducerStateTable(db, self.APP_TUNNEL_DECAP_TABLE_NAME) - ps.set(tunnel_name, fvs) + if "skip_tunnel_creation" in kwargs: + skip_tunnel_creation = kwargs.pop("skip_tunnel_creation") + + if not skip_tunnel_creation: + fvs = create_fvs(**kwargs) + # create tunnel entry in DB + ps = swsscommon.ProducerStateTable(db, self.APP_TUNNEL_DECAP_TABLE_NAME) + ps.set(tunnel_name, fvs) # wait till config will be applied time.sleep(1) @@ -191,10 +195,10 @@ def add_qos_map(self, configdb, asicdb, qos_map_type_name, qos_map_name, qos_map oid = diff.pop() return oid - def remove_qos_map(self, configdb, qos_map_type_name, qos_map_oid): + def remove_qos_map(self, configdb, qos_map_type_name, qos_map_name): """ Remove the testing qos map""" table = swsscommon.Table(configdb, qos_map_type_name) - table._del(qos_map_oid) + table._del(qos_map_name) def cleanup_left_over(self, db, asicdb): """ Cleanup APP and ASIC tables """ @@ -207,10 +211,9 @@ def cleanup_left_over(self, db, asicdb): for key in tunnel_term_table.getKeys(): tunnel_term_table._del(key) - tunnel_app_table = swsscommon.Table(asicdb, self.APP_TUNNEL_DECAP_TABLE_NAME) + tunnel_app_table = swsscommon.Table(db, self.APP_TUNNEL_DECAP_TABLE_NAME) for key in tunnel_app_table.getKeys(): - tunnel_table._del(key) - + tunnel_app_table._del(key) class TestDecapTunnel(TestTunnelBase): """ Tests for decap tunnel creation and removal """ @@ -268,11 +271,59 @@ def test_TunnelDecap_MuxTunnel(self, dvs, testlog): "decap_tc_to_pg_map_oid": tc_to_pg_map_oid } self.create_and_test_tunnel(db, asicdb, tunnel_name="MuxTunnel0", **params) + + # Remove Tunnel first + self.remove_and_test_tunnel(db, asicdb,"MuxTunnel0") + + self.remove_qos_map(configdb, swsscommon.CFG_DSCP_TO_TC_MAP_TABLE_NAME, self.TUNNEL_QOS_MAP_NAME) + self.remove_qos_map(configdb, swsscommon.CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, self.TUNNEL_QOS_MAP_NAME) + + def test_TunnelDecap_MuxTunnel_with_retry(self, dvs, testlog): + """ Test MuxTunnel creation. """ + db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + asicdb = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + configdb = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + self.cleanup_left_over(db, asicdb) + # Create MuxTunnel0 with QoS remapping attributes + params = { + "tunnel_type": "IPINIP", + "src_ip": "1.1.1.1", + "dst_ip": "1.1.1.2", + "dscp_mode": "pipe", + "ecn_mode": "copy_from_outer", + "ttl_mode": "uniform", + "decap_dscp_to_tc_map": "AZURE_TUNNEL", + "decap_tc_to_pg_map": "AZURE_TUNNEL", + } + # Verify tunnel is not created when decap_dscp_to_tc_map/decap_tc_to_pg_map is specified while oid is not ready in qosorch + fvs = create_fvs(**params) + # create tunnel entry in DB + ps = swsscommon.ProducerStateTable(db, self.APP_TUNNEL_DECAP_TABLE_NAME) + ps.set("MuxTunnel0", fvs) + + time.sleep(1) + # check asic db table + tunnel_table = swsscommon.Table(asicdb, self.ASIC_TUNNEL_TABLE) + tunnels = tunnel_table.getKeys() + assert len(tunnels) == 0 + + #Verify tunneldecaporch creates tunnel when qos map is available + dscp_to_tc_map_oid = self.add_qos_map(configdb, asicdb, swsscommon.CFG_DSCP_TO_TC_MAP_TABLE_NAME, self.TUNNEL_QOS_MAP_NAME, self.DSCP_TO_TC_MAP) + tc_to_pg_map_oid = self.add_qos_map(configdb, asicdb, swsscommon.CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, self.TUNNEL_QOS_MAP_NAME, self.TC_TO_PRIORITY_GROUP_MAP) + params.update({ + "decap_dscp_to_tc_map_oid": dscp_to_tc_map_oid, + "decap_tc_to_pg_map_oid": tc_to_pg_map_oid, + "skip_tunnel_creation": True + }) + self.create_and_test_tunnel(db, asicdb, tunnel_name="MuxTunnel0", **params) + + # Cleanup + self.remove_and_test_tunnel(db, asicdb,"MuxTunnel0") self.remove_qos_map(configdb, swsscommon.CFG_DSCP_TO_TC_MAP_TABLE_NAME, dscp_to_tc_map_oid) self.remove_qos_map(configdb, swsscommon.CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, tc_to_pg_map_oid) - class TestSymmetricTunnel(TestTunnelBase): """ Tests for symmetric tunnel creation and removal """ diff --git a/tests/test_vnet.py b/tests/test_vnet.py index 39cb648c8c..60a2ed8c33 100644 --- a/tests/test_vnet.py +++ b/tests/test_vnet.py @@ -450,7 +450,7 @@ def get_bfd_session_id(dvs, addr): status, fvs = tbl.get(entry) fvs = dict(fvs) assert status, "Got an error when get a key" - if fvs["SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS"] == addr: + if fvs["SAI_BFD_SESSION_ATTR_DST_IP_ADDRESS"] == addr and fvs["SAI_BFD_SESSION_ATTR_MULTIHOP"] == "true": return entry return None diff --git a/tlm_teamd/Makefile.am b/tlm_teamd/Makefile.am index 6bf7574a8f..1c86c118ee 100644 --- a/tlm_teamd/Makefile.am +++ b/tlm_teamd/Makefile.am @@ -10,10 +10,15 @@ endif tlm_teamd_SOURCES = main.cpp teamdctl_mgr.cpp values_store.cpp -tlm_teamd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -tlm_teamd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(JANSSON_CFLAGS) -tlm_teamd_LDADD = -lhiredis -lswsscommon -lteamdctl $(JANSSON_LIBS) +tlm_teamd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN) +tlm_teamd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(JANSSON_CFLAGS) $(CFLAGS_ASAN) +tlm_teamd_LDADD = $(LDFLAGS_ASAN) -lhiredis -lswsscommon -lteamdctl $(JANSSON_LIBS) if GCOV_ENABLED tlm_teamd_LDADD += -lgcovpreload endif + +if ASAN_ENABLED +tlm_teamd_SOURCES += $(top_srcdir)/lib/asan.cpp +endif +