Skip to content

Commit 8a8efc6

Browse files
committed
Merge branch 'master' of https://github.com/sonic-net/sonic-platform-daemons into vdm_read_through_xcvrd
2 parents f88fbed + 29e65fe commit 8a8efc6

File tree

9 files changed

+292
-60
lines changed

9 files changed

+292
-60
lines changed

sonic-chassisd/scripts/chassisd

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ try:
1717
import time
1818
import json
1919
import glob
20-
from datetime import datetime
20+
from datetime import datetime, timezone
2121

2222
from sonic_py_common import daemon_base, logger, device_info
2323
from sonic_py_common.task_base import ProcessTaskBase
@@ -136,6 +136,16 @@ def get_chassis():
136136
self.log_error("Failed to load chassis due to {}".format(repr(e)))
137137
sys.exit(CHASSIS_LOAD_ERROR)
138138

139+
def get_formatted_time(datetimeobj=None, op_format=None):
140+
"""
141+
Get the current time in specified format
142+
:param datetimeobj: Optional - A datetime object already initialized with a specific time
143+
:param op_format: Optional - Output Format for the time to be displayed
144+
:returns time in string format
145+
"""
146+
date_obj = datetimeobj if datetimeobj else datetime.now(timezone.utc)
147+
return date_obj.strftime(op_format if op_format else "%a %b %d %I:%M:%S %p UTC %Y")
148+
139149
#
140150
# Module Config Updater ========================================================
141151
#
@@ -765,28 +775,22 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
765775

766776
def update_dpu_state(self, key, state):
767777
"""
768-
Update DPU state in chassisStateDB using the given key.
778+
Update specific DPU state fields in chassisStateDB using the given key.
769779
"""
770780
try:
771781
# Connect to the CHASSIS_STATE_DB using daemon_base
772782
if not self.chassis_state_db:
773783
self.chassis_state_db = daemon_base.db_connect("CHASSIS_STATE_DB")
774784

775-
# Fetch the current data for the given key and convert it to a dict
776-
current_data = self._convert_to_dict(self.chassis_state_db.hgetall(key))
777-
778-
if current_data:
779-
self.chassis_state_db.delete(key)
780-
781-
# Prepare the updated data
785+
# Prepare the fields to update
782786
updates = {
783787
"dpu_midplane_link_state": state,
784788
"dpu_midplane_link_reason": "",
785-
"dpu_midplane_link_time": datetime.now().strftime("%a %b %d %I:%M:%S %p UTC %Y"),
789+
"dpu_midplane_link_time": get_formatted_time(),
786790
}
787-
current_data.update(updates)
788791

789-
for field, value in current_data.items():
792+
# Update each field directly
793+
for field, value in updates.items():
790794
self.chassis_state_db.hset(key, field, value)
791795

792796
except Exception as e:
@@ -818,7 +822,7 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
818822

819823
def _get_current_time_str(self):
820824
"""Returns the current time as a string in 'YYYY_MM_DD_HH_MM_SS' format."""
821-
return datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
825+
return get_formatted_time(op_format="%Y_%m_%d_%H_%M_%S")
822826

823827
def _get_history_path(self, module, file_name):
824828
"""Generates the full path for history files."""
@@ -880,11 +884,9 @@ class SmartSwitchModuleUpdater(ModuleUpdater):
880884

881885
file_path = self._get_history_path(module, file_name)
882886
try:
883-
dt_obj = datetime.strptime(prev_reboot_time, "%Y_%m_%d_%H_%M_%S")
887+
formatted_time = get_formatted_time(datetimeobj=datetime.strptime(prev_reboot_time, "%Y_%m_%d_%H_%M_%S"))
884888
except ValueError:
885-
dt_obj = datetime.now()
886-
887-
formatted_time = dt_obj.strftime("%a %b %d %I:%M:%S %p UTC %Y")
889+
formatted_time = get_formatted_time()
888890

889891
reboot_cause_dict = {
890892
"cause": cause,
@@ -1188,7 +1190,7 @@ class DpuStateUpdater(logger.Logger):
11881190
return True
11891191

11901192
def _time_now(self):
1191-
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1193+
return get_formatted_time()
11921194

11931195
def _update_dp_dpu_state(self, state):
11941196
self.dpu_state_table.hset(self.name, self.DP_STATE, state)

sonic-chassisd/tests/test_chassisd.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,27 @@ def test_chassis_db_bootup_with_empty_slot():
15151515
assert status == fvs[CHASSIS_MODULE_INFO_OPERSTATUS_FIELD]
15161516
assert down_module_lc1_key in sup_module_updater.down_modules.keys()
15171517

1518+
1519+
def test_smartswitch_time_format():
1520+
chassis = MockSmartSwitchChassis()
1521+
chassis_state_db = MagicMock()
1522+
mod_updater = SmartSwitchModuleUpdater(SYSLOG_IDENTIFIER, chassis)
1523+
mod_updater.chassis_state_db = chassis_state_db
1524+
mod_updater.chassis_state_db.hgetall = MagicMock(return_value={})
1525+
mod_updater.chassis_state_db.hset = MagicMock()
1526+
date_format = "%a %b %d %I:%M:%S %p UTC %Y"
1527+
def is_valid_date(date_str):
1528+
try:
1529+
datetime.strptime(date_str, date_format)
1530+
except ValueError:
1531+
# Parsing failed and we are unable to obtain the time
1532+
return False
1533+
return True
1534+
mod_updater.update_dpu_state("DPU1", 'up')
1535+
date_value = None
1536+
for args in (mod_updater.chassis_state_db.hset.call_args_list):
1537+
if args[0][0] == "DPU1" and args[0][1] == "dpu_midplane_link_time":
1538+
date_value = args[0][2]
1539+
if not date_value:
1540+
AssertionError("Date is not set!")
1541+
assert is_valid_date(date_value)

sonic-chassisd/tests/test_dpu_chassisd.py

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import signal
66
import threading
77
from imp import load_source
8+
import re
89

910
from mock import MagicMock
1011
from sonic_py_common import daemon_base
@@ -75,14 +76,14 @@ def test_dpu_state_update_api(state, expected_state):
7576

7677
@pytest.mark.parametrize('dpu_id, dp_state, cp_state, expected_state', [
7778
(0, False, False, {'DPU0':
78-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
79-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
79+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
80+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8081
(0, False, True, {'DPU0':
81-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
82-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
82+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
83+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8384
(0, True, True, {'DPU0':
84-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
85-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
85+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
86+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
8687
])
8788
def test_dpu_state_update(dpu_id, dp_state, cp_state, expected_state):
8889
chassis = MockDpuChassis()
@@ -102,7 +103,7 @@ def hset(key, field, value):
102103

103104
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset) as hset_mock:
104105
dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, chassis)
105-
dpu_updater._time_now = MagicMock(return_value='2000-01-01 00:00:00')
106+
dpu_updater._time_now = MagicMock(return_value='Sat Jan 01 12:00:00 AM UTC 2000')
106107

107108
dpu_updater.update_state()
108109

@@ -112,20 +113,20 @@ def hset(key, field, value):
112113

113114
# After the deinit we assume that the DPU state is down.
114115
assert chassis_state_db == {'DPU0':
115-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
116-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
116+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
117+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
117118

118119

119120
@pytest.mark.parametrize('dpu_id, dp_state, cp_state, expected_state', [
120121
(0, False, False, {'DPU0':
121-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
122-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
122+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
123+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
123124
(0, False, True, {'DPU0':
124-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
125-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
125+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
126+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
126127
(0, True, True, {'DPU0':
127-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
128-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
128+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
129+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}),
129130
])
130131
def test_dpu_state_manager(dpu_id, dp_state, cp_state, expected_state):
131132
chassis = MockDpuChassis()
@@ -146,7 +147,7 @@ def hset(key, field, value):
146147
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset):
147148
with mock.patch.object(swsscommon.Select, 'select', side_effect=((swsscommon.Select.OBJECT, None), (swsscommon.Select.OBJECT, None), KeyboardInterrupt)):
148149
dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, chassis)
149-
dpu_updater._time_now = MagicMock(return_value='2000-01-01 00:00:00')
150+
dpu_updater._time_now = MagicMock(return_value='Sat Jan 01 12:00:00 AM UTC 2000')
150151

151152
dpu_state_mng = DpuStateManagerTask(SYSLOG_IDENTIFIER, dpu_updater)
152153

@@ -158,8 +159,8 @@ def hset(key, field, value):
158159

159160
# After the deinit we assume that the DPU state is down.
160161
assert chassis_state_db == {'DPU0':
161-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
162-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
162+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
163+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
163164

164165

165166
def test_dpu_chassis_daemon():
@@ -180,7 +181,7 @@ def hset(key, field, value):
180181
chassis_state_db[key][field] = value
181182

182183
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset) as hset_mock:
183-
with mock.patch.object(DpuStateUpdater, '_time_now', side_effect=lambda: '2000-01-01 00:00:00') as mock_time_now:
184+
with mock.patch.object(DpuStateUpdater, '_time_now', side_effect=lambda: 'Sat Jan 01 12:00:00 AM UTC 2000') as mock_time_now:
184185

185186
daemon_chassisd = DpuChassisdDaemon(SYSLOG_IDENTIFIER, chassis)
186187
daemon_chassisd.CHASSIS_INFO_UPDATE_PERIOD_SECS = MagicMock(return_value=1)
@@ -195,14 +196,40 @@ def hset(key, field, value):
195196
time.sleep(3)
196197

197198
assert chassis_state_db == {'DPU1':
198-
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
199-
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
199+
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
200+
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
200201

201202
daemon_chassisd.signal_handler(signal.SIGINT, None)
202203
daemon_chassisd.stop.wait.return_value = True
203204

204205
thread.join()
205206

206207
assert chassis_state_db == {'DPU1':
207-
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
208-
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}
208+
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000',
209+
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': 'Sat Jan 01 12:00:00 AM UTC 2000'}}
210+
with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset):
211+
daemon_chassisd = DpuChassisdDaemon(SYSLOG_IDENTIFIER, chassis)
212+
daemon_chassisd.CHASSIS_INFO_UPDATE_PERIOD_SECS = MagicMock(return_value=1)
213+
214+
daemon_chassisd.stop = MagicMock()
215+
daemon_chassisd.stop.wait.return_value = False
216+
217+
thread = threading.Thread(target=daemon_chassisd.run)
218+
thread.start()
219+
# Wait for thread to start and update DB
220+
time.sleep(3)
221+
date_format = "%a %b %d %I:%M:%S %p UTC %Y"
222+
223+
def is_valid_date(date_str):
224+
try:
225+
datetime.strptime(date_str, date_format)
226+
except ValueError:
227+
# Parsing failed and we are unable to obtain the time
228+
return False
229+
return True
230+
assert is_valid_date(chassis_state_db['DPU1']['dpu_data_plane_time'])
231+
assert is_valid_date(chassis_state_db['DPU1']['dpu_control_plane_time'])
232+
daemon_chassisd.signal_handler(signal.SIGINT, None)
233+
daemon_chassisd.stop.wait.return_value = True
234+
235+
thread.join()

sonic-pcied/scripts/pcied

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ SYSLOG_IDENTIFIER = "pcied"
2727
PCIE_RESULT_REGEX = "PCIe Device Checking All Test"
2828
PCIE_DEVICE_TABLE_NAME = "PCIE_DEVICE"
2929
PCIE_STATUS_TABLE_NAME = "PCIE_DEVICES"
30+
PCIE_DETACH_INFO_TABLE = "PCIE_DETACH_INFO"
31+
32+
PCIE_DETACH_BUS_INFO_FIELD = "bus_info"
33+
PCIE_DETACH_DPU_STATE_FIELD = "dpu_state"
3034

3135
PCIED_MAIN_THREAD_SLEEP_SECS = 60
3236

@@ -92,6 +96,7 @@ class DaemonPcied(daemon_base.DaemonBase):
9296
self.state_db = daemon_base.db_connect("STATE_DB")
9397
self.device_table = swsscommon.Table(self.state_db, PCIE_DEVICE_TABLE_NAME)
9498
self.status_table = swsscommon.Table(self.state_db, PCIE_STATUS_TABLE_NAME)
99+
self.detach_info = swsscommon.Table(self.state_db, PCIE_DETACH_INFO_TABLE)
95100

96101
def __del__(self):
97102
if self.device_table:
@@ -102,6 +107,10 @@ class DaemonPcied(daemon_base.DaemonBase):
102107
stable_keys = self.status_table.getKeys()
103108
for stk in stable_keys:
104109
self.status_table._del(stk)
110+
if self.detach_info:
111+
detach_info_keys = self.detach_info.getKeys()
112+
for dk in detach_info_keys:
113+
self.detach_info._del(dk)
105114

106115
# load aer-fields into statedb
107116
def update_aer_to_statedb(self):
@@ -151,6 +160,28 @@ class DaemonPcied(daemon_base.DaemonBase):
151160

152161
self.status_table.set("status", fvs)
153162

163+
# Check if any PCI interface is in detaching mode by querying the state_db
164+
def is_dpu_in_detaching_mode(self, pcie_dev):
165+
# Ensure detach_info is not None
166+
if self.detach_info is None:
167+
self.log_debug("detach_info is None")
168+
return False
169+
170+
# Query the state_db for the device detaching status
171+
detach_info_keys = list(self.detach_info.getKeys())
172+
if not detach_info_keys:
173+
return False
174+
175+
for key in detach_info_keys:
176+
dpu_info = self.detach_info.get(key)
177+
if dpu_info:
178+
bus_info = dpu_info.get(PCIE_DETACH_BUS_INFO_FIELD)
179+
dpu_state = dpu_info.get(PCIE_DETACH_DPU_STATE_FIELD)
180+
if bus_info == pcie_dev and dpu_state == "detaching":
181+
return True
182+
183+
return False
184+
154185
# Check the PCIe devices
155186
def check_pcie_devices(self):
156187
self.resultInfo = platform_pcieutil.get_pcie_check()
@@ -160,6 +191,14 @@ class DaemonPcied(daemon_base.DaemonBase):
160191

161192
for result in self.resultInfo:
162193
if result["result"] == "Failed":
194+
# Convert bus, device, and function to a bus_info format like "0000:03:00.0"
195+
pcie_dev = "0000:{int(result['bus'], 16):02x}:{int(result['dev'], 16):02x}.{int(result['fn'], 16)}"
196+
197+
# Check if the device is in detaching mode
198+
if device_info.is_smartswitch() and self.is_dpu_in_detaching_mode(pcie_dev):
199+
self.log_debug("PCIe Device: {} is in detaching mode, skipping warning.".format(pcie_dev))
200+
continue
201+
163202
self.log_warning("PCIe Device: " + result["name"] + " Not Found")
164203
err += 1
165204
else:

0 commit comments

Comments
 (0)