Skip to content

Commit bb161df

Browse files
committed
Added remove_stale_transceiver_info function
1 parent a0f158f commit bb161df

File tree

3 files changed

+105
-9
lines changed

3 files changed

+105
-9
lines changed

sonic-xcvrd/tests/test_xcvrd.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,50 @@ def mock_get_sfp(port):
18991899
assert sfp_obj_dict[1] == mock_sfp_obj_1
19001900
assert sfp_obj_dict[2] == mock_sfp_obj_2
19011901

1902+
@pytest.mark.parametrize(
1903+
"logical_ports, transceiver_presence, expected_removed_ports",
1904+
[
1905+
# Test case 1: No transceivers are present
1906+
(["Ethernet0", "Ethernet1"], [False, False], ["Ethernet0", "Ethernet1"]),
1907+
# Test case 2: Some transceivers are present
1908+
(["Ethernet0", "Ethernet1"], [True, False], ["Ethernet1"]),
1909+
# Test case 3: All transceivers are present
1910+
(["Ethernet0", "Ethernet1"], [True, True], []),
1911+
# Test case 4: No logical ports
1912+
([], [], []),
1913+
],
1914+
)
1915+
@patch('xcvrd.xcvrd.del_port_sfp_dom_info_from_db')
1916+
@patch('xcvrd.xcvrd._wrapper_get_presence')
1917+
def test_remove_stale_transceiver_info(self, mock_get_presence, mock_del_port_sfp_dom_info_from_db,
1918+
logical_ports, transceiver_presence, expected_removed_ports):
1919+
# Mock the DaemonXcvrd class and its dependencies
1920+
mock_xcvrd = DaemonXcvrd(SYSLOG_IDENTIFIER)
1921+
mock_port_mapping_data = MagicMock()
1922+
mock_xcvrd.xcvr_table_helper = MagicMock()
1923+
mock_xcvrd.xcvr_table_helper.get_intf_tbl.return_value = MagicMock()
1924+
1925+
# Mock logical ports and their mappings
1926+
mock_port_mapping_data.logical_port_list = logical_ports
1927+
mock_port_mapping_data.get_asic_id_for_logical_port.side_effect = lambda port: 0
1928+
mock_port_mapping_data.get_logical_to_physical.side_effect = lambda port: [logical_ports.index(port)]
1929+
1930+
mock_get_presence.side_effect = lambda physical_port: transceiver_presence[physical_port]
1931+
1932+
# Mock the interface table
1933+
mock_intf_tbl = mock_xcvrd.xcvr_table_helper.get_intf_tbl.return_value
1934+
mock_intf_tbl.get.side_effect = lambda port: (port in logical_ports, None)
1935+
1936+
# Call the function
1937+
mock_xcvrd.remove_stale_transceiver_info(mock_port_mapping_data)
1938+
1939+
# Verify that the correct ports were removed
1940+
for port in logical_ports:
1941+
if port in expected_removed_ports:
1942+
mock_del_port_sfp_dom_info_from_db.assert_any_call(port, mock_port_mapping_data, [mock_intf_tbl])
1943+
else:
1944+
assert (port, mock_port_mapping_data, [mock_intf_tbl]) not in mock_del_port_sfp_dom_info_from_db.call_args_list
1945+
19021946
@patch('xcvrd.xcvrd.DaemonXcvrd.init')
19031947
@patch('xcvrd.xcvrd.DaemonXcvrd.deinit')
19041948
@patch('xcvrd.xcvrd.DomInfoUpdateTask.start')
@@ -4149,6 +4193,7 @@ def test_DaemonXcvrd_init_deinit_fastboot_enabled(self):
41494193
with patch("subprocess.check_output") as mock_run:
41504194
mock_run.return_value = "true"
41514195
xcvrd.initialize_port_init_control_fields_in_port_table = MagicMock()
4196+
xcvrd.remove_stale_transceiver_info = MagicMock()
41524197

41534198
xcvrd.init()
41544199

@@ -4191,6 +4236,7 @@ def test_DaemonXcvrd_init_deinit_cold(self):
41914236
with patch("subprocess.check_output") as mock_run:
41924237
mock_run.return_value = "false"
41934238
xcvrdaemon.initialize_port_init_control_fields_in_port_table = MagicMock()
4239+
xcvrdaemon.remove_stale_transceiver_info = MagicMock()
41944240

41954241
xcvrdaemon.init()
41964242

sonic-xcvrd/xcvrd/dom/utilities/db/utils.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import time
1+
from datetime import datetime
22
from swsscommon import swsscommon
33
from xcvrd.xcvrd_utilities.utils import XCVRDUtils
44

@@ -84,9 +84,13 @@ def update_flag_metadata_tables(self, logical_port_name, curr_flag_dict,
8484
flag_change_count_table, flag_last_set_time_table, flag_last_clear_time_table,
8585
table_name_for_logging):
8686
"""
87-
Updates the metadata tables for flag table.
88-
Compares the current flag values with the database values and updates the metadata accordingly based on the changes
89-
between the two.
87+
Updates the metadata tables for a flag table.
88+
89+
This method compares the current flag values with the values stored in the database.
90+
If there are changes, it updates the metadata tables accordingly, including:
91+
- Change count
92+
- Last set time
93+
- Last clear time
9094
9195
Args:
9296
logical_port_name (str): Logical port name.
@@ -128,11 +132,17 @@ def beautify_info_dict(self, info_dict):
128132
if not isinstance(v, str):
129133
info_dict[k] = str(v)
130134

131-
def get_current_time(self):
132-
""""
133-
Returns the current time in the format "Day Mon DD HH:MM:SS YYYY" (local time)
135+
def get_current_time(self, time_format="%a %b %d %H:%M:%S %Y"):
136+
"""
137+
Returns the current time in the specified format (UTC time).
138+
139+
Args:
140+
time_format (str): The format in which to return the time. Defaults to "Day Mon DD HH:MM:SS YYYY".
141+
142+
Returns:
143+
str: The current time in UTC.
134144
"""
135-
return time.strftime("%a %b %d %H:%M:%S %Y", time.localtime())
145+
return datetime.utcnow().strftime(time_format)
136146

137147
def _initialize_metadata_tables(self, logical_port_name, curr_flag_dict,
138148
flag_change_count_table, flag_last_set_time_table,

sonic-xcvrd/xcvrd/xcvrd.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ def task_worker(self):
11011101

11021102
# double-check the HW presence before moving forward
11031103
sfp = platform_chassis.get_sfp(pport)
1104-
if not sfp.get_presence():
1104+
if not _wrapper_get_presence(pport):
11051105
self.update_port_transceiver_status_table_sw_cmis_state(lport, CMIS_STATE_REMOVED)
11061106
continue
11071107

@@ -2132,6 +2132,40 @@ def initialize_sfp_obj_dict(self, port_mapping_data):
21322132

21332133
return sfp_obj_dict
21342134

2135+
def remove_stale_transceiver_info(self, port_mapping_data):
2136+
"""
2137+
Remove stale entries from the TRANSCEIVER_INFO table for ports where the transceiver is no longer present.
2138+
2139+
This function iterates through all logical ports in the provided port mapping data. For each port:
2140+
- It checks if the TRANSCEIVER_INFO table entry exists.
2141+
- If the entry exists and the transceiver is absent, the entry is removed from the table.
2142+
2143+
Args:
2144+
port_mapping_data (PortMapping): The port mapping data containing logical-to-physical port mappings.
2145+
2146+
Returns:
2147+
None
2148+
"""
2149+
logical_port_list = port_mapping_data.logical_port_list
2150+
for lport in logical_port_list:
2151+
asic_index = port_mapping_data.get_asic_id_for_logical_port(lport)
2152+
intf_tbl = self.xcvr_table_helper.get_intf_tbl(asic_index)
2153+
if not intf_tbl:
2154+
continue
2155+
2156+
found, _ = intf_tbl.get(lport)
2157+
if found:
2158+
# If transceiver is absent, remove the entry from TRANSCEIVER_INFO table
2159+
pport_list = port_mapping_data.get_logical_to_physical(lport)
2160+
if not pport_list:
2161+
self.log_error(f"Remove stale transceiver info: No physical port found for lport {lport}")
2162+
continue
2163+
pport = pport_list[0]
2164+
2165+
if not _wrapper_get_presence(pport):
2166+
self.log_notice(f"Remove stale transceiver info: Transceiver is absent for lport {lport}")
2167+
del_port_sfp_dom_info_from_db(lport, port_mapping_data, [intf_tbl])
2168+
21352169
# Initialize daemon
21362170
def init(self):
21372171
global platform_sfputil
@@ -2182,6 +2216,12 @@ def init(self):
21822216
self.initialize_port_init_control_fields_in_port_table(port_mapping_data)
21832217
self.sfp_obj_dict = self.initialize_sfp_obj_dict(port_mapping_data)
21842218

2219+
# Remove the TRANSCEIVER_INFO table if the transceiver is absent.
2220+
# This ensures stale entries are cleaned up when a transceiver is removed while xcvrd is not running.
2221+
# Performed in the init() method to ensure the table is cleared before starting child threads.
2222+
# Note: Other transceiver-related tables are cleared during xcvrd deinitialization.
2223+
self.remove_stale_transceiver_info(port_mapping_data)
2224+
21852225
return port_mapping_data
21862226

21872227
# Deinitialize daemon

0 commit comments

Comments
 (0)