3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from ifupdown
.iface
import *
13 from ifupdown
.utils
import utils
14 import ifupdown
.policymanager
as policymanager
16 import ifupdown
.rtnetlink_api
as rtnetlink_api
17 import ifupdown
.ifupdownflags
as ifupdownflags
18 from ifupdownaddons
.modulebase
import moduleBase
19 from ifupdownaddons
.bondutil
import bondutil
20 from ifupdownaddons
.iproute2
import iproute2
21 from ifupdownaddons
.dhclient
import dhclient
22 from ifupdownaddons
.utilsbase
import *
27 class vrf(moduleBase
):
28 """ ifupdown2 addon module to configure vrfs """
29 _modinfo
= { 'mhelp' : 'vrf configuration module',
32 {'help' : 'vrf device routing table id. key to ' +
33 'creating a vrf device. ' +
34 'Table id is either \'auto\' or '+
35 '\'valid routing table id\'',
36 'example': ['vrf-table auto', 'vrf-table 1001']},
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 system_reserved_rt_tables
= {'255' : 'local', '254' : 'main',
49 '253' : 'default', '0' : 'unspec'}
51 def __init__(self
, *args
, **kargs
):
52 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
55 self
.dhclientcmd
= None
56 self
.name
= self
.__class
__.__name
__
57 if ifupdownflags
.flags
.PERFMODE
:
58 # if perf mode is set, remove vrf map file.
59 # start afresh. PERFMODE is set at boot
60 if os
.path
.exists(self
.iproute2_vrf_filename
):
62 self
.logger
.info('vrf: removing file %s'
63 %self
.iproute2_vrf_filename
)
64 os
.remove(self
.iproute2_vrf_filename
)
66 self
.logger
.debug('vrf: removing file failed (%s)'
69 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
70 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
72 self
.ip_rule_cache
= []
73 self
.logger
.warn('vrf: cache v4: %s' % str(e
))
76 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
77 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
79 self
.ip6_rule_cache
= []
80 self
.logger
.warn('vrf: cache v6: %s' % str(e
))
82 #self.logger.debug("vrf: ip rule cache")
83 #self.logger.info(self.ip_rule_cache)
85 #self.logger.info("vrf: ip -6 rule cache")
86 #self.logger.info(self.ip6_rule_cache)
88 self
._iproute
2_vrf
_map
_initialized
= False
89 self
.iproute2_vrf_map
= {}
90 self
.iproute2_vrf_map_fd
= None
91 self
.iproute2_vrf_map_sync_to_disk
= False
93 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
94 if not self
.vrf_table_id_start
:
95 self
.vrf_table_id_start
= self
.VRF_TABLE_START
96 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
97 if not self
.vrf_table_id_end
:
98 self
.vrf_table_id_end
= self
.VRF_TABLE_END
99 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
101 self
.vrf_fix_local_table
= True
103 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
104 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
106 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
107 if self
._iproute
2_vrf
_map
_initialized
:
110 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
111 self
.iproute2_vrf_map
= {}
112 iproute2_vrf_map_force_rewrite
= False
113 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
114 if os
.path
.exists(self
.iproute2_vrf_filename
):
115 with
open(self
.iproute2_vrf_filename
, 'r+') as vrf_map_fd
:
116 lines
= vrf_map_fd
.readlines()
122 (table
, vrf_name
) = l
.strip().split()
123 if self
.iproute2_vrf_map
.get(int(table
)):
124 # looks like the existing file has
125 # duplicate entries, force rewrite of the
127 iproute2_vrf_map_force_rewrite
= True
129 self
.iproute2_vrf_map
[int(table
)] = vrf_name
131 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
135 vrfs
= self
.ipcmd
.link_get_vrfs()
138 for v
, lattrs
in vrfs
.iteritems():
139 table
= lattrs
.get('table', None)
141 running_vrf_map
[int(table
)] = v
143 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
144 self
.iproute2_vrf_map
= running_vrf_map
145 iproute2_vrf_map_force_rewrite
= True
147 self
.iproute2_vrf_map_fd
= None
149 if iproute2_vrf_map_force_rewrite
:
150 # reopen the file and rewrite the map
151 self
._iproute
2_vrf
_map
_open
(True, False)
153 self
._iproute
2_vrf
_map
_open
(False, True)
155 self
.iproute2_vrf_map_sync_to_disk
= False
156 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
158 self
.logger
.info("vrf: dumping iproute2_vrf_map")
159 self
.logger
.info(self
.iproute2_vrf_map
)
161 last_used_vrf_table
= None
162 for t
in range(self
.vrf_table_id_start
,
163 self
.vrf_table_id_end
):
164 if not self
.iproute2_vrf_map
.get(t
):
166 last_used_vrf_table
= t
167 self
.last_used_vrf_table
= last_used_vrf_table
168 self
._iproute
2_vrf
_map
_initialized
= True
169 self
.vrf_count
= len(self
.iproute2_vrf_map
)
171 def _iproute2_vrf_map_sync_to_disk(self
):
172 if (ifupdownflags
.flags
.DRYRUN
or
173 not self
.iproute2_vrf_map_sync_to_disk
):
175 self
.logger
.info('vrf: syncing table map to %s'
176 %self
.iproute2_vrf_filename
)
177 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
178 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
179 self
.vrf_table_id_end
))
180 for t
, v
in self
.iproute2_vrf_map
.iteritems():
181 f
.write('%s %s\n' %(t
, v
))
184 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
185 self
.logger
.info('vrf: syncing table map to %s'
186 %self
.iproute2_vrf_filename
)
187 if ifupdownflags
.flags
.DRYRUN
:
189 fmode
= 'a+' if append
else 'w'
191 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
193 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
195 self
.log_warn('vrf: error opening %s (%s)'
196 %(self
.iproute2_vrf_filename
, str(e
)))
201 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
202 %(self
.vrf_table_id_start
,
203 self
.vrf_table_id_end
))
204 for t
, v
in self
.iproute2_vrf_map
.iteritems():
205 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
206 self
.iproute2_vrf_map_fd
.flush()
208 def _is_vrf(self
, ifaceobj
):
209 if ifaceobj
.get_attr_value_first('vrf-table'):
213 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
214 """ Returns list of interfaces dependent on ifaceobj """
216 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
218 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
219 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
220 ifaceobj
.role |
= ifaceRole
.MASTER
221 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
222 if not vrf_iface_name
:
224 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
225 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
227 return [vrf_iface_name
]
229 def get_upper_ifacenames_running(self
, ifaceobj
):
232 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
233 for t
, v
in self
.iproute2_vrf_map
.iteritems():
234 if v
== vrf_dev_name
:
238 def _get_avail_vrf_table_id(self
):
239 if self
.last_used_vrf_table
== None:
240 table_id_start
= self
.vrf_table_id_start
242 table_id_start
= self
.last_used_vrf_table
+ 1
243 for t
in range(table_id_start
,
244 self
.vrf_table_id_end
):
245 if not self
.iproute2_vrf_map
.get(t
):
246 self
.last_used_vrf_table
= t
250 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
251 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
252 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
253 self
.log_error('table id %s already assigned to vrf dev %s'
254 %(table_id
, old_vrf_name
), vrfifaceobj
)
256 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
257 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
259 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
260 if self
.iproute2_vrf_map_fd
:
261 self
.iproute2_vrf_map_fd
.write('%s %s\n'
262 %(table_id
, vrfifaceobj
.name
))
263 self
.iproute2_vrf_map_fd
.flush()
267 if old_vrf_name
!= vrfifaceobj
.name
:
268 self
.log_error('table id %d already assigned to vrf dev %s'
269 %(table_id
, old_vrf_name
))
271 def _iproute2_vrf_table_entry_del(self
, table_id
):
273 # with any del of vrf map, we need to force sync to disk
274 self
.iproute2_vrf_map_sync_to_disk
= True
275 del self
.iproute2_vrf_map
[int(table_id
)]
277 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
281 def _is_vrf_dev(self
, ifacename
):
282 # Look at iproute2 map for now.
283 # If it was a master we knew about,
284 # it is definately there
285 if ifacename
in self
.iproute2_vrf_map
.values():
289 def _is_dhcp_slave(self
, ifaceobj
):
290 if (not ifaceobj
.addr_method
or
291 (ifaceobj
.addr_method
!= 'dhcp' and
292 ifaceobj
.addr_method
!= 'dhcp6')):
296 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
298 """ If we have a vrf slave that has dhcp configured, bring up the
299 vrf master now. This is needed because vrf has special handling
300 in dhclient hook which requires the vrf master to be present """
302 vrf_master
= ifaceobj
.upperifaces
[0]
304 self
.logger
.warn('%s: vrf master not found' %ifacename
)
306 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
307 self
.logger
.info('%s: vrf master %s exists returning'
308 %(ifacename
, vrf_master
))
310 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
311 if not vrf_master_objs
:
312 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
314 self
.logger
.info('%s: bringing up vrf master %s'
315 %(ifacename
, vrf_master
))
316 for mobj
in vrf_master_objs
:
317 vrf_table
= mobj
.get_attr_value_first('vrf-table')
319 if vrf_table
== 'auto':
320 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
322 self
.log_error('%s: unable to get an auto table id'
323 %mobj
.name
, ifaceobj
)
324 self
.logger
.info('%s: table id auto: selected table id %s\n'
325 %(mobj
.name
, vrf_table
))
327 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
331 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
332 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
335 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
337 dhclient_cmd_prefix
= None
338 if (vrfname
and self
.vrf_exec_cmd_prefix
and
339 self
.ipcmd
.link_exists(vrfname
)):
340 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
342 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
344 # ignore any dhclient release errors
347 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
348 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
350 if (self
.vrf_mgmt_devname
and
351 self
.vrf_mgmt_devname
== vrfname
):
352 self
._kill
_ssh
_connections
(ifaceobj
.name
)
353 if self
._is
_dhcp
_slave
(ifaceobj
):
354 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
356 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
357 ifaceobj_getfunc
=None, vrf_exists
=False):
360 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
361 upper
= self
.ipcmd
.link_get_upper(ifacename
)
362 if not upper
or upper
!= vrfname
:
363 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
364 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
365 elif ifupdownflags
.flags
.ALL
and ifaceobj
:
366 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
369 master_exists
= False
371 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
372 elif ifupdownflags
.flags
.ALL
:
373 self
.log_error('vrf %s not around, skipping vrf config'
374 %(vrfname), ifaceobj
)
376 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
378 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
380 ip_rule_out_format
= '%s: from all %s %s lookup %s'
381 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
383 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
384 if rule
in self
.ip_rule_cache
:
385 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
387 utils
.exec_command(rule_cmd
)
389 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
390 if rule
in self
.ip_rule_cache
:
391 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
393 utils
.exec_command(rule_cmd
)
395 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
396 if rule
in self
.ip6_rule_cache
:
397 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
399 utils
.exec_command(rule_cmd
)
401 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
402 if rule
in self
.ip6_rule_cache
:
403 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
405 utils
.exec_command(rule_cmd
)
407 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
409 ip_rule_out_format
= '%s: from all %s %s lookup %s'
410 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
411 if self
.vrf_fix_local_table
:
412 self
.vrf_fix_local_table
= False
413 rule
= '0: from all lookup local'
414 if rule
in self
.ip_rule_cache
:
416 utils
.exec_command('ip rule del pref 0')
417 utils
.exec_command('ip rule add pref 32765 table local')
419 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
421 if rule
in self
.ip6_rule_cache
:
423 utils
.exec_command('ip -6 rule del pref 0')
424 utils
.exec_command('ip -6 rule add pref 32765 table local')
426 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
430 #200: from all oif blue lookup blue
431 #200: from all iif blue lookup blue
433 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
434 if rule
not in self
.ip_rule_cache
:
435 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
437 utils
.exec_command(rule_cmd
)
439 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
440 if rule
not in self
.ip_rule_cache
:
441 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
443 utils
.exec_command(rule_cmd
)
445 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
446 if rule
not in self
.ip6_rule_cache
:
447 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
449 utils
.exec_command(rule_cmd
)
451 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
452 if rule
not in self
.ip6_rule_cache
:
453 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
455 utils
.exec_command(rule_cmd
)
457 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
458 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
459 config_slaves
= ifaceobj
.lowerifaces
460 if not config_slaves
and not running_slaves
:
463 if not config_slaves
: config_slaves
= []
464 if not running_slaves
: running_slaves
= []
465 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
466 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
470 if not self
.ipcmd
.link_exists(s
):
474 sobj
= ifaceobj_getfunc(s
)
475 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
476 sobj
[0] if sobj
else None,
477 ifaceobj_getfunc
, True)
479 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
486 sobj
= ifaceobj_getfunc(s
)
487 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
490 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
492 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
493 for s
in config_slaves
:
495 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
497 self
.logger
.debug('%s: %s: link set up (%s)'
498 %(ifaceobj
.name
, s
, str(e
)))
501 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
502 ifaceobj
.module_flags
[self
.name
] = \
503 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
504 vrfPrivFlags
.PROCESSED
506 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
507 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
511 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
512 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
513 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
514 self
.log_error('cannot use system reserved %s vrf names'
515 %(str(self
.system_reserved_rt_tables
.values())),
517 if self
.vrf_count
== self
.vrf_max_count
:
518 self
.log_error('%s: max vrf count %d hit...not '
519 'creating vrf' %(ifaceobj
.name
,
520 self
.vrf_count
), ifaceobj
)
521 if vrf_table
== 'auto':
522 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
524 self
.log_error('%s: unable to get an auto table id'
525 %ifaceobj
.name
, ifaceobj
)
526 self
.logger
.info('%s: table id auto: selected table id %s\n'
527 %(ifaceobj
.name
, vrf_table
))
529 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
530 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
531 self
.log_error('cannot use system reserved %s table ids'
532 %(str(self
.system_reserved_rt_tables
.keys())),
535 if not vrf_table
.isdigit():
536 self
.log_error('%s: vrf-table must be an integer or \'auto\''
537 %(ifaceobj
.name
), ifaceobj
)
539 # XXX: If we decide to not allow vrf id usages out of
540 # the reserved ifupdown range, then uncomment this code.
542 if (int(vrf_table
) < self
.vrf_table_id_start
or
543 int(vrf_table
) > self
.vrf_table_id_end
):
544 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
545 %(ifaceobj
.name
, vrf_table
,
546 self
.vrf_table_id_start
,
547 self
.vrf_table_id_end
), ifaceobj
)
549 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
550 {'table' : '%s' %vrf_table
})
552 self
.log_error('%s: create failed (%s)\n'
553 %(ifaceobj
.name
, str(e
)), ifaceobj
)
554 if vrf_table
!= 'auto':
555 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
557 if vrf_table
== 'auto':
558 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
560 self
.log_error('%s: unable to get vrf table id'
561 %ifaceobj
.name
, ifaceobj
)
563 # if the device exists, check if table id is same
564 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
566 running_table
= vrfdev_attrs
.get('table', None)
567 if vrf_table
!= running_table
:
568 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
569 running_table
, vrf_table
),
573 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
575 if ifupdownflags
.flags
.PERFMODE
:
578 utils
.exec_command('%s create %s %s %s' %
584 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
585 ifaceobj_getfunc
=None):
587 # if vrf dev is already processed return. This can happen
588 # if we the slave was configured before.
589 # see self._up_vrf_slave_without_master
590 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
594 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
596 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
599 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
600 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
602 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
603 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
604 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
606 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
608 def _kill_ssh_connections(self
, ifacename
):
610 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
611 if not runningaddrsdict
:
613 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
618 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
619 #users:(("sshd",pid=2528,fd=3))
620 cmdl
= ['/bin/ss', '-t', '-p']
621 for line
in utils
.exec_commandl(cmdl
).splitlines():
622 citems
= line
.split()
625 addr
= citems
[3].split('%')[0]
626 elif ':ssh' in citems
[3]:
627 addr
= citems
[3].split(':')[0]
632 proc
.append(citems
[5].split(',')[1].split('=')[1])
637 # outpt of '/usr/bin/pstree -Aps <pid>':
638 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
639 # get the above output to following format
640 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
641 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
642 for index
, process
in enumerate(pstree
):
643 # check the parent of SSH process to make sure
644 # we don't kill SSH server or systemd process
645 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
646 pid
= filter(lambda x
: x
.isdigit(), process
)
648 self
.logger
.info("%s: killing active ssh sessions: %s"
649 %(ifacename
, str(proc
)))
651 if ifupdownflags
.flags
.DRYRUN
:
656 os
.kill(int(id), signal
.SIGINT
)
660 # Kill current SSH client
665 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
666 if (forkret
== 0): # The first child.
669 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
670 except OSError, (err_no
, err_message
):
671 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
672 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
674 self
.logger
.info("%s: killing our session: %s"
675 %(ifacename
, str(proc
)))
676 os
.kill(int(pid
), signal
.SIGINT
)
681 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
683 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
685 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
687 self
._iproute
2_vrf
_map
_initialize
()
688 # This is a vrf device
689 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
691 vrf
= ifaceobj
.get_attr_value_first('vrf')
693 self
._iproute
2_vrf
_map
_initialize
()
694 # This is a vrf slave
695 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
698 # check if we were a slave before
699 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
701 self
._iproute
2_vrf
_map
_initialize
()
702 if self
._is
_vrf
_dev
(master
):
703 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
706 self
.log_error(str(e
), ifaceobj
)
708 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
710 if ifupdownflags
.flags
.PERFMODE
:
713 utils
.exec_command('%s delete %s %s %s' %
719 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
721 if vrf_table
== 'auto':
722 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
724 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
726 for s
in running_slaves
:
728 sobj
= ifaceobj_getfunc(s
)
730 self
._handle
_existing
_connections
(sobj
[0]
734 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
737 self
.ipcmd
.addr_flush(s
)
738 rtnetlink_api
.rtnl_api
.link_set(s
, "down")
740 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
744 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
746 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
750 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
752 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
756 self
.ipcmd
.link_delete(ifaceobj
.name
)
758 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
762 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
764 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
768 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
770 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
771 self
.ipcmd
.link_set(ifacename
, 'nomaster')
772 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
774 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
776 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
778 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
780 self
._iproute
2_vrf
_map
_initialize
()
781 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
783 vrf
= ifaceobj
.get_attr_value_first('vrf')
785 self
._iproute
2_vrf
_map
_initialize
()
786 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
788 self
.log_warn(str(e
))
790 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
792 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
793 if not master
or master
!= vrf
:
794 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
796 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
798 self
.log_error(str(e
), ifaceobjcurr
)
800 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
802 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
803 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
805 if vrf_table
== 'auto':
806 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
808 config_table
= vrf_table
809 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
811 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
813 running_table
= vrfdev_attrs
.get('table')
814 if not running_table
:
815 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
817 if config_table
!= running_table
:
818 ifaceobjcurr
.update_config_with_status('vrf-table',
821 ifaceobjcurr
.update_config_with_status('vrf-table',
823 if not ifupdownflags
.flags
.WITHDEFAULTS
:
827 utils
.exec_command('%s verify %s %s'
829 ifaceobj
.name
, config_table
))
830 ifaceobjcurr
.update_config_with_status('vrf-helper',
836 ifaceobjcurr
.update_config_with_status('vrf-helper',
843 self
.log_warn(str(e
))
845 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
847 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
849 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
850 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
852 vrf
= ifaceobj
.get_attr_value_first('vrf')
854 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
855 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
857 self
.log_warn(str(e
))
859 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
861 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
863 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
865 running_table
= vrfdev_attrs
.get('table')
867 ifaceobjrunning
.update_config('vrf-table',
869 elif kind
== 'vrf_slave':
870 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
872 ifaceobjrunning
.update_config('vrf', vrf
)
874 self
.log_warn(str(e
))
876 def _query(self
, ifaceobj
, **kwargs
):
877 if not self
.vrf_helper
:
879 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
880 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
883 _run_ops
= {'pre-up' : _up
,
885 'query-running' : _query_running
,
886 'query-checkcurr' : _query_check
,
890 """ returns list of ops supported by this module """
891 return self
._run
_ops
.keys()
893 def _init_command_handlers(self
):
895 self
.ipcmd
= iproute2()
897 self
.bondcmd
= bondutil()
898 if not self
.dhclientcmd
:
899 self
.dhclientcmd
= dhclient()
901 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
902 ifaceobj_getfunc
=None, **extra_args
):
903 """ run bond configuration on the interface object passed as argument
906 **ifaceobj** (object): iface object
908 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
912 **query_ifaceobj** (object): query check ifaceobject. This is only
913 valid when op is 'query-checkcurr'. It is an object same as
914 ifaceobj, but contains running attribute values and its config
915 status. The modules can use it to return queried running state
916 of interfaces. status is success if the running state is same
917 as user required state in ifaceobj. error otherwise.
919 op_handler
= self
._run
_ops
.get(operation
)
922 self
._init
_command
_handlers
()
923 if operation
== 'query-checkcurr':
924 op_handler(self
, ifaceobj
, query_ifaceobj
)
926 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)