25
25
from scapy .all import conf , in6_getnsma , inet_pton , inet_ntop , in6_getnsmac , get_if_hwaddr , Ether , ARP , IPv6 , ICMPv6ND_NS , ICMPv6NDOptSrcLLAddr
26
26
from swsscommon import swsscommon
27
27
import errno
28
+ import syslog
28
29
29
30
logger = logging .getLogger (__name__ )
30
31
logger .setLevel (logging .WARNING )
31
32
logger .addHandler (logging .NullHandler ())
32
33
34
+ SYSLOG_IDENTIFIER = 'restore_neighbor'
35
+
36
+ def log_info (msg ):
37
+ syslog .openlog (SYSLOG_IDENTIFIER )
38
+ syslog .syslog (syslog .LOG_INFO , msg )
39
+ syslog .closelog ()
40
+
41
+ def log_warning (msg ):
42
+ syslog .openlog (SYSLOG_IDENTIFIER )
43
+ syslog .syslog (syslog .LOG_WARNING , msg )
44
+ syslog .closelog ()
45
+
46
+ def log_error (msg ):
47
+ syslog .openlog (SYSLOG_IDENTIFIER )
48
+ syslog .syslog (syslog .LOG_ERR , msg )
49
+ syslog .closelog ()
50
+
33
51
# timeout the restore process in 110 seconds if not finished
34
52
# This is mostly to wait for interfaces to be created and up after system warm-reboot
35
53
# and this process is started by supervisord in swss docker.
@@ -58,12 +76,27 @@ def is_intf_oper_state_up(intf):
58
76
state_file = open (oper_file .format (intf ), 'r' )
59
77
state = state_file .readline ().rstrip ()
60
78
except Exception as e :
61
- logger . info ('Error: {}' .format (str (e )))
79
+ log_info ('Error: {}' .format (str (e )))
62
80
return False
63
81
if state == '1' :
64
82
return True
65
83
return False
66
84
85
+ def is_intf_up (intf , db ):
86
+ if not is_intf_oper_state_up (intf ):
87
+ return False
88
+ if 'Vlan' in intf :
89
+ table_name = 'VLAN_MEMBER_TABLE|{}|*' .format (intf )
90
+ key = db .keys (db .STATE_DB , table_name )
91
+ if key is None :
92
+ log_info ("Vlan member is not yet created" )
93
+ return False
94
+ if is_intf_up .counter == 0 :
95
+ time .sleep (3 * CHECK_INTERVAL )
96
+ is_intf_up .counter = 1
97
+ log_info ("intf {} is up" .format (intf ))
98
+ return True
99
+
67
100
# read the neigh table from AppDB to memory, format as below
68
101
# build map as below, this can efficiently access intf and family groups later
69
102
# { intf1 -> { { family1 -> [[ip1, mac1], [ip2, mac2] ...] }
@@ -131,7 +164,7 @@ def read_neigh_table_to_maps():
131
164
132
165
# Use netlink to set neigh table into kernel, not overwrite the existing ones
133
166
def set_neigh_in_kernel (ipclass , family , intf_idx , dst_ip , dmac ):
134
- logging . info ('Add neighbor entries: family: {}, intf_idx: {}, ip: {}, mac: {}' .format (
167
+ log_info ('Add neighbor entries: family: {}, intf_idx: {}, ip: {}, mac: {}' .format (
135
168
family , intf_idx , dst_ip , dmac ))
136
169
137
170
if family not in ip_family :
@@ -152,7 +185,7 @@ def set_neigh_in_kernel(ipclass, family, intf_idx, dst_ip, dmac):
152
185
# If neigh exists, log it but no exception raise, other exceptions, raise
153
186
except NetlinkError as e :
154
187
if e [0 ] == errno .EEXIST :
155
- logger . warning ('Neigh exists in kernel with family: {}, intf_idx: {}, ip: {}, mac: {}' .format (
188
+ log_warning ('Neigh exists in kernel with family: {}, intf_idx: {}, ip: {}, mac: {}' .format (
156
189
family , intf_idx , dst_ip , dmac ))
157
190
else :
158
191
raise
@@ -196,10 +229,13 @@ def restore_update_kernel_neighbors(intf_neigh_map, timeout=DEF_TIME_OUT):
196
229
ipclass = IPRoute ()
197
230
mtime = monotonic .time .time
198
231
start_time = mtime ()
232
+ is_intf_up .counter = 0
233
+ db = swsssdk .SonicV2Connector (host = '127.0.0.1' )
234
+ db .connect (db .STATE_DB , False )
199
235
while (mtime () - start_time ) < timeout :
200
236
for intf , family_neigh_map in intf_neigh_map .items ():
201
237
# only try to restore to kernel when link is up
202
- if is_intf_oper_state_up (intf ):
238
+ if is_intf_up (intf , db ):
203
239
src_mac = get_if_hwaddr (intf )
204
240
intf_idx = ipclass .link_lookup (ifname = intf )[0 ]
205
241
# create socket per intf to send packets
@@ -215,6 +251,8 @@ def restore_update_kernel_neighbors(intf_neigh_map, timeout=DEF_TIME_OUT):
215
251
# use netlink to set neighbor entries
216
252
set_neigh_in_kernel (ipclass , family , intf_idx , dst_ip , dmac )
217
253
254
+ log_info ('Sending Neigh with family: {}, intf_idx: {}, ip: {}, mac: {}' .format (
255
+ family , intf_idx , dst_ip , dmac ))
218
256
# sending arp/ns packet to update kernel neigh info
219
257
s .send (build_arp_ns_pkt (family , src_mac , src_ip , dst_ip ))
220
258
# delete this family on the intf
@@ -229,28 +267,27 @@ def restore_update_kernel_neighbors(intf_neigh_map, timeout=DEF_TIME_OUT):
229
267
if not intf_neigh_map :
230
268
break
231
269
time .sleep (CHECK_INTERVAL )
270
+ db .close (db .STATE_DB )
232
271
233
272
234
273
def main ():
235
274
236
- print "restore_neighbors service is started"
237
-
275
+ log_info ("restore_neighbors service is started" )
238
276
# Use warmstart python binding to check warmstart information
239
277
warmstart = swsscommon .WarmStart ()
240
278
warmstart .initialize ("neighsyncd" , "swss" )
241
279
warmstart .checkWarmStart ("neighsyncd" , "swss" , False )
242
280
243
281
# if swss or system warm reboot not enabled, don't run
244
282
if not warmstart .isWarmStart ():
245
- print "restore_neighbors service is skipped as warm restart not enabled"
283
+ log_info ( "restore_neighbors service is skipped as warm restart not enabled" )
246
284
return
247
285
248
286
# swss restart not system warm reboot, set statedb directly
249
287
if not warmstart .isSystemWarmRebootEnabled ():
250
288
set_statedb_neigh_restore_done ()
251
- print "restore_neighbors service is done as system warm reboot not enabled"
289
+ log_info ( "restore_neighbors service is done as system warm reboot not enabled" )
252
290
return
253
-
254
291
# read the neigh table from appDB to internal map
255
292
try :
256
293
intf_neigh_map = read_neigh_table_to_maps ()
@@ -266,7 +303,7 @@ def main():
266
303
267
304
# set statedb to signal other processes like neighsyncd
268
305
set_statedb_neigh_restore_done ()
269
- print "restore_neighbor service is done for system warmreboot"
306
+ log_info ( "restore_neighbor service is done for system warmreboot" )
270
307
return
271
308
272
309
if __name__ == '__main__' :
0 commit comments