Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SmartSwitch] Extend implementation of the DPU chassis daemon. #563

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion sonic-chassisd/scripts/chassisd
Original file line number Diff line number Diff line change
Expand Up @@ -790,21 +790,74 @@ class ChassisdDaemon(daemon_base.DaemonBase):
self.log_info("Shutting down...")


class DpuStateManagerTask(ProcessTaskBase):

def __init__(self, log_identifier, dpu_state_updater):
super(DpuStateManagerTask, self).__init__()

self.logger = logger.Logger(log_identifier)
self.dpu_state_updater = dpu_state_updater
self.state_db = daemon_base.db_connect('STATE_DB')
self.app_db = daemon_base.db_connect('APPL_DB')

def task_worker(self):
sel = swsscommon.Select()
selectable = [
swsscommon.SubscriberStateTable(self.app_db, 'PORT_TABLE'),
swsscommon.SubscriberStateTable(self.state_db, 'SYSTEM_READY')
]

for s in selectable:
sel.addSelectable(s)

try:
while True:
(state, c) = sel.select(SELECT_TIMEOUT)

if state == swsscommon.Select.TIMEOUT:
continue

if state != swsscommon.Select.OBJECT:
continue

for s in selectable:
s.pops()

self.dpu_state_updater.update_state()

except KeyboardInterrupt:
pass


class DpuChassisdDaemon(ChassisdDaemon):

def run(self):
self.log_info("Starting up...")

poll_dpu_state = True
if not try_get(self.platform_chassis.get_dataplane_state, default=None) and not \
try_get(self.platform_chassis.get_controlplane_state, default=None):
poll_dpu_state = False

dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, self.platform_chassis)
dpu_state_mng = None

if not poll_dpu_state:
dpu_state_mng = DpuStateManagerTask(SYSLOG_IDENTIFIER, dpu_updater)
dpu_state_mng.task_run()

# Start main loop
self.log_info("Start daemon main loop")

while not self.stop.wait(CHASSIS_INFO_UPDATE_PERIOD_SECS):
dpu_updater.update_state()
if poll_dpu_state:
dpu_updater.update_state()

self.log_info("Stop daemon main loop")

if dpu_state_mng:
dpu_state_mng.task_stop()

dpu_updater.deinit()

self.log_info("Shutting down...")
Expand Down
8 changes: 7 additions & 1 deletion sonic-chassisd/tests/mock_swsscommon.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __init__(self, fvs):
pass

class Select:
OBJECT = 0
TIMEOUT = 1

def addSelectable(self, selectable):
Expand All @@ -66,7 +67,12 @@ def select(self, timeout=-1, interrupt_on_signal=False):
return self.TIMEOUT, None

class SubscriberStateTable(Table):
pass

def pop(self):
return None

def pops(self):
return None

class RedisPipeline:
def __init__(self, db):
Expand Down
46 changes: 46 additions & 0 deletions sonic-chassisd/tests/test_dpu_chassisd.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,52 @@ def hset(key, field, value):
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}


@pytest.mark.parametrize('dpu_id, dp_state, cp_state, expected_state', [
(0, False, False, {'DPU0':
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
(0, False, True, {'DPU0':
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
(0, True, True, {'DPU0':
{'dpu_data_plane_state': 'up', 'dpu_data_plane_time': '2000-01-01 00:00:00',
'dpu_control_plane_state': 'up', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}),
])
def test_dpu_state_manager(dpu_id, dp_state, cp_state, expected_state):
chassis = MockDpuChassis()

chassis.get_dpu_id = MagicMock(return_value=dpu_id)
chassis.get_dataplane_state = MagicMock(return_value=dp_state)
chassis.get_controlplane_state = MagicMock(return_value=cp_state)

chassis_state_db = {}

def hset(key, field, value):
print(key, field, value)
if key not in chassis_state_db:
chassis_state_db[key] = {}

chassis_state_db[key][field] = value

with mock.patch.object(swsscommon.Table, 'hset', side_effect=hset):
with mock.patch.object(swsscommon.Select, 'select', side_effect=((swsscommon.Select.OBJECT, None), (swsscommon.Select.OBJECT, None), KeyboardInterrupt)):
dpu_updater = DpuStateUpdater(SYSLOG_IDENTIFIER, chassis)
dpu_updater._time_now = MagicMock(return_value='2000-01-01 00:00:00')

dpu_state_mng = DpuStateManagerTask(SYSLOG_IDENTIFIER, dpu_updater)

dpu_state_mng.task_worker()

assert chassis_state_db == expected_state

dpu_updater.deinit()

# After the deinit we assume that the DPU state is down.
assert chassis_state_db == {'DPU0':
{'dpu_data_plane_state': 'down', 'dpu_data_plane_time': '2000-01-01 00:00:00',
'dpu_control_plane_state': 'down', 'dpu_control_plane_time': '2000-01-01 00:00:00'}}


def test_dpu_chassis_daemon():
# Test the chassisd run
chassis = MockDpuChassis()
Expand Down
Loading