From e28c83d2fc7a845c09d6b5e59743116f744efc9a Mon Sep 17 00:00:00 2001 From: Prince George Date: Sat, 17 Feb 2024 16:45:26 +0000 Subject: [PATCH] Add port flap count and last flap timestamp Signed-off-by: Prince George --- orchagent/port.h | 1 + orchagent/portsorch.cpp | 56 +++++++++++++++++++++++++++++++++++++++-- orchagent/portsorch.h | 2 ++ tests/test_port.py | 50 ++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/orchagent/port.h b/orchagent/port.h index f6b598edeb9..f549ff04ae6 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -164,6 +164,7 @@ class Port uint32_t m_nat_zone_id = 0; uint32_t m_vnid = VNID_NONE; uint32_t m_fdb_count = 0; + uint32_t m_flap_count = 0; uint32_t m_up_member_count = 0; uint32_t m_maximum_headroom = 0; std::set m_adv_speeds; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index abfa9d5ee9e..35c006c10c6 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3074,6 +3074,38 @@ bool PortsOrch::removeVlanHostIntf(Port vl) return true; } +void PortsOrch::updateDbPortFlapCount(Port& port, sai_port_oper_status_t pstatus) +{ + SWSS_LOG_ENTER(); + + ++port.m_flap_count; + vector tuples; + FieldValueTuple tuple("flap_count", std::to_string(port.m_flap_count)); + tuples.push_back(tuple); + m_portTable->set(port.m_alias, tuples); + + if (pstatus == SAI_PORT_OPER_STATUS_DOWN) + { + vector tuples; + auto now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + FieldValueTuple tuple("last_down_time", std::ctime(&now_c)); + tuples.push_back(tuple); + m_portTable->set(port.m_alias, tuples); + } + + if (pstatus == SAI_PORT_OPER_STATUS_UP) + { + vector tuples; + auto now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + FieldValueTuple tuple("last_up_time", std::ctime(&now_c)); + tuples.push_back(tuple); + m_portTable->set(port.m_alias, tuples); + } +} + + void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const { SWSS_LOG_ENTER(); @@ -5282,7 +5314,7 @@ bool PortsOrch::initializePort(Port &port) /* Check warm start states */ vector tuples; bool exist = m_portTable->get(port.m_alias, tuples); - string operStatus; + string operStatus, flapCount = "0"; if (exist) { for (auto i : tuples) @@ -5291,9 +5323,14 @@ bool PortsOrch::initializePort(Port &port) { operStatus = fvValue(i); } + + if (fvField(i) == "flap_count") + { + flapCount = fvValue(i); + } } } - SWSS_LOG_DEBUG("initializePort %s with oper %s", port.m_alias.c_str(), operStatus.c_str()); + SWSS_LOG_NOTICE("Port %s with oper %s flap_count=%s", port.m_alias.c_str(), operStatus.c_str(), flapCount.c_str()); /** * Create database port oper status as DOWN if attr missing @@ -5314,6 +5351,20 @@ bool PortsOrch::initializePort(Port &port) port.m_oper_status = SAI_PORT_OPER_STATUS_DOWN; } + // initalize port flap count + if (!flapCount.empty()) + { + try + { + port.m_flap_count = to_uint(flapCount); + } + catch (const std::exception &e) + { + SWSS_LOG_ERROR("Failed to get port (%s) flap_count: %s", port.m_alias.c_str(), e.what()); + } + m_portTable->hset(port.m_alias, "flap_count", flapCount); + } + /* initialize port admin status */ if (!getPortAdminStatus(port.m_port_id, port.m_admin_state_up)) { @@ -7545,6 +7596,7 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) if (port.m_type == Port::PHY) { updateDbPortOperStatus(port, status); + updateDbPortFlapCount(port, status); updateGearboxPortOperStatus(port); /* Refresh the port states and reschedule the poller tasks */ diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index cc71c056b4b..ba15e6bc4bf 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -146,6 +146,8 @@ class PortsOrch : public Orch, public Subject bool setHostIntfsOperStatus(const Port& port, bool up) const; void updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const; + void updateDbPortFlapCount(Port& port, sai_port_oper_status_t pstatus); + bool createVlanHostIntf(Port& vl, string hostif_name); bool removeVlanHostIntf(Port vl); diff --git a/tests/test_port.py b/tests/test_port.py index 3853a61ffe0..30e647c4756 100644 --- a/tests/test_port.py +++ b/tests/test_port.py @@ -58,6 +58,56 @@ def test_PortMtu(self, dvs, testlog): if fv[0] == "mtu": assert fv[1] == "9100" + def test_PortFlapCount(self, dvs, testlog): + def get_port_flapcount(dvs): + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, "PORT_TABLE") + (status, fvs) = tbl.get("Ethernet0") + assert status == True + fcount = 0 + + for v in fvs: + if v[0] == "flap_count": + fcount = v[1] + break + return fcount + + def port_change_admin_status(dvs, op_status): + dvs.servers[0].runcmd("ip link set {} dev eth0".format(op_status)) == 0 + time.sleep(1) + + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, "PORT_TABLE") + (status, fvs) = tbl.get("Ethernet0") + assert status == True + + oper_status = "unknown" + for v in fvs: + if v[0] == "oper_status": + oper_status = v[1] + break + + assert oper_status == op_status + + dvs.port_admin_set("Ethernet0", "up") + dvs.interface_ip_add("Ethernet0", "10.0.0.0/31") + dvs.port_admin_set("Ethernet4", "up") + dvs.interface_ip_add("Ethernet4", "10.0.0.2/31") + # Init the flap_count = 0 + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, "PORT_TABLE") + fvs = swsscommon.FieldValuePairs([("flap_count", "0")]) + tbl.set("Ethernet0", fvs) + + port_change_admin_status(dvs, "down") + assert 1 == get_port_flapcount(dvs) + port_change_admin_status(dvs, "up") + assert 2 == get_port_flapcount(dvs) + port_change_admin_status(dvs, "down") + assert 3 == get_port_flapcount(dvs) + port_change_admin_status(dvs, "up") + assert 4 == get_port_flapcount(dvs) + def test_PortNotification(self, dvs, testlog): dvs.port_admin_set("Ethernet0", "up") dvs.interface_ip_add("Ethernet0", "10.0.0.0/31")