@@ -25,30 +25,73 @@ import re
25
25
import sys
26
26
import xml .etree .ElementTree as ET
27
27
from tabulate import tabulate
28
+ import argparse
29
+ import sonic_device_util
30
+ from swsssdk import ConfigDBConnector , SonicDBConfig
31
+ BACKEND_ASIC_INTERFACE_NAME_PREFIX = 'Ethernet-BP'
32
+
33
+ LLDP_INTERFACE_LIST_IN_HOST_NAMESPACE = ''
34
+ LLDP_INSTANCE_IN_HOST_NAMESPACE = ''
35
+ LLDP_DEFAULT_INTERFACE_LIST_IN_ASIC_NAMESPACE = ''
36
+ SPACE_TOKEN = ' '
28
37
29
38
class Lldpshow (object ):
30
39
def __init__ (self ):
31
- self .lldpraw = None
40
+ self .lldpraw = []
32
41
self .lldpsum = {}
42
+ self .lldp_interface = []
43
+ self .lldp_instance = []
33
44
self .err = None
34
45
### So far only find Router and Bridge two capabilities in lldpctl, so any other capacility types will be read as Other
35
46
### if further capability type is supported like WLAN, can just add the tag definition here
36
47
self .ctags = {'Router' : 'R' , 'Bridge' : 'B' }
48
+ SonicDBConfig .load_sonic_global_db_config ()
49
+
50
+ # For multi-asic platforms we will get only front-panel interface to display
51
+ namespaces = sonic_device_util .get_all_namespaces ()
52
+ per_asic_configdb = {}
53
+ for instance_num , front_asic_namespaces in enumerate (namespaces ['front_ns' ]):
54
+ per_asic_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
55
+ per_asic_configdb [front_asic_namespaces ].connect ()
56
+ # Initalize Interface list to be ''. We will do string append of the interfaces below.
57
+ self .lldp_interface .append (LLDP_DEFAULT_INTERFACE_LIST_IN_ASIC_NAMESPACE )
58
+ self .lldp_instance .append (instance_num )
59
+ keys = per_asic_configdb [front_asic_namespaces ].get_keys ("PORT" )
60
+ for key in keys :
61
+ if key .startswith (BACKEND_ASIC_INTERFACE_NAME_PREFIX ):
62
+ continue
63
+ self .lldp_interface [instance_num ] += key + SPACE_TOKEN
37
64
38
- def get_info (self ):
65
+ # LLDP running in host namespace
66
+ self .lldp_instance .append (LLDP_INSTANCE_IN_HOST_NAMESPACE )
67
+ self .lldp_interface .append (LLDP_INTERFACE_LIST_IN_HOST_NAMESPACE )
68
+
69
+ def get_info (self , lldp_detail_info , lldp_port ):
39
70
"""
40
- use 'lldpctl -f xml ' command to gather local lldp detailed information
71
+ use 'lldpctl' command to gather local lldp detailed information
41
72
"""
42
- lldp_cmd = 'lldpctl -f xml'
43
- p = subprocess .Popen (lldp_cmd , stdout = subprocess .PIPE , shell = True )
44
- (output , err ) = p .communicate ()
45
- ## Wait for end of command. Get return returncode ##
46
- returncode = p .wait ()
47
- ### if no error, get the lldpctl result
48
- if returncode == 0 :
49
- self .lldpraw = output
50
- else :
51
- self .err = err
73
+ for lldp_instace_num in range (len (self .lldp_instance )):
74
+ lldp_interface_list = lldp_port if lldp_port is not None else self .lldp_interface [lldp_instace_num ]
75
+ # In detail mode we will pass interface list (only front ports) and get O/P as plain text
76
+ # and in table format we will get xml output
77
+ lldp_cmd = 'sudo docker exec -it lldp{} lldpctl ' .format (self .lldp_instance [lldp_instace_num ]) + ('-f xml' if not lldp_detail_info else lldp_interface_list )
78
+ p = subprocess .Popen (lldp_cmd , stdout = subprocess .PIPE , shell = True )
79
+ (output , err ) = p .communicate ()
80
+ ## Wait for end of command. Get return returncode ##
81
+ returncode = p .wait ()
82
+ ### if no error, get the lldpctl result
83
+ if returncode == 0 :
84
+ # ignore the output if given port is not present
85
+ if lldp_port is not None and lldp_port not in output :
86
+ continue
87
+ self .lldpraw .append (output )
88
+ if lldp_port is not None :
89
+ break
90
+ else :
91
+ self .err = err
92
+
93
+ if self .err :
94
+ self .lldpraw = []
52
95
53
96
def parse_cap (self , capabs ):
54
97
"""
@@ -64,15 +107,19 @@ class Lldpshow(object):
64
107
capability += 'O'
65
108
return capability
66
109
67
- def parse_info (self ):
110
+ def parse_info (self , lldp_detail_info ):
68
111
"""
69
112
Parse the lldp detailed infomation into dict
70
113
"""
71
- if self .lldpraw is not None :
72
- neis = ET .fromstring (self .lldpraw )
114
+ if lldp_detail_info :
115
+ return
116
+ for lldpraw in self .lldpraw :
117
+ neis = ET .fromstring (lldpraw )
73
118
intfs = neis .findall ('interface' )
74
119
for intf in intfs :
75
120
l_intf = intf .attrib ['name' ]
121
+ if l_intf .startswith (BACKEND_ASIC_INTERFACE_NAME_PREFIX ):
122
+ continue
76
123
self .lldpsum [l_intf ] = {}
77
124
chassis = intf .find ('chassis' )
78
125
capabs = chassis .findall ('capability' )
@@ -97,11 +144,17 @@ class Lldpshow(object):
97
144
return sorted (summary , key = alphanum_key )
98
145
99
146
100
- def display_sum (self ):
147
+ def display_sum (self , lldp_detail_info ):
101
148
"""
102
149
print out summary result of lldp neighbors
103
150
"""
104
- if self .lldpraw is not None :
151
+ # In detail mode output is plain text
152
+ if self .lldpraw and lldp_detail_info :
153
+ lldp_output = ''
154
+ for lldp_detail_output in self .lldpraw :
155
+ lldp_output += lldp_detail_output
156
+ print (lldp_output )
157
+ elif self .lldpraw :
105
158
lldpstatus = []
106
159
print ('Capability codes: (R) Router, (B) Bridge, (O) Other' )
107
160
header = ['LocalPort' , 'RemoteDevice' , 'RemotePortID' , 'Capability' , 'RemotePortDescr' ]
@@ -115,11 +168,32 @@ class Lldpshow(object):
115
168
print ('Error:' ,self .err )
116
169
117
170
def main ():
171
+ parser = argparse .ArgumentParser (description = 'Display the LLDP neighbors' ,
172
+ version = '1.0.0' ,
173
+ formatter_class = argparse .RawTextHelpFormatter ,
174
+ epilog = """
175
+ Examples:
176
+ lldpshow
177
+ lldpshow -d
178
+ lldpshow -d -p Ethernet0
179
+ lldpshow -p Ethernet0
180
+ """ )
181
+
182
+ parser .add_argument ('-d' , '--detail' , action = 'store_true' , help = 'LLDP neighbors detail information' , default = False )
183
+ parser .add_argument ('-p' , '--port' , type = str , help = 'LLDP neighbors detail information for given port' , default = None )
184
+ args = parser .parse_args ()
185
+
186
+ lldp_detail_info = args .detail
187
+ lldp_port = args .port
188
+
189
+ if lldp_port and not lldp_detail_info :
190
+ lldp_detail_info = True
191
+
118
192
try :
119
193
lldp = Lldpshow ()
120
- lldp .get_info ()
121
- lldp .parse_info ()
122
- lldp .display_sum ()
194
+ lldp .get_info (lldp_detail_info , lldp_port )
195
+ lldp .parse_info (lldp_detail_info )
196
+ lldp .display_sum (lldp_detail_info )
123
197
except Exception as e :
124
198
print (e .message , file = sys .stderr )
125
199
sys .exit (1 )
0 commit comments