Skip to content

Commit

Permalink
[chassis][mutli-asic][lldp] "show lldp table/neighbors" displays erro…
Browse files Browse the repository at this point in the history
…r message in output on multi-asis linecard. (sonic-net#3358)

Modify the lldpshow script to fix the output of the "show lldp table" and "show lldp neighbors" on the multi-asic Linecard. Fixes sonic-net/sonic-buildimage#19209

* [mutli-asic][lldp] "show lldp table" displays error message in output on multi-asic linecard

* Added code coverage UT

Signed-off-by: mlok <[email protected]>
  • Loading branch information
mlok-nokia authored Jun 19, 2024
1 parent 515265a commit 9d206af
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 7 deletions.
13 changes: 9 additions & 4 deletions scripts/lldpshow
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import sys
from lxml import etree as ET

from sonic_py_common import device_info
from utilities_common import constants
from swsscommon.swsscommon import ConfigDBConnector
from utilities_common.general import load_db_config
from utilities_common.general import load_db_config, get_feature_state_data
from tabulate import tabulate

BACKEND_ASIC_INTERFACE_NAME_PREFIX = 'Ethernet-BP'
Expand Down Expand Up @@ -69,8 +70,12 @@ class Lldpshow(object):
self.lldp_interface[instance_num] += key + SPACE_TOKEN

# LLDP running in host namespace
self.lldp_instance.append(LLDP_INSTANCE_IN_HOST_NAMESPACE)
self.lldp_interface.append(LLDP_INTERFACE_LIST_IN_HOST_NAMESPACE)
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=constants.DEFAULT_NAMESPACE)
config_db.connect()
global_scope, asic_scope = get_feature_state_data(config_db, "lldp")
if global_scope == "True":
self.lldp_instance.append(LLDP_INSTANCE_IN_HOST_NAMESPACE)
self.lldp_interface.append(LLDP_INTERFACE_LIST_IN_HOST_NAMESPACE)

def get_info(self, lldp_detail_info, lldp_port):
"""
Expand All @@ -85,7 +90,7 @@ class Lldpshow(object):
elif lldp_interface_list == '':
lldp_args = []
else:
lldp_args = [lldp_interface_list]
lldp_args = lldp_interface_list.split(' ')
lldp_cmd = ['sudo', 'docker', 'exec', '-i', 'lldp{}'.format(self.lldp_instance[lldp_instace_num]), 'lldpctl'] + lldp_args
p = subprocess.Popen(lldp_cmd, stdout=subprocess.PIPE, text=True)
(output, err) = p.communicate()
Expand Down
17 changes: 17 additions & 0 deletions tests/lldp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from click.testing import CliRunner
from utilities_common.general import load_module_from_source
from importlib import reload

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
Expand Down Expand Up @@ -83,6 +84,22 @@ def test_get_info(self):
output = lldp.get_summary_output(lldp_detail_info=True)
assert output.strip('\n') == expected_lldpctl_xml_output[0].strip('\n')

def test_get_info_multi_asic(self):
from .mock_tables import mock_multi_asic
from .mock_tables import dbconnector
reload(mock_multi_asic)
dbconnector.load_namespace_config()
lldp = lldpshow.Lldpshow()
from .mock_tables import mock_single_asic
reload(mock_single_asic)
dbconnector.load_namespace_config()
lldp.lldp_instance = ['']
lldp.lldpraw = expected_lldpctl_xml_output
lldp.get_info(lldp_detail_info=True, lldp_port='Ethernet0')
lldp.parse_info(lldp_detail_info=True)
output = lldp.get_summary_output(lldp_detail_info=True)
assert output.strip('\n') == expected_lldpctl_xml_output[0].strip('\n')

@classmethod
def teardown_class(cls):
print("TEARDOWN")
2 changes: 2 additions & 0 deletions tests/mock_tables/config_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,8 @@
"FEATURE|lldp": {
"state": "enabled",
"auto_restart": "enabled",
"has_global_scope": "False",
"has_per_asic_scope": "True",
"high_mem_alert": "disabled",
"set_owner": "kube"
},
Expand Down
31 changes: 28 additions & 3 deletions utilities_common/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import importlib.util
import sys

from sonic_py_common.multi_asic import is_multi_asic
from sonic_py_common import multi_asic
from swsscommon import swsscommon
FEATURE_TABLE = "FEATURE"
FEATURE_HAS_PER_ASIC_SCOPE = 'has_per_asic_scope'
FEATURE_HAS_GLOBAL_SCOPE = 'has_global_scope'

def load_module_from_source(module_name, file_path):
"""
Expand All @@ -25,7 +28,7 @@ def load_db_config():
- database_global.json for multi asic
- database_config.json for single asic
'''
if is_multi_asic():
if multi_asic.is_multi_asic():
if not swsscommon.SonicDBConfig.isGlobalInit():
swsscommon.SonicDBConfig.load_sonic_global_db_config()
else:
Expand All @@ -39,6 +42,28 @@ def get_optional_value_for_key_in_config_tbl(config_db, port, key, table):
return None

value = info_dict.get(key, None)

return value


def get_feature_state_data(config_db, feature):
'''
Get feature state from FEATURE table from CONFIG_DB.
return global_scope, per_asic_scope
- if feature state is disabled, return "False" for both global_scope and per_asic_scope
- if is not a multi-asic, return feature state for global_scope ("True/False") and
"False" for asic_scope
'''
global_scope = "False"
asic_scope = "False"
info_dict = {}
info_dict = config_db.get_entry(FEATURE_TABLE, feature)
if info_dict is None:
return global_scope, asic_scope
if multi_asic.is_multi_asic():
if info_dict['state'].lower() == "enabled":
global_scope = info_dict[FEATURE_HAS_GLOBAL_SCOPE]
asic_scope = info_dict[FEATURE_HAS_PER_ASIC_SCOPE]
else:
if info_dict['state'].lower() == "enabled":
global_scope = "True"
return global_scope, asic_scope

0 comments on commit 9d206af

Please sign in to comment.