diff --git a/cfgmgr/sflowmgr.cpp b/cfgmgr/sflowmgr.cpp index a063708c14..122ffc0780 100644 --- a/cfgmgr/sflowmgr.cpp +++ b/cfgmgr/sflowmgr.cpp @@ -10,22 +10,8 @@ using namespace std; using namespace swss; -map sflowSpeedRateInitMap = -{ - {SFLOW_SAMPLE_RATE_KEY_400G, SFLOW_SAMPLE_RATE_VALUE_400G}, - {SFLOW_SAMPLE_RATE_KEY_200G, SFLOW_SAMPLE_RATE_VALUE_200G}, - {SFLOW_SAMPLE_RATE_KEY_100G, SFLOW_SAMPLE_RATE_VALUE_100G}, - {SFLOW_SAMPLE_RATE_KEY_50G, SFLOW_SAMPLE_RATE_VALUE_50G}, - {SFLOW_SAMPLE_RATE_KEY_40G, SFLOW_SAMPLE_RATE_VALUE_40G}, - {SFLOW_SAMPLE_RATE_KEY_25G, SFLOW_SAMPLE_RATE_VALUE_25G}, - {SFLOW_SAMPLE_RATE_KEY_10G, SFLOW_SAMPLE_RATE_VALUE_10G}, - {SFLOW_SAMPLE_RATE_KEY_1G, SFLOW_SAMPLE_RATE_VALUE_1G} -}; - -SflowMgr::SflowMgr(DBConnector *cfgDb, DBConnector *appDb, const vector &tableNames) : - Orch(cfgDb, tableNames), - m_cfgSflowTable(cfgDb, CFG_SFLOW_TABLE_NAME), - m_cfgSflowSessionTable(cfgDb, CFG_SFLOW_SESSION_TABLE_NAME), +SflowMgr::SflowMgr(DBConnector *appDb, const std::vector& tableNames) : + Orch(tableNames), m_appSflowTable(appDb, APP_SFLOW_TABLE_NAME), m_appSflowSessionTable(appDb, APP_SFLOW_SESSION_TABLE_NAME) { @@ -35,6 +21,33 @@ SflowMgr::SflowMgr(DBConnector *cfgDb, DBConnector *appDb, const vector m_intfAllDir = "rx"; } +void SflowMgr::readPortConfig() +{ + auto consumer_it = m_consumerMap.find(CFG_PORT_TABLE_NAME); + if (consumer_it != m_consumerMap.end()) + { + consumer_it->second->drain(); + SWSS_LOG_NOTICE("Port Configuration Read.."); + } + else + { + SWSS_LOG_ERROR("Consumer object for PORT_TABLE not found"); + } +} + +bool SflowMgr::isPortEnabled(const std::string& alias) +{ + /* Checks if the sflow is enabled on the port */ + auto it = m_sflowPortConfMap.find(alias); + if (it == m_sflowPortConfMap.end()) + { + return false; + } + bool local_admin = it->second.local_admin_cfg; + bool status = it->second.admin == "up" ? true : false; + return m_gEnable && (m_intfAllConf || (local_admin && status)); +} + void SflowMgr::sflowHandleService(bool enable) { stringstream cmd; @@ -71,7 +84,6 @@ void SflowMgr::sflowUpdatePortInfo(Consumer &consumer) while (it != consumer.m_toSync.end()) { KeyOpFieldsValuesTuple t = it->second; - string key = kfvKey(t); string op = kfvOp(t); auto values = kfvFieldsValues(t); @@ -87,16 +99,17 @@ void SflowMgr::sflowUpdatePortInfo(Consumer &consumer) new_port = true; port_info.local_rate_cfg = false; port_info.local_admin_cfg = false; + port_info.speed = ERROR_SPEED; + port_info.oper_speed = NA_SPEED; port_info.local_dir_cfg = false; - port_info.speed = SFLOW_ERROR_SPEED_STR; port_info.rate = ""; port_info.admin = ""; port_info.dir = ""; m_sflowPortConfMap[key] = port_info; } - bool speed_change = false; - string new_speed = SFLOW_ERROR_SPEED_STR; + bool rate_update = false; + string new_speed = ERROR_SPEED; for (auto i : values) { if (fvField(i) == "speed") @@ -107,7 +120,11 @@ void SflowMgr::sflowUpdatePortInfo(Consumer &consumer) if (m_sflowPortConfMap[key].speed != new_speed) { m_sflowPortConfMap[key].speed = new_speed; - speed_change = true; + /* if oper_speed is set, no need to write to APP_DB */ + if (m_sflowPortConfMap[key].oper_speed == NA_SPEED) + { + rate_update = true; + } } string def_dir = "rx"; @@ -116,13 +133,13 @@ void SflowMgr::sflowUpdatePortInfo(Consumer &consumer) m_sflowPortConfMap[key].dir = def_dir; } - if (m_gEnable && m_intfAllConf) + if (isPortEnabled(key)) { - // If the Local rate Conf is already present, dont't override it even though the speed is changed - if (new_port || (speed_change && !m_sflowPortConfMap[key].local_rate_cfg)) + // If the Local rate conf is already present, dont't override it even though the speed is changed + if (new_port || (rate_update && !m_sflowPortConfMap[key].local_rate_cfg)) { vector fvs; - sflowGetGlobalInfo(fvs, m_sflowPortConfMap[key].speed, m_sflowPortConfMap[key].dir); + sflowGetGlobalInfo(fvs, key, m_sflowPortConfMap[key].dir); m_appSflowSessionTable.set(key, fvs); } } @@ -147,6 +164,59 @@ void SflowMgr::sflowUpdatePortInfo(Consumer &consumer) } } +void SflowMgr::sflowProcessOperSpeed(Consumer &consumer) +{ + auto it = consumer.m_toSync.begin(); + + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string alias = kfvKey(t); + string op = kfvOp(t); + auto values = kfvFieldsValues(t); + string oper_speed = ""; + bool rate_update = false; + + for (auto i : values) + { + if (fvField(i) == "speed") + { + oper_speed = fvValue(i); + } + } + + if (m_sflowPortConfMap.find(alias) != m_sflowPortConfMap.end() && op == SET_COMMAND) + { + SWSS_LOG_DEBUG("STATE_DB update: iface: %s, oper_speed: %s, cfg_speed: %s, new_speed: %s", + alias.c_str(), m_sflowPortConfMap[alias].oper_speed.c_str(), + m_sflowPortConfMap[alias].speed.c_str(), + oper_speed.c_str()); + /* oper_speed is updated by orchagent if the vendor supports and oper status is up */ + if (m_sflowPortConfMap[alias].oper_speed != oper_speed && !oper_speed.empty()) + { + rate_update = true; + if (oper_speed == m_sflowPortConfMap[alias].speed && m_sflowPortConfMap[alias].oper_speed == NA_SPEED) + { + /* if oper_speed is equal to cfg_speed, avoid the write to APP_DB + Can happen if auto-neg is not set */ + rate_update = false; + } + m_sflowPortConfMap[alias].oper_speed = oper_speed; + } + + if (isPortEnabled(alias) && rate_update && !m_sflowPortConfMap[alias].local_rate_cfg) + { + vector fvs; + sflowGetGlobalInfo(fvs, alias, m_sflowPortConfMap[alias].dir); + m_appSflowSessionTable.set(alias, fvs); + SWSS_LOG_NOTICE("Default sampling rate for %s updated to %s", alias.c_str(), findSamplingRate(alias).c_str()); + } + } + /* Do nothing for DEL as the SflowPortConfMap will already be cleared by the DEL from CONFIG_DB */ + it = consumer.m_toSync.erase(it); + } +} + void SflowMgr::sflowHandleSessionAll(bool enable, string direction) { for (auto it: m_sflowPortConfMap) @@ -171,7 +241,7 @@ void SflowMgr::sflowHandleSessionAll(bool enable, string direction) } else { - sflowGetGlobalInfo(fvs, it.second.speed, direction); + sflowGetGlobalInfo(fvs, it.first, direction); } m_appSflowSessionTable.set(it.first, fvs); } @@ -202,21 +272,12 @@ void SflowMgr::sflowHandleSessionLocal(bool enable) } } -void SflowMgr::sflowGetGlobalInfo(vector &fvs, string speed, string dir) +void SflowMgr::sflowGetGlobalInfo(vector &fvs, const string& alias, const string& dir) { - string rate; FieldValueTuple fv1("admin_state", "up"); fvs.push_back(fv1); - if (speed != SFLOW_ERROR_SPEED_STR && sflowSpeedRateInitMap.find(speed) != sflowSpeedRateInitMap.end()) - { - rate = sflowSpeedRateInitMap[speed]; - } - else - { - rate = SFLOW_ERROR_SPEED_STR; - } - FieldValueTuple fv2("sample_rate",rate); + FieldValueTuple fv2("sample_rate", findSamplingRate(alias)); fvs.push_back(fv2); FieldValueTuple fv3("sample_direction",dir); @@ -289,17 +350,7 @@ void SflowMgr::sflowCheckAndFillValues(string alias, vector &va if (m_sflowPortConfMap[alias].rate == "" || m_sflowPortConfMap[alias].local_rate_cfg) { - string speed = m_sflowPortConfMap[alias].speed; - - if (speed != SFLOW_ERROR_SPEED_STR && sflowSpeedRateInitMap.find(speed) != sflowSpeedRateInitMap.end()) - { - rate = sflowSpeedRateInitMap[speed]; - } - else - { - rate = SFLOW_ERROR_SPEED_STR; - } - m_sflowPortConfMap[alias].rate = rate; + m_sflowPortConfMap[alias].rate = findSamplingRate(alias); } m_sflowPortConfMap[alias].local_rate_cfg = false; FieldValueTuple fv("sample_rate", m_sflowPortConfMap[alias].rate); @@ -331,6 +382,24 @@ void SflowMgr::sflowCheckAndFillValues(string alias, vector &va } } +string SflowMgr::findSamplingRate(const string& alias) +{ + /* Default sampling rate is equal to the oper_speed, if present + if oper_speed is not found, use the configured speed */ + if (m_sflowPortConfMap.find(alias) == m_sflowPortConfMap.end()) + { + SWSS_LOG_ERROR("%s not found in port configuration map", alias.c_str()); + return ERROR_SPEED; + } + string oper_speed = m_sflowPortConfMap[alias].oper_speed; + string cfg_speed = m_sflowPortConfMap[alias].speed; + if (!oper_speed.empty() && oper_speed != NA_SPEED) + { + return oper_speed; + } + return cfg_speed; +} + void SflowMgr::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -342,6 +411,11 @@ void SflowMgr::doTask(Consumer &consumer) sflowUpdatePortInfo(consumer); return; } + else if (table == STATE_PORT_TABLE_NAME) + { + sflowProcessOperSpeed(consumer); + return; + } auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) @@ -502,7 +576,7 @@ void SflowMgr::doTask(Consumer &consumer) if (m_intfAllConf) { vector fvs; - sflowGetGlobalInfo(fvs, m_sflowPortConfMap[key].speed, m_intfAllDir); + sflowGetGlobalInfo(fvs, key, m_intfAllDir); m_appSflowSessionTable.set(key,fvs); } } diff --git a/cfgmgr/sflowmgr.h b/cfgmgr/sflowmgr.h index 8f13266f6f..5cdc231d79 100644 --- a/cfgmgr/sflowmgr.h +++ b/cfgmgr/sflowmgr.h @@ -10,25 +10,8 @@ namespace swss { -#define SFLOW_SAMPLE_RATE_KEY_400G "400000" -#define SFLOW_SAMPLE_RATE_KEY_200G "200000" -#define SFLOW_SAMPLE_RATE_KEY_100G "100000" -#define SFLOW_SAMPLE_RATE_KEY_50G "50000" -#define SFLOW_SAMPLE_RATE_KEY_40G "40000" -#define SFLOW_SAMPLE_RATE_KEY_25G "25000" -#define SFLOW_SAMPLE_RATE_KEY_10G "10000" -#define SFLOW_SAMPLE_RATE_KEY_1G "1000" - -#define SFLOW_SAMPLE_RATE_VALUE_400G "400000" -#define SFLOW_SAMPLE_RATE_VALUE_200G "200000" -#define SFLOW_SAMPLE_RATE_VALUE_100G "100000" -#define SFLOW_SAMPLE_RATE_VALUE_50G "50000" -#define SFLOW_SAMPLE_RATE_VALUE_40G "40000" -#define SFLOW_SAMPLE_RATE_VALUE_25G "25000" -#define SFLOW_SAMPLE_RATE_VALUE_10G "10000" -#define SFLOW_SAMPLE_RATE_VALUE_1G "1000" - -#define SFLOW_ERROR_SPEED_STR "error" +#define ERROR_SPEED "error" +#define NA_SPEED "N/A" struct SflowPortInfo { @@ -36,6 +19,7 @@ struct SflowPortInfo bool local_admin_cfg; bool local_dir_cfg; std::string speed; + std::string oper_speed; std::string rate; std::string admin; std::string dir; @@ -47,15 +31,14 @@ typedef std::map SflowPortConfMap; class SflowMgr : public Orch { public: - SflowMgr(DBConnector *cfgDb, DBConnector *appDb, const std::vector &tableNames); + SflowMgr(DBConnector *appDb, const std::vector& tableNames); + void readPortConfig(); using Orch::doTask; private: - Table m_cfgSflowTable; - Table m_cfgSflowSessionTable; ProducerStateTable m_appSflowTable; ProducerStateTable m_appSflowSessionTable; - SflowPortConfMap m_sflowPortConfMap; + SflowPortConfMap m_sflowPortConfMap; bool m_intfAllConf; bool m_gEnable; std::string m_intfAllDir; @@ -64,11 +47,14 @@ class SflowMgr : public Orch void doTask(Consumer &consumer); void sflowHandleService(bool enable); void sflowUpdatePortInfo(Consumer &consumer); + void sflowProcessOperSpeed(Consumer &consumer); void sflowHandleSessionAll(bool enable, std::string direction); void sflowHandleSessionLocal(bool enable); void sflowCheckAndFillValues(std::string alias, std::vector &values, std::vector &fvs); void sflowGetPortInfo(std::vector &fvs, SflowPortInfo &local_info); - void sflowGetGlobalInfo(std::vector &fvs, std::string speed, std::string direction); + void sflowGetGlobalInfo(std::vector &fvs, const std::string& alias, const std::string& direction); + bool isPortEnabled(const std::string& alias); + std::string findSamplingRate(const std::string& speed); }; } diff --git a/cfgmgr/sflowmgrd.cpp b/cfgmgr/sflowmgrd.cpp index 7de5f15a2d..4672d04a42 100644 --- a/cfgmgr/sflowmgrd.cpp +++ b/cfgmgr/sflowmgrd.cpp @@ -44,21 +44,31 @@ int main(int argc, char **argv) try { - vector cfg_sflow_tables = { - CFG_SFLOW_TABLE_NAME, - CFG_SFLOW_SESSION_TABLE_NAME, - CFG_PORT_TABLE_NAME - }; - DBConnector cfgDb("CONFIG_DB", 0); DBConnector appDb("APPL_DB", 0); + DBConnector stateDb("STATE_DB", 0); + + TableConnector conf_port_table(&cfgDb, CFG_PORT_TABLE_NAME); + TableConnector state_port_table(&stateDb, STATE_PORT_TABLE_NAME); + TableConnector conf_sflow_table(&cfgDb, CFG_SFLOW_TABLE_NAME); + TableConnector conf_sflow_session_table(&cfgDb, CFG_SFLOW_SESSION_TABLE_NAME); + + vector sflow_tables = { + conf_port_table, + state_port_table, + conf_sflow_table, + conf_sflow_session_table + }; - SflowMgr sflowmgr(&cfgDb, &appDb, cfg_sflow_tables); + SflowMgr sflowmgr(&appDb, sflow_tables); + /* During process startup, the ordering of config_db followed by state_db notifications cannot be guaranteed + and so handle the config events manually */ + sflowmgr.readPortConfig(); - vector cfgOrchList = {&sflowmgr}; + vector orchList = {&sflowmgr}; swss::Select s; - for (Orch *o : cfgOrchList) + for (Orch *o : orchList) { s.addSelectables(o->getSelectables()); } diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 3741e7da27..fd8982eae8 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -45,6 +45,7 @@ tests_SOURCES = aclorch_ut.cpp \ mock_redisreply.cpp \ bulker_ut.cpp \ portmgr_ut.cpp \ + sflowmgrd_ut.cpp \ fake_response_publisher.cpp \ swssnet_ut.cpp \ flowcounterrouteorch_ut.cpp \ @@ -109,6 +110,7 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/srv6orch.cpp \ $(top_srcdir)/orchagent/nvgreorch.cpp \ $(top_srcdir)/cfgmgr/portmgr.cpp \ + $(top_srcdir)/cfgmgr/sflowmgr.cpp \ $(top_srcdir)/cfgmgr/buffermgrdyn.cpp \ $(top_srcdir)/warmrestart/warmRestartAssist.cpp diff --git a/tests/mock_tests/sflowmgrd_ut.cpp b/tests/mock_tests/sflowmgrd_ut.cpp new file mode 100644 index 0000000000..7e47b162f2 --- /dev/null +++ b/tests/mock_tests/sflowmgrd_ut.cpp @@ -0,0 +1,320 @@ +#include "gtest/gtest.h" +#include "mock_table.h" +#include "redisutility.h" +#include "sflowmgr.h" + +namespace sflowmgr_ut +{ + using namespace swss; + using namespace std; + + struct SflowMgrTest : public ::testing::Test + { + shared_ptr m_app_db; + shared_ptr m_config_db; + shared_ptr m_state_db; + shared_ptr m_sflowMgr; + SflowMgrTest() + { + m_app_db = make_shared( + "APPL_DB", 0); + m_config_db = make_shared( + "CONFIG_DB", 0); + m_state_db = make_shared( + "STATE_DB", 0); + } + + virtual void SetUp() override + { + ::testing_db::reset(); + TableConnector conf_port_table(m_config_db.get(), CFG_PORT_TABLE_NAME); + TableConnector state_port_table(m_state_db.get(), STATE_PORT_TABLE_NAME); + TableConnector conf_sflow_table(m_config_db.get(), CFG_SFLOW_TABLE_NAME); + TableConnector conf_sflow_session_table(m_config_db.get(), CFG_SFLOW_SESSION_TABLE_NAME); + + vector sflow_tables = { + conf_port_table, + state_port_table, + conf_sflow_table, + conf_sflow_session_table + }; + m_sflowMgr.reset(new SflowMgr(m_app_db.get(), sflow_tables)); + } + + void enableSflow() + { + Table cfg_sflow(m_config_db.get(), CFG_SFLOW_TABLE_NAME); + cfg_sflow.set("global", { + {"admin_state", "up"} + }); + m_sflowMgr->addExistingData(&cfg_sflow); + m_sflowMgr->doTask(); + } + + void cfgSflowSession(string alias, bool status, string sample_rate, string direction = "") + { + Table cfg_sflow_table(m_config_db.get(), CFG_SFLOW_SESSION_TABLE_NAME); + vector values; + values.emplace_back("admin_state", status ? "up" : "down"); + if (!sample_rate.empty()) + { + values.emplace_back("sample_rate", sample_rate); + } + if (!direction.empty()) + { + values.emplace_back("sample_direction", direction); + } + cfg_sflow_table.set(alias, values); + m_sflowMgr->addExistingData(&cfg_sflow_table); + m_sflowMgr->doTask(); + } + + void cfgSflowSessionAll(bool status) + { + Table cfg_sflow_table(m_config_db.get(), CFG_SFLOW_SESSION_TABLE_NAME); + cfg_sflow_table.set("all", { + {"admin_state", status ? "up" : "down"}, + }); + m_sflowMgr->addExistingData(&cfg_sflow_table); + m_sflowMgr->doTask(); + } + + void cfgPortSpeed(string alias, string speed) + { + Table cfg_port_table(m_config_db.get(), CFG_PORT_TABLE_NAME); + cfg_port_table.set(alias, { + {"speed", speed} + }); + m_sflowMgr->addExistingData(&cfg_port_table); + m_sflowMgr->doTask(); + } + + void statePortSpeed(string alias, string speed) + { + Table state_port_table(m_config_db.get(), STATE_PORT_TABLE_NAME); + state_port_table.set(alias, { + {"speed", speed} + }); + m_sflowMgr->addExistingData(&state_port_table); + m_sflowMgr->doTask(); + } + + string getSflowSampleRate(string alias) + { + Table appl_sflow_table(m_app_db.get(), APP_SFLOW_SESSION_TABLE_NAME); + std::vector values; + appl_sflow_table.get(alias, values); + auto value_rate = swss::fvsGetValue(values, "sample_rate", true); + if (value_rate) + { + string ret = value_rate.get(); + return ret; + } + return ""; + } + + string getSflowSampleDir(string alias) + { + Table appl_sflow_table(m_app_db.get(), APP_SFLOW_SESSION_TABLE_NAME); + std::vector values; + appl_sflow_table.get(alias, values); + auto value_rate = swss::fvsGetValue(values, "sample_direction", true); + if (value_rate) + { + string ret = value_rate.get(); + return ret; + } + return ""; + } + + string getSflowAdminStatus(string alias) + { + Table appl_sflow_table(m_app_db.get(), APP_SFLOW_SESSION_TABLE_NAME); + std::vector values; + appl_sflow_table.get(alias, values); + auto value_rate = swss::fvsGetValue(values, "admin_state", true); + if (value_rate) + { + string ret = value_rate.get(); + return ret; + } + return "down"; + } + }; + + TEST_F(SflowMgrTest, test_RateConfiguration) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + + /* Scenario: Operational Speed Changes to 25000 */ + statePortSpeed("Ethernet0", "25000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "25000"); + ASSERT_TRUE(getSflowSampleDir("Ethernet0") == "rx"); + } + + TEST_F(SflowMgrTest, test_RateConfigurationCfgSpeed) + { + enableSflow(); + /* Configure the Speed to 100G */ + cfgPortSpeed("Ethernet0", "100000"); + + /* Scenario: Operational Speed Changes to 100G with autoneg */ + statePortSpeed("Ethernet0", "100000"); + + /* User changes the config speed to 10G */ + cfgPortSpeed("Ethernet0", "10000"); + + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + + /* Scenario: Operational Speed Changes to 10G, with autoneg */ + statePortSpeed("Ethernet0", "10000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "10000"); + + /* Configured speed is updated by user */ + cfgPortSpeed("Ethernet0", "200000"); + + /* Sampling Rate will not be updated */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "10000"); + } + + TEST_F(SflowMgrTest, test_OnlyStateDbNotif) + { + enableSflow(); + statePortSpeed("Ethernet0", "100000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == ""); + } + + TEST_F(SflowMgrTest, test_LocalRateConfiguration) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + cfgSflowSession("Ethernet0", true, "12345"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "12345"); + } + + TEST_F(SflowMgrTest, test_LocalRateConfWithOperSpeed) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + + /* Scenario: Operational Speed Changes to 25000 */ + statePortSpeed("Ethernet0", "25000"); + + /* Set per interface sampling rate*/ + cfgSflowSession("Ethernet0", true, "12345"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "12345"); + + /* Operational Speed Changes again to 50000 */ + statePortSpeed("Ethernet0", "50000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "12345"); + } + + TEST_F(SflowMgrTest, test_newSpeed) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "800000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "800000"); + } + + TEST_F(SflowMgrTest, test_CfgSpeedAdminCfg) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + cfgSflowSessionAll(false); /* Disable sflow on all interfaces*/ + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "down"); + cfgSflowSession("Ethernet0", true, ""); /* Set local admin up with no rate */ + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + + /* Sampling rate should adhere to config speed*/ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + + cfgPortSpeed("Ethernet0", "25000"); /* Change cfg speed */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "25000"); + } + + TEST_F(SflowMgrTest, test_OperSpeedAdminCfg) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + cfgSflowSessionAll(false); /* Disable sflow on all interfaces*/ + cfgSflowSession("Ethernet0", true, ""); /* Set local admin up with no rate */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + + statePortSpeed("Ethernet0", "50000"); + /* Sampling rate should adhere to oper speed*/ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "50000"); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + + /* Change cfg speed */ + cfgPortSpeed("Ethernet0", "25000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "50000"); + + statePortSpeed("Ethernet0", "1000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "1000"); + + cfgSflowSession("Ethernet0", true, "12345"); /* Set local sampling rate */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "12345"); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + + /* Change oper speed now */ + statePortSpeed("Ethernet0", "12345"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "12345"); + } + + TEST_F(SflowMgrTest, test_SflowCfgAfterPortCfg) + { + cfgPortSpeed("Ethernet0", "100000"); + /* Nothing is written yet since cfg is not enabled */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == ""); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "down"); + + /* State DB is updated with oper speed */ + statePortSpeed("Ethernet0", "100000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == ""); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "down"); + + /* enable sflow */ + enableSflow(); + cfgSflowSessionAll(true); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + ASSERT_TRUE(getSflowSampleDir("Ethernet0") == "rx"); + } + + TEST_F(SflowMgrTest, test_SflowCfgAfterOperSpeed) + { + cfgPortSpeed("Ethernet0", "100000"); + /* Nothing is written yet since cfg is not enabled */ + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == ""); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "down"); + + /* State DB is updated with oper speed */ + statePortSpeed("Ethernet0", "50000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == ""); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "down"); + + /* enable sflow */ + cfgSflowSessionAll(true); + enableSflow(); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "50000"); + ASSERT_TRUE(getSflowAdminStatus("Ethernet0") == "up"); + ASSERT_TRUE(getSflowSampleDir("Ethernet0") == "rx"); + } + + TEST_F(SflowMgrTest, test_RateConfigEgressDir) + { + enableSflow(); + cfgPortSpeed("Ethernet0", "100000"); + /* Set local admin up with no rate and no egress direction */ + cfgSflowSession("Ethernet0", true, "", "tx"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "100000"); + + /* Scenario: Operational Speed Changes to 25000 */ + statePortSpeed("Ethernet0", "25000"); + ASSERT_TRUE(getSflowSampleRate("Ethernet0") == "25000"); + ASSERT_TRUE(getSflowSampleDir("Ethernet0") == "tx"); + } +}