3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from ifupdown
.iface
import *
13 import ifupdown
.policymanager
as policymanager
15 import ifupdown
.rtnetlink_api
as rtnetlink_api
16 import ifupdown
.ifupdownflags
as ifupdownflags
17 from ifupdownaddons
.modulebase
import moduleBase
18 from ifupdownaddons
.bondutil
import bondutil
19 from ifupdownaddons
.iproute2
import iproute2
20 from ifupdownaddons
.dhclient
import dhclient
25 class vrf(moduleBase
):
26 """ ifupdown2 addon module to configure vrfs """
27 _modinfo
= { 'mhelp' : 'vrf configuration module',
30 {'help' : 'vrf device table id. key to ' +
31 'creating a vrf device',
32 'example': ['vrf-table-id 1']},
34 {'help' : 'vrf device default route ' +
35 'to avoid communication outside the vrf device',
36 'example': ['vrf-default-route yes/no']},
38 {'help' : 'vrf the interface is part of.',
39 'example': ['vrf blue']}}}
41 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
42 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
43 '# It contains the vrf name to table mapping.\n' + \
44 '# Reserved table range %s %s\n'
45 VRF_TABLE_START
= 1001
48 def __init__(self
, *args
, **kargs
):
49 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
52 self
.dhclientcmd
= None
53 self
.name
= self
.__class
__.__name
__
54 if ifupdownflags
.flags
.PERFMODE
:
55 # if perf mode is set, remove vrf map file.
56 # start afresh. PERFMODE is set at boot
57 if os
.path
.exists(self
.iproute2_vrf_filename
):
59 self
.logger
.info('vrf: removing file %s'
60 %self
.iproute2_vrf_filename
)
61 os
.remove(self
.iproute2_vrf_filename
)
63 self
.logger
.debug('vrf: removing file failed (%s)'
66 ip_rules
= self
.exec_command('/sbin/ip rule show').splitlines()
67 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
69 self
.ip_rule_cache
= []
70 self
.logger
.warn('%s' %str
(e
))
73 ip_rules
= self
.exec_command('/sbin/ip -6 rule show').splitlines()
74 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
76 self
.ip6_rule_cache
= []
77 self
.logger
.warn('%s' %str
(e
))
79 #self.logger.debug("vrf: ip rule cache")
80 #self.logger.info(self.ip_rule_cache)
82 #self.logger.info("vrf: ip -6 rule cache")
83 #self.logger.info(self.ip6_rule_cache)
85 self
._iproute
2_vrf
_map
_initialized
= False
86 self
.iproute2_vrf_map
= {}
87 self
.iproute2_vrf_map_fd
= None
88 self
.iproute2_vrf_map_sync_to_disk
= False
90 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
91 if not self
.vrf_table_id_start
:
92 self
.vrf_table_id_start
= self
.VRF_TABLE_START
93 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
94 if not self
.vrf_table_id_end
:
95 self
.vrf_table_id_end
= self
.VRF_TABLE_END
96 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
98 self
.vrf_fix_local_table
= True
100 self
.vrf_cgroup_create
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-cgroup-create')
102 if not self
.vrf_cgroup_create
:
103 self
.vrf_cgroup_create
= False
104 elif self
.vrf_cgroup_create
== 'yes':
105 self
.vrf_cgroup_create
= True
107 self
.vrf_cgroup_create
= False
108 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
109 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
111 def _iproute2_vrf_map_initialize(self
):
112 if self
._iproute
2_vrf
_map
_initialized
:
115 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
116 self
.iproute2_vrf_map
= {}
117 iproute2_vrf_map_force_rewrite
= False
118 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
119 if os
.path
.exists(self
.iproute2_vrf_filename
):
120 vrf_map_fd
= open(self
.iproute2_vrf_filename
, 'r+')
121 lines
= vrf_map_fd
.readlines()
127 (table
, vrf_name
) = l
.strip().split()
128 if self
.iproute2_vrf_map
.get(int(table
)):
129 # looks like the existing file has
130 # duplicate entries, force rewrite of the
132 iproute2_vrf_map_force_rewrite
= True
134 self
.iproute2_vrf_map
[int(table
)] = vrf_name
136 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
140 vrfs
= self
.ipcmd
.link_get_vrfs()
143 for v
, lattrs
in vrfs
.iteritems():
144 table
= lattrs
.get('table', None)
146 running_vrf_map
[int(table
)] = v
148 if running_vrf_map
and (running_vrf_map
!= self
.iproute2_vrf_map
):
149 self
.iproute2_vrf_map
= running_vrf_map
150 iproute2_vrf_map_force_rewrite
= True
152 self
.iproute2_vrf_map_fd
= None
153 if iproute2_vrf_map_force_rewrite
:
154 # reopen the file and rewrite the map
155 self
._iproute
2_vrf
_map
_open
(True, False)
157 self
._iproute
2_vrf
_map
_open
(False, True)
159 self
.iproute2_vrf_map_sync_to_disk
= False
160 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
162 self
.logger
.info("vrf: dumping iproute2_vrf_map")
163 self
.logger
.info(self
.iproute2_vrf_map
)
165 last_used_vrf_table
= None
166 for t
in range(self
.vrf_table_id_start
,
167 self
.vrf_table_id_end
):
168 if not self
.iproute2_vrf_map
.get(t
):
170 last_used_vrf_table
= t
171 self
.last_used_vrf_table
= last_used_vrf_table
172 self
._iproute
2_vrf
_map
_initialized
= True
174 def _iproute2_vrf_map_sync_to_disk(self
):
175 if not self
.iproute2_vrf_map_sync_to_disk
:
177 self
.logger
.info('vrf: syncing table map to %s'
178 %self
.iproute2_vrf_filename
)
179 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
180 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
181 self
.vrf_table_id_end
))
182 for t
, v
in self
.iproute2_vrf_map
.iteritems():
183 f
.write('%s %s\n' %(t
, v
))
186 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
187 self
.logger
.info('vrf: syncing table map to %s'
188 %self
.iproute2_vrf_filename
)
189 fmode
= 'a+' if append
else 'w'
191 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
194 self
.log_warn('vrf: error opening %s (%s)'
195 %(self
.iproute2_vrf_filename
, str(e
)))
200 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
201 %(self
.vrf_table_id_start
,
202 self
.vrf_table_id_end
))
203 for t
, v
in self
.iproute2_vrf_map
.iteritems():
204 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
205 self
.iproute2_vrf_map_fd
.flush()
207 def _is_vrf(self
, ifaceobj
):
208 if ifaceobj
.get_attr_value_first('vrf-table'):
212 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
213 """ Returns list of interfaces dependent on ifaceobj """
215 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
217 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
218 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
219 ifaceobj
.role |
= ifaceRole
.MASTER
220 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
221 if not vrf_iface_name
:
223 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
224 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
226 return [vrf_iface_name
]
228 def get_upper_ifacenames_running(self
, ifaceobj
):
231 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
232 for t
, v
in self
.iproute2_vrf_map
.iteritems():
233 if v
== vrf_dev_name
:
237 def _get_avail_vrf_table_id(self
):
238 if self
.last_used_vrf_table
== None:
239 table_id_start
= self
.vrf_table_id_start
241 table_id_start
= self
.last_used_vrf_table
+ 1
242 for t
in range(table_id_start
,
243 self
.vrf_table_id_end
):
244 if not self
.iproute2_vrf_map
.get(t
):
245 self
.last_used_vrf_table
= t
249 def _iproute2_is_vrf_tableid_inuse(self
, vrf_dev_name
, table_id
):
250 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
251 if old_vrf_name
and old_vrf_name
!= vrf_dev_name
:
252 self
.log_error('table id %s already assigned to vrf dev %s'
253 %(table_id
, old_vrf_name
))
255 def _iproute2_vrf_table_entry_add(self
, vrf_dev_name
, table_id
):
256 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
258 self
.iproute2_vrf_map
[int(table_id
)] = vrf_dev_name
259 if self
.iproute2_vrf_map_fd
:
260 self
.iproute2_vrf_map_fd
.write('%s %s\n'
261 %(table_id
, vrf_dev_name
))
262 self
.iproute2_vrf_map_fd
.flush()
265 if old_vrf_name
!= vrf_dev_name
:
266 self
.log_error('table id %d already assigned to vrf dev %s'
267 %(table_id
, old_vrf_name
))
269 def _iproute2_vrf_table_entry_del(self
, table_id
):
271 # with any del of vrf map, we need to force sync to disk
272 self
.iproute2_vrf_map_sync_to_disk
= True
273 del self
.iproute2_vrf_map
[int(table_id
)]
275 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
279 def _is_vrf_dev(self
, ifacename
):
280 # Look at iproute2 map for now.
281 # If it was a master we knew about,
282 # it is definately there
283 if ifacename
in self
.iproute2_vrf_map
.values():
287 def _is_dhcp_slave(self
, ifaceobj
):
288 if (not ifaceobj
.addr_method
or
289 (ifaceobj
.addr_method
!= 'dhcp' and
290 ifaceobj
.addr_method
!= 'dhcp6')):
294 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
296 """ If we have a vrf slave that has dhcp configured, bring up the
297 vrf master now. This is needed because vrf has special handling
298 in dhclient hook which requires the vrf master to be present """
300 vrf_master
= ifaceobj
.upperifaces
[0]
302 self
.logger
.warn('%s: vrf master not found' %ifacename
)
304 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
305 self
.logger
.info('%s: vrf master %s exists returning'
306 %(ifacename
, vrf_master
))
308 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
309 if not vrf_master_objs
:
310 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
312 self
.logger
.info('%s: bringing up vrf master %s'
313 %(ifacename
, vrf_master
))
314 for mobj
in vrf_master_objs
:
315 vrf_table
= mobj
.get_attr_value_first('vrf-table')
317 if vrf_table
== 'auto':
318 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
320 self
.log_error('%s: unable to get an auto table id'
322 self
.logger
.info('%s: table id auto: selected table id %s\n'
323 %(mobj
.name
, vrf_table
))
325 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
329 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
330 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
333 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
335 dhclient_cmd_prefix
= None
336 if (vrfname
and self
.vrf_exec_cmd_prefix
and
337 self
.ipcmd
.link_exists(vrfname
)):
338 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
340 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
342 # ignore any dhclient release errors
345 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
346 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
348 if (self
.vrf_mgmt_devname
and
349 self
.vrf_mgmt_devname
== vrfname
):
350 self
._kill
_ssh
_connections
(ifaceobj
.name
)
351 if self
._is
_dhcp
_slave
(ifaceobj
):
352 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
354 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
355 ifaceobj_getfunc
=None, vrf_exists
=False):
357 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
358 upper
= self
.ipcmd
.link_get_upper(ifacename
)
359 if not upper
or upper
!= vrfname
:
360 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
361 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
363 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
365 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
367 self
.log_error('%s: %s' %(ifacename
, str(e
)))
369 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
371 ip_rule_out_format
= '%s: from all %s %s lookup %s'
372 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
374 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
375 if rule
in self
.ip_rule_cache
:
376 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
378 self
.exec_command(rule_cmd
)
380 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
381 if rule
in self
.ip_rule_cache
:
382 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
384 self
.exec_command(rule_cmd
)
386 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
387 if rule
in self
.ip6_rule_cache
:
388 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
390 self
.exec_command(rule_cmd
)
392 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
393 if rule
in self
.ip6_rule_cache
:
394 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
396 self
.exec_command(rule_cmd
)
398 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
400 ip_rule_out_format
= '%s: from all %s %s lookup %s'
401 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
402 if self
.vrf_fix_local_table
:
403 self
.vrf_fix_local_table
= False
404 rule
= '0: from all lookup local'
405 if rule
in self
.ip_rule_cache
:
407 self
.exec_command('ip rule del pref 0')
408 self
.exec_command('ip rule add pref 32765 table local')
410 self
.logger
.info('%s' %str
(e
))
412 if rule
in self
.ip6_rule_cache
:
414 self
.exec_command('ip -6 rule del pref 0')
415 self
.exec_command('ip -6 rule add pref 32765 table local')
417 self
.logger
.info('%s' %str
(e
))
421 #200: from all oif blue lookup blue
422 #200: from all iif blue lookup blue
424 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
425 if rule
not in self
.ip_rule_cache
:
426 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
428 self
.exec_command(rule_cmd
)
430 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
431 if rule
not in self
.ip_rule_cache
:
432 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
434 self
.exec_command(rule_cmd
)
436 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
437 if rule
not in self
.ip6_rule_cache
:
438 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
440 self
.exec_command(rule_cmd
)
442 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
443 if rule
not in self
.ip6_rule_cache
:
444 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
446 self
.exec_command(rule_cmd
)
448 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
449 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
450 config_slaves
= ifaceobj
.lowerifaces
451 if not config_slaves
and not running_slaves
:
454 if not config_slaves
: config_slaves
= []
455 if not running_slaves
: running_slaves
= []
456 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
457 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
463 sobj
= ifaceobj_getfunc(s
)
464 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
465 sobj
[0] if sobj
else None,
466 ifaceobj_getfunc
, True)
468 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
475 sobj
= ifaceobj_getfunc(s
)
476 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
479 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
481 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
482 for s
in config_slaves
:
484 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
486 self
.logger
.debug('%s: %s: link set up (%s)'
487 %(ifaceobj
.name
, s
, str(e
)))
490 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
491 ifaceobj
.module_flags
[self
.name
] = \
492 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
493 vrfPrivFlags
.PROCESSED
495 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
496 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
500 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
501 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
502 if vrf_table
== 'auto':
503 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
505 self
.log_error('%s: unable to get an auto table id'
507 self
.logger
.info('%s: table id auto: selected table id %s\n'
508 %(ifaceobj
.name
, vrf_table
))
510 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
.name
, vrf_table
)
512 if not vrf_table
.isdigit():
513 self
.log_error('%s: vrf-table must be an integer or \'auto\''
514 %(ifaceobj
.name
), ifaceobj
)
516 # XXX: If we decide to not allow vrf id usages out of
517 # the reserved ifupdown range, then uncomment this code.
519 if (int(vrf_table
) < self
.vrf_table_id_start
or
520 int(vrf_table
) > self
.vrf_table_id_end
):
521 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
522 %(ifaceobj
.name
, vrf_table
,
523 self
.vrf_table_id_start
,
524 self
.vrf_table_id_end
))
526 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
527 {'table' : '%s' %vrf_table
})
529 self
.log_error('%s: create failed (%s)\n'
530 %(ifaceobj
.name
, str(e
)))
531 if vrf_table
!= 'auto':
532 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
.name
, vrf_table
)
534 if vrf_table
== 'auto':
535 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
537 self
.log_error('%s: unable to get vrf table id'
540 # if the device exists, check if table id is same
541 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
543 running_table
= vrfdev_attrs
.get('table', None)
544 if vrf_table
!= running_table
:
545 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
546 running_table
, vrf_table
))
549 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
551 self
.exec_command('%s create %s %s' %(self
.vrf_helper
,
552 ifaceobj
.name
, vrf_table
))
554 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
555 ifaceobj_getfunc
=None):
557 # if vrf dev is already processed return. This can happen
558 # if we the slave was configured before.
559 # see self._up_vrf_slave_without_master
560 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
564 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
566 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)))
569 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
570 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
572 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
573 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
574 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
576 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)))
578 def _kill_ssh_connections(self
, ifacename
):
580 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
581 if not runningaddrsdict
:
583 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
588 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
589 #users:(("sshd",pid=2528,fd=3))
590 cmdl
= ['/bin/ss', '-t', '-p']
591 for line
in subprocess
.check_output(cmdl
, stderr
=subprocess
.STDOUT
,
592 shell
=False).splitlines():
593 citems
= line
.split()
596 addr
= citems
[3].split('%')[0]
597 elif ':ssh' in citems
[3]:
598 addr
= citems
[3].split(':')[0]
603 proc
.append(citems
[5].split(',')[1].split('=')[1])
607 pid
= subprocess
.check_output(['/bin/ps', '--no-headers',
608 '-fp', str(os
.getppid())],
609 stderr
=subprocess
.STDOUT
,
610 shell
=False).split()[2]
611 self
.logger
.info("%s: killing active ssh sessions: %s"
612 %(ifacename
, str(proc
)))
616 os
.kill(int(id), signal
.SIGINT
)
620 # Kill current SSH client
625 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
626 if (forkret
== 0): # The first child.
629 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
630 except OSError, (err_no
, err_message
):
631 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
632 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
634 self
.logger
.info("%s: killing our session: %s"
635 %(ifacename
, str(proc
)))
636 os
.kill(int(pid
), signal
.SIGINT
)
641 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
643 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
645 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
647 self
._iproute
2_vrf
_map
_initialize
()
648 # This is a vrf device
649 if self
.vrf_count
== self
.vrf_max_count
:
650 self
.log_error('%s: max vrf count %d hit...not '
651 'creating vrf' %(ifaceobj
.name
,
653 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
655 vrf
= ifaceobj
.get_attr_value_first('vrf')
657 self
._iproute
2_vrf
_map
_initialize
()
658 # This is a vrf slave
659 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
662 # check if we were a slave before
663 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
665 self
._iproute
2_vrf
_map
_initialize
()
666 if self
._is
_vrf
_dev
(master
):
667 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
670 self
.log_error(str(e
))
672 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
674 self
.exec_command('%s delete %s %s' %(self
.vrf_helper
,
675 ifaceobj
.name
, vrf_table
))
677 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
679 if vrf_table
== 'auto':
680 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
683 self
.exec_command('/usr/bin/vrf service disable %s' %ifaceobj
.name
)
685 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
689 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
691 for s
in running_slaves
:
693 sobj
= ifaceobj_getfunc(s
)
694 self
._handle
_existing
_connections
(sobj
[0] if sobj
else None,
697 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
700 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
703 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
705 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
709 self
.ipcmd
.link_delete(ifaceobj
.name
)
711 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
715 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
717 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
721 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
723 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
724 self
.ipcmd
.link_set(ifacename
, 'nomaster')
725 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
727 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
729 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
731 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
733 self
._iproute
2_vrf
_map
_initialize
()
734 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
736 vrf
= ifaceobj
.get_attr_value_first('vrf')
738 self
._iproute
2_vrf
_map
_initialize
()
739 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
741 self
.log_warn(str(e
))
743 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
745 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
746 if not master
or master
!= vrf
:
747 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
749 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
751 self
.log_warn(str(e
))
753 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
755 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
756 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
758 if vrf_table
== 'auto':
759 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
761 config_table
= vrf_table
762 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
764 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
766 running_table
= vrfdev_attrs
.get('table')
767 if not running_table
:
768 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
770 if config_table
!= running_table
:
771 ifaceobjcurr
.update_config_with_status('vrf-table',
774 ifaceobjcurr
.update_config_with_status('vrf-table',
777 self
.log_warn(str(e
))
779 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
781 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
783 self
._iproute
2_vrf
_map
_initialize
()
784 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
786 vrf
= ifaceobj
.get_attr_value_first('vrf')
788 self
._iproute
2_vrf
_map
_initialize
()
789 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
791 self
.log_warn(str(e
))
793 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
795 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
797 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
799 running_table
= vrfdev_attrs
.get('table')
801 ifaceobjrunning
.update_config('vrf-table',
803 elif kind
== 'vrf_slave':
804 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
806 ifaceobjrunning
.update_config('vrf', vrf
)
808 self
.log_warn(str(e
))
810 _run_ops
= {'pre-up' : _up
,
812 'query-running' : _query_running
,
813 'query-checkcurr' : _query_check
}
816 """ returns list of ops supported by this module """
817 return self
._run
_ops
.keys()
819 def _init_command_handlers(self
):
821 self
.ipcmd
= iproute2()
823 self
.bondcmd
= bondutil()
824 if not self
.dhclientcmd
:
825 self
.dhclientcmd
= dhclient()
827 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
828 ifaceobj_getfunc
=None, **extra_args
):
829 """ run bond configuration on the interface object passed as argument
832 **ifaceobj** (object): iface object
834 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
838 **query_ifaceobj** (object): query check ifaceobject. This is only
839 valid when op is 'query-checkcurr'. It is an object same as
840 ifaceobj, but contains running attribute values and its config
841 status. The modules can use it to return queried running state
842 of interfaces. status is success if the running state is same
843 as user required state in ifaceobj. error otherwise.
845 op_handler
= self
._run
_ops
.get(operation
)
848 self
._init
_command
_handlers
()
849 if operation
== 'query-checkcurr':
850 op_handler(self
, ifaceobj
, query_ifaceobj
)
852 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)