Skip to content

Commit b6af9f4

Browse files
authored
Fix expected neighbor when multiple ports connect to same neighbor (sonic-net#1162)
Previous code only enumerate on distinct neighbors, thus only one port is shown for a neighbor. Signed-off-by: Guohan Lu <[email protected]>
1 parent a71c72b commit b6af9f4

File tree

9 files changed

+296095
-23
lines changed

9 files changed

+296095
-23
lines changed

show/interfaces/__init__.py

+20-16
Original file line numberDiff line numberDiff line change
@@ -249,25 +249,29 @@ def expected(db, interfacename):
249249
header = ['LocalPort', 'Neighbor', 'NeighborPort', 'NeighborLoopback', 'NeighborMgmt', 'NeighborType']
250250
body = []
251251
if interfacename:
252-
for device in natsorted(neighbor_metadata_dict.keys()):
253-
if device2interface_dict[device]['localPort'] == interfacename:
254-
body.append([device2interface_dict[device]['localPort'],
255-
device,
256-
device2interface_dict[device]['neighborPort'],
257-
neighbor_metadata_dict[device]['lo_addr'],
258-
neighbor_metadata_dict[device]['mgmt_addr'],
259-
neighbor_metadata_dict[device]['type']])
260-
if len(body) == 0:
261-
click.echo("No neighbor information available for interface {}".format(interfacename))
262-
return
263-
else:
264-
for device in natsorted(neighbor_metadata_dict.keys()):
265-
body.append([device2interface_dict[device]['localPort'],
252+
try:
253+
device = neighbor_dict[interfacename]['name']
254+
body.append([interfacename,
266255
device,
267-
device2interface_dict[device]['neighborPort'],
256+
neighbor_dict[interfacename]['port'],
268257
neighbor_metadata_dict[device]['lo_addr'],
269258
neighbor_metadata_dict[device]['mgmt_addr'],
270259
neighbor_metadata_dict[device]['type']])
260+
except KeyError:
261+
click.echo("No neighbor information available for interface {}".format(interfacename))
262+
return
263+
else:
264+
for port in natsorted(neighbor_dict.keys()):
265+
try:
266+
device = neighbor_dict[port]['name']
267+
body.append([port,
268+
device,
269+
neighbor_dict[port]['port'],
270+
neighbor_metadata_dict[device]['lo_addr'],
271+
neighbor_metadata_dict[device]['mgmt_addr'],
272+
neighbor_metadata_dict[device]['type']])
273+
except KeyError:
274+
pass
271275

272276
click.echo(tabulate(body, header))
273277

@@ -387,7 +391,7 @@ def errors(verbose, period, namespace, display):
387391
cmd = "portstat -e"
388392
if period is not None:
389393
cmd += " -p {}".format(period)
390-
394+
391395
cmd += " -s {}".format(display)
392396
if namespace is not None:
393397
cmd += " -n {}".format(namespace)

tests/conftest.py

+5
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ def setup_single_broacom_asic():
7070
config.asic_type = mock.MagicMock(return_value="broadcom")
7171
config._get_device_type = mock.MagicMock(return_value="ToRRouter")
7272

73+
@pytest.fixture
74+
def setup_t1_topo():
75+
mock_tables.dbconnector.topo = "t1"
76+
yield
77+
mock_tables.dbconnector.topo = None
7378

7479
@pytest.fixture
7580
def setup_single_bgp_instance(request):

tests/interfaces_test.py

+78
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,67 @@
5757
Ethernet124 ARISTA04T1 Ethernet1 None 10.250.0.54 LeafRouter
5858
"""
5959

60+
show_interfaces_neighbor_expected_output_t1="""\
61+
LocalPort Neighbor NeighborPort NeighborLoopback NeighborMgmt NeighborType
62+
----------- ---------- -------------- ------------------ -------------- --------------
63+
Ethernet0 ARISTA01T2 Ethernet1 None 172.16.137.56 SpineRouter
64+
Ethernet4 ARISTA01T2 Ethernet2 None 172.16.137.56 SpineRouter
65+
Ethernet8 ARISTA03T2 Ethernet1 None 172.16.137.57 SpineRouter
66+
Ethernet12 ARISTA03T2 Ethernet2 None 172.16.137.57 SpineRouter
67+
Ethernet16 ARISTA05T2 Ethernet1 None 172.16.137.58 SpineRouter
68+
Ethernet20 ARISTA05T2 Ethernet2 None 172.16.137.58 SpineRouter
69+
Ethernet24 ARISTA07T2 Ethernet1 None 172.16.137.59 SpineRouter
70+
Ethernet28 ARISTA07T2 Ethernet2 None 172.16.137.59 SpineRouter
71+
Ethernet32 ARISTA09T2 Ethernet1 None 172.16.137.60 SpineRouter
72+
Ethernet36 ARISTA09T2 Ethernet2 None 172.16.137.60 SpineRouter
73+
Ethernet40 ARISTA11T2 Ethernet1 None 172.16.137.61 SpineRouter
74+
Ethernet44 ARISTA11T2 Ethernet2 None 172.16.137.61 SpineRouter
75+
Ethernet48 ARISTA13T2 Ethernet1 None 172.16.137.62 SpineRouter
76+
Ethernet52 ARISTA13T2 Ethernet2 None 172.16.137.62 SpineRouter
77+
Ethernet56 ARISTA15T2 Ethernet1 None 172.16.137.63 SpineRouter
78+
Ethernet60 ARISTA15T2 Ethernet2 None 172.16.137.63 SpineRouter
79+
Ethernet64 ARISTA01T0 Ethernet1 None 172.16.137.64 ToRRouter
80+
Ethernet68 ARISTA02T0 Ethernet1 None 172.16.137.65 ToRRouter
81+
Ethernet72 ARISTA03T0 Ethernet1 None 172.16.137.66 ToRRouter
82+
Ethernet76 ARISTA04T0 Ethernet1 None 172.16.137.67 ToRRouter
83+
Ethernet80 ARISTA05T0 Ethernet1 None 172.16.137.68 ToRRouter
84+
Ethernet84 ARISTA06T0 Ethernet1 None 172.16.137.69 ToRRouter
85+
Ethernet88 ARISTA07T0 Ethernet1 None 172.16.137.70 ToRRouter
86+
Ethernet92 ARISTA08T0 Ethernet1 None 172.16.137.71 ToRRouter
87+
Ethernet96 ARISTA09T0 Ethernet1 None 172.16.137.72 ToRRouter
88+
Ethernet100 ARISTA10T0 Ethernet1 None 172.16.137.73 ToRRouter
89+
Ethernet104 ARISTA11T0 Ethernet1 None 172.16.137.74 ToRRouter
90+
Ethernet108 ARISTA12T0 Ethernet1 None 172.16.137.75 ToRRouter
91+
Ethernet112 ARISTA13T0 Ethernet1 None 172.16.137.76 ToRRouter
92+
Ethernet116 ARISTA14T0 Ethernet1 None 172.16.137.77 ToRRouter
93+
Ethernet120 ARISTA15T0 Ethernet1 None 172.16.137.78 ToRRouter
94+
Ethernet124 ARISTA16T0 Ethernet1 None 172.16.137.79 ToRRouter
95+
"""
96+
6097
show_interfaces_neighbor_expected_output_Ethernet112="""\
6198
LocalPort Neighbor NeighborPort NeighborLoopback NeighborMgmt NeighborType
6299
----------- ---------- -------------- ------------------ -------------- --------------
63100
Ethernet112 ARISTA01T1 Ethernet1 None 10.250.0.51 LeafRouter
64101
"""
65102

103+
show_interfaces_neighbor_expected_output_t1_Ethernet0="""\
104+
LocalPort Neighbor NeighborPort NeighborLoopback NeighborMgmt NeighborType
105+
----------- ---------- -------------- ------------------ -------------- --------------
106+
Ethernet0 ARISTA01T2 Ethernet1 None 172.16.137.56 SpineRouter
107+
"""
108+
66109
show_interfaces_neighbor_expected_output_etp29="""\
67110
LocalPort Neighbor NeighborPort NeighborLoopback NeighborMgmt NeighborType
68111
----------- ---------- -------------- ------------------ -------------- --------------
69112
etp29 ARISTA01T1 Ethernet1 None 10.250.0.51 LeafRouter
70113
"""
71114

115+
show_interfaces_neighbor_expected_output_t1_Ethernet1_1="""\
116+
LocalPort Neighbor NeighborPort NeighborLoopback NeighborMgmt NeighborType
117+
----------- ---------- -------------- ------------------ -------------- --------------
118+
Ethernet1/1 ARISTA01T2 Ethernet1 None 172.16.137.56 SpineRouter
119+
"""
120+
72121
show_interfaces_portchannel_output="""\
73122
Flags: A - active, I - inactive, Up - up, Dw - Down, N/A - not available,
74123
S - selected, D - deselected, * - not synced
@@ -166,6 +215,15 @@ def test_show_interfaces_neighbor_expected(self):
166215
assert result.exit_code == 0
167216
assert result.output == show_interfaces_neighbor_expected_output
168217

218+
def test_show_interfaces_neighbor_expected_t1(self, setup_t1_topo):
219+
runner = CliRunner()
220+
result = runner.invoke(show.cli.commands["interfaces"].commands["neighbor"].commands["expected"], [])
221+
print(result.exit_code)
222+
print(result.output)
223+
# traceback.print_tb(result.exc_info[2])
224+
assert result.exit_code == 0
225+
assert result.output == show_interfaces_neighbor_expected_output_t1
226+
169227
def test_show_interfaces_neighbor_expected_Ethernet112(self):
170228
runner = CliRunner()
171229
result = runner.invoke(show.cli.commands["interfaces"].commands["neighbor"].commands["expected"], ["Ethernet112"])
@@ -175,6 +233,15 @@ def test_show_interfaces_neighbor_expected_Ethernet112(self):
175233
assert result.exit_code == 0
176234
assert result.output == show_interfaces_neighbor_expected_output_Ethernet112
177235

236+
def test_show_interfaces_neighbor_expected_t1_Ethernet0(self, setup_t1_topo):
237+
runner = CliRunner()
238+
result = runner.invoke(show.cli.commands["interfaces"].commands["neighbor"].commands["expected"], ["Ethernet0"])
239+
print(result.exit_code)
240+
print(result.output)
241+
# traceback.print_tb(result.exc_info[2])
242+
assert result.exit_code == 0
243+
assert result.output == show_interfaces_neighbor_expected_output_t1_Ethernet0
244+
178245
def test_show_interfaces_neighbor_expected_etp29(self):
179246
runner = CliRunner()
180247
os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
@@ -186,6 +253,17 @@ def test_show_interfaces_neighbor_expected_etp29(self):
186253
assert result.exit_code == 0
187254
assert result.output == show_interfaces_neighbor_expected_output_etp29
188255

256+
def test_show_interfaces_neighbor_expected_t1_Ethernet1_1(self, setup_t1_topo):
257+
runner = CliRunner()
258+
os.environ['SONIC_CLI_IFACE_MODE'] = "alias"
259+
result = runner.invoke(show.cli.commands["interfaces"].commands["neighbor"].commands["expected"], ["Ethernet1/1"])
260+
os.environ['SONIC_CLI_IFACE_MODE'] = "default"
261+
print(result.exit_code)
262+
print(result.output)
263+
# traceback.print_tb(result.exc_info[2])
264+
assert result.exit_code == 0
265+
assert result.output == show_interfaces_neighbor_expected_output_t1_Ethernet1_1
266+
189267
def test_show_interfaces_neighbor_expected_Ethernet0(self):
190268
runner = CliRunner()
191269
result = runner.invoke(show.cli.commands["interfaces"].commands["neighbor"].commands["expected"], ["Ethernet0"])

tests/mock_tables/dbconnector.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from swsssdk import SonicDBConfig, SonicV2Connector
1010
from swsssdk.interface import redis
1111

12+
topo = None
13+
1214
def clean_up_config():
1315
# Set SonicDBConfig variables to initial state
1416
# so that it can be loaded with single or multiple
@@ -20,7 +22,7 @@ def clean_up_config():
2022
def load_namespace_config():
2123
# To support multi asic testing
2224
# SonicDBConfig load_sonic_global_db_config
23-
# is invoked to load multiple namespaces
25+
# is invoked to load multiple namespaces
2426
clean_up_config()
2527
SonicDBConfig.load_sonic_global_db_config(
2628
global_db_file_path=os.path.join(
@@ -37,7 +39,8 @@ def load_database_config():
3739
_old_connect_SonicV2Connector = SonicV2Connector.connect
3840

3941
def connect_SonicV2Connector(self, db_name, retry_on=True):
40-
42+
# add topo to kwargs for testing different topology
43+
self.dbintf.redis_kwargs['topo'] = topo
4144
# add the namespace to kwargs for testing multi asic
4245
self.dbintf.redis_kwargs['namespace'] = self.namespace
4346
# Mock DB filename for unit-test
@@ -79,23 +82,32 @@ def __init__(self, *args, **kwargs):
7982
super(SwssSyncClient, self).__init__(strict=True, *args, **kwargs)
8083
# Namespace is added in kwargs specifically for unit-test
8184
# to identify the file path to load the db json files.
85+
topo = kwargs.pop('topo')
8286
namespace = kwargs.pop('namespace')
8387
db_name = kwargs.pop('db_name')
8488
fname = db_name.lower() + ".json"
8589
self.pubsub = MockPubSub()
86-
90+
8791
if namespace is not None and namespace is not multi_asic.DEFAULT_NAMESPACE:
8892
fname = os.path.join(INPUT_DIR, namespace, fname)
93+
elif topo is not None:
94+
fname = os.path.join(INPUT_DIR, topo, fname)
8995
else:
9096
fname = os.path.join(INPUT_DIR, fname)
91-
9297

9398
if os.path.exists(fname):
9499
with open(fname) as f:
95100
js = json.load(f)
96-
for h, table in js.items():
97-
for k, v in table.items():
98-
self.hset(h, k, v)
101+
for k, v in js.items():
102+
if v.has_key('expireat') and v.has_key('ttl') and v.has_key('type') and v.has_key('value'):
103+
# database is in redis-dump format
104+
if v['type'] == 'hash':
105+
# ignore other types for now since sonic has hset keys only in the db
106+
for attr, value in v['value'].items():
107+
self.hset(k, attr, value)
108+
else:
109+
for attr, value in v.items():
110+
self.hset(k, attr, value)
99111

100112
# Patch mockredis/mockredis/client.py
101113
# The official implementation will filter out keys with a slash '/'

0 commit comments

Comments
 (0)