@@ -30,6 +30,8 @@ VERSION = "1.0"
30
30
31
31
SYSLOG_IDENTIFIER = "lldpmgrd"
32
32
PORT_INIT_TIMEOUT = 300
33
+ FAILED_CMD_TIMEOUT = 6
34
+ RETRY_LIMIT = 5
33
35
34
36
35
37
class LldpManager (daemon_base .DaemonBase ):
@@ -41,7 +43,8 @@ class LldpManager(daemon_base.DaemonBase):
41
43
state_db: Handle to Redis State database via swsscommon lib
42
44
config_db: Handle to Redis Config database via swsscommon lib
43
45
pending_cmds: Dictionary where key is port name, value is pending
44
- LLDP configuration command to run
46
+ LLDP configuration command to run
47
+ and the last timestamp that this command was failed (used for retry mechanism)
45
48
"""
46
49
REDIS_TIMEOUT_MS = 0
47
50
@@ -58,6 +61,11 @@ class LldpManager(daemon_base.DaemonBase):
58
61
self .REDIS_TIMEOUT_MS ,
59
62
False )
60
63
64
+ # Open a handle to the State database
65
+ self .state_db = swsscommon .DBConnector ("STATE_DB" ,
66
+ self .REDIS_TIMEOUT_MS ,
67
+ False )
68
+
61
69
self .pending_cmds = {}
62
70
self .hostname = "None"
63
71
self .mgmt_ip = "None"
@@ -66,6 +74,7 @@ class LldpManager(daemon_base.DaemonBase):
66
74
self .port_table = swsscommon .Table (self .config_db , swsscommon .CFG_PORT_TABLE_NAME )
67
75
self .mgmt_table = swsscommon .Table (self .config_db , swsscommon .CFG_MGMT_INTERFACE_TABLE_NAME )
68
76
self .app_port_table = swsscommon .Table (self .appl_db , swsscommon .APP_PORT_TABLE_NAME )
77
+ self .state_port_table = swsscommon .Table (self .state_db , swsscommon .STATE_PORT_TABLE_NAME )
69
78
70
79
def update_hostname (self , hostname ):
71
80
cmd = "lldpcli configure system hostname {0}" .format (hostname )
@@ -99,32 +108,25 @@ class LldpManager(daemon_base.DaemonBase):
99
108
100
109
def is_port_up (self , port_name ):
101
110
"""
102
- Determine if a port is up or down by looking into the oper-status for the port in
103
- PORT TABLE in the Application DB
111
+ Determine if a port is up or down by looking into the netdev_oper_status for the port in
112
+ PORT TABLE in the State DB
104
113
"""
105
114
# Retrieve all entires for this port from the Port table
106
- (status , fvp ) = self .app_port_table .get (port_name )
115
+ (status , fvp ) = self .state_port_table .get (port_name )
107
116
if status :
108
117
# Convert list of tuples to a dictionary
109
118
port_table_dict = dict (fvp )
110
119
111
120
# Get the oper-status for the port
112
- if "oper_status" in port_table_dict :
113
- port_oper_status = port_table_dict .get ("oper_status" )
114
- self .log_info ("Port name {} oper status: {}" .format (port_name , port_oper_status ))
121
+ if "netdev_oper_status" in port_table_dict :
122
+ port_oper_status = port_table_dict .get ("netdev_oper_status" )
115
123
return port_oper_status == "up"
116
124
else :
117
125
return False
118
126
else :
119
- # Retrieve PortInitDone entry from the Port table
120
- (init_status , init_fvp ) = self .port_table .get ("PortInitDone" )
121
- # The initialization procedure is done, but don't have this port entry
122
- if init_status :
123
- self .log_error ("Port '{}' not found in {} table in App DB" .format (
124
- port_name , swsscommon .APP_PORT_TABLE_NAME ))
125
127
return False
126
128
127
- def generate_pending_lldp_config_cmd_for_port (self , port_name ):
129
+ def generate_pending_lldp_config_cmd_for_port (self , port_name , port_table_dict ):
128
130
"""
129
131
For port `port_name`, look up the description and alias in the Config database,
130
132
then form the appropriate lldpcli configuration command and run it.
@@ -135,27 +137,16 @@ class LldpManager(daemon_base.DaemonBase):
135
137
# asic-to-asic communication in VOQ based chassis system. We do not configure LLDP on these.
136
138
if port_name .startswith (inband_prefix ()):
137
139
return
138
-
139
- # Retrieve all entires for this port from the Port table
140
- (status , fvp ) = self .port_table .get (port_name )
141
- if status :
142
- # Convert list of tuples to a dictionary
143
- port_table_dict = dict (fvp )
144
-
145
- # Get the port alias. If None or empty string, use port name instead
146
- port_alias = port_table_dict .get ("alias" )
147
- if not port_alias :
148
- self .log_info ("Unable to retrieve port alias for port '{}'. Using port name instead." .format (port_name ))
149
- port_alias = port_name
150
-
151
- # Get the port description. If None or empty string, we'll skip this configuration
152
- port_desc = port_table_dict .get ("description" )
153
-
154
- else :
155
- self .log_error ("Port '{}' not found in {} table in Config DB. Using port name instead of port alias." .format (
156
- port_name , swsscommon .CFG_PORT_TABLE_NAME ))
140
+
141
+ # Get the port alias. If None or empty string, use port name instead
142
+ port_alias = port_table_dict .get ("alias" )
143
+ if not port_alias :
144
+ self .log_info ("Unable to retrieve port alias for port '{}'. Using port name instead." .format (port_name ))
157
145
port_alias = port_name
158
-
146
+
147
+ # Get the port description. If None or empty string, we'll skip this configuration
148
+ port_desc = port_table_dict .get ("description" )
149
+
159
150
lldpcli_cmd = "lldpcli configure ports {0} lldp portidsubtype local {1}" .format (port_name , port_alias )
160
151
161
152
# if there is a description available, also configure that
@@ -166,17 +157,25 @@ class LldpManager(daemon_base.DaemonBase):
166
157
167
158
# Add the command to our dictionary of pending commands, overwriting any
168
159
# previous pending command for this port
169
- self .pending_cmds [port_name ] = lldpcli_cmd
160
+ self .pending_cmds [port_name ] = { 'cmd' : lldpcli_cmd , 'failed_count' : 0 }
170
161
171
162
def process_pending_cmds (self ):
172
163
# List of port names (keys of elements) to delete from self.pending_cmds
173
164
to_delete = []
174
165
175
- for (port_name , cmd ) in self .pending_cmds .items ():
176
- self . log_debug ( "Running command: '{}'" . format ( cmd ))
166
+ for (port_name , port_item ) in self .pending_cmds .items ():
167
+ cmd = port_item [ ' cmd' ]
177
168
178
- rc , stderr = run_cmd (self , cmd )
169
+ # check if linux port is up
170
+ if not self .is_port_up (port_name ):
171
+ self .log_info ("port %s is not up, continue" % port_name )
172
+ continue
173
+
174
+ if 'failed_timestamp' in port_item and time .time ()- port_item ['failed_timestamp' ]< FAILED_CMD_TIMEOUT :
175
+ continue
179
176
177
+ self .log_debug ("Running command: '{}'" .format (cmd ))
178
+ rc , stderr = run_cmd (self , cmd )
180
179
# If the command succeeds, add the port name to our to_delete list.
181
180
# We will delete this command from self.pending_cmds below.
182
181
# If the command fails, log a message, but don't delete the command
@@ -185,8 +184,15 @@ class LldpManager(daemon_base.DaemonBase):
185
184
if rc == 0 :
186
185
to_delete .append (port_name )
187
186
else :
188
- self .log_warning ("Command failed '{}': {}" .format (cmd , stderr ))
189
-
187
+ if port_item ['failed_count' ] >= RETRY_LIMIT :
188
+ self .log_error ("Command failed '{}': {} - command was failed {} times, disabling retry" .format (cmd , stderr , RETRY_LIMIT + 1 ))
189
+ # not retrying again
190
+ to_delete .append (port_name )
191
+ else :
192
+ self .pending_cmds [port_name ]['failed_count' ] += 1
193
+ self .pending_cmds [port_name ]['failed_timestamp' ] = time .time ()
194
+ self .log_info ("Command failed '{}': {} - cmd failed {} times, retrying again" .format (cmd , stderr , self .pending_cmds [port_name ]['failed_count' ]))
195
+
190
196
# Delete all successful commands from self.pending_cmds
191
197
for port_name in to_delete :
192
198
self .pending_cmds .pop (port_name , None )
@@ -268,10 +274,6 @@ class LldpManager(daemon_base.DaemonBase):
268
274
269
275
sel = swsscommon .Select ()
270
276
271
- # Subscribe to PORT table notifications in the Config DB
272
- sst_confdb = swsscommon .SubscriberStateTable (self .config_db , swsscommon .CFG_PORT_TABLE_NAME )
273
- sel .addSelectable (sst_confdb )
274
-
275
277
# Subscribe to PORT table notifications in the App DB
276
278
sst_appdb = swsscommon .SubscriberStateTable (self .appl_db , swsscommon .APP_PORT_TABLE_NAME )
277
279
sel .addSelectable (sst_appdb )
@@ -289,17 +291,6 @@ class LldpManager(daemon_base.DaemonBase):
289
291
(state , c ) = sel .select (SELECT_TIMEOUT_MS )
290
292
291
293
if state == swsscommon .Select .OBJECT :
292
- (key , op , fvp ) = sst_confdb .pop ()
293
- if fvp :
294
- fvp_dict = dict (fvp )
295
-
296
- # handle config change
297
- if ("alias" in fvp_dict or "description" in fvp_dict ) and (op in ["SET" , "DEL" ]):
298
- if self .is_port_up (key ):
299
- self .generate_pending_lldp_config_cmd_for_port (key )
300
- else :
301
- self .pending_cmds .pop (key , None )
302
-
303
294
(key , op , fvp ) = sst_mgmt_ip_confdb .pop ()
304
295
if key :
305
296
self .lldp_process_mgmt_info_change (op , dict (fvp ), key )
@@ -310,15 +301,16 @@ class LldpManager(daemon_base.DaemonBase):
310
301
311
302
(key , op , fvp ) = sst_appdb .pop ()
312
303
if (key != "PortInitDone" ) and (key != "PortConfigDone" ):
313
- if fvp :
314
- fvp_dict = dict (fvp )
315
-
316
- # handle port status change
317
- if "oper_status" in fvp_dict :
318
- if "up" in fvp_dict .get ("oper_status" ):
319
- self .generate_pending_lldp_config_cmd_for_port (key )
304
+ if op == "SET" :
305
+ if fvp :
306
+ if "up" in dict (fvp ).get ("oper_status" ,"" ):
307
+ self .generate_pending_lldp_config_cmd_for_port (key , dict (fvp ))
320
308
else :
321
309
self .pending_cmds .pop (key , None )
310
+ elif op == "DEL" :
311
+ self .pending_cmds .pop (key , None )
312
+ else :
313
+ self .log_error ("unknown operation" )
322
314
323
315
elif key == "PortInitDone" :
324
316
port_init_done = True
0 commit comments