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
26 class vrf(moduleBase
):
27 """ ifupdown2 addon module to configure vrfs """
28 _modinfo
= { 'mhelp' : 'vrf configuration module',
31 {'help' : 'vrf device routing table id. key to ' +
32 'creating a vrf device. ' +
33 'Table id is either \'auto\' or '+
34 '\'valid routing table id\'',
35 'example': ['vrf-table auto', 'vrf-table 1001']},
37 {'help' : 'vrf the interface is part of.',
38 'example': ['vrf blue']}}}
40 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
41 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
42 '# It contains the vrf name to table mapping.\n' + \
43 '# Reserved table range %s %s\n'
44 VRF_TABLE_START
= 1001
47 system_reserved_rt_tables
= {'255' : 'local', '254' : 'main',
48 '253' : 'default', '0' : 'unspec'}
50 def __init__(self
, *args
, **kargs
):
51 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
54 self
.dhclientcmd
= None
55 self
.name
= self
.__class
__.__name
__
56 if ifupdownflags
.flags
.PERFMODE
:
57 # if perf mode is set, remove vrf map file.
58 # start afresh. PERFMODE is set at boot
59 if os
.path
.exists(self
.iproute2_vrf_filename
):
61 self
.logger
.info('vrf: removing file %s'
62 %self
.iproute2_vrf_filename
)
63 os
.remove(self
.iproute2_vrf_filename
)
65 self
.logger
.debug('vrf: removing file failed (%s)'
68 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
69 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
71 self
.ip_rule_cache
= []
72 self
.logger
.warn('vrf: cache v4: %s' % str(e
))
75 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
76 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
78 self
.ip6_rule_cache
= []
79 self
.logger
.warn('vrf: cache v6: %s' % str(e
))
81 #self.logger.debug("vrf: ip rule cache")
82 #self.logger.info(self.ip_rule_cache)
84 #self.logger.info("vrf: ip -6 rule cache")
85 #self.logger.info(self.ip6_rule_cache)
87 self
._iproute
2_vrf
_map
_initialized
= False
88 self
.iproute2_vrf_map
= {}
89 self
.iproute2_vrf_map_fd
= None
90 self
.iproute2_vrf_map_sync_to_disk
= False
92 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
93 if not self
.vrf_table_id_start
:
94 self
.vrf_table_id_start
= self
.VRF_TABLE_START
95 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
96 if not self
.vrf_table_id_end
:
97 self
.vrf_table_id_end
= self
.VRF_TABLE_END
98 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
100 self
.vrf_fix_local_table
= True
102 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
103 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
105 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
106 if self
._iproute
2_vrf
_map
_initialized
:
109 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
110 self
.iproute2_vrf_map
= {}
111 iproute2_vrf_map_force_rewrite
= False
112 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
113 if os
.path
.exists(self
.iproute2_vrf_filename
):
114 with
open(self
.iproute2_vrf_filename
, 'r+') as vrf_map_fd
:
115 lines
= vrf_map_fd
.readlines()
121 (table
, vrf_name
) = l
.strip().split()
122 if self
.iproute2_vrf_map
.get(int(table
)):
123 # looks like the existing file has
124 # duplicate entries, force rewrite of the
126 iproute2_vrf_map_force_rewrite
= True
128 self
.iproute2_vrf_map
[int(table
)] = vrf_name
130 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
134 vrfs
= self
.ipcmd
.link_get_vrfs()
137 for v
, lattrs
in vrfs
.iteritems():
138 table
= lattrs
.get('table', None)
140 running_vrf_map
[int(table
)] = v
142 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
143 self
.iproute2_vrf_map
= running_vrf_map
144 iproute2_vrf_map_force_rewrite
= True
146 self
.iproute2_vrf_map_fd
= None
148 if iproute2_vrf_map_force_rewrite
:
149 # reopen the file and rewrite the map
150 self
._iproute
2_vrf
_map
_open
(True, False)
152 self
._iproute
2_vrf
_map
_open
(False, True)
154 self
.iproute2_vrf_map_sync_to_disk
= False
155 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
157 self
.logger
.info("vrf: dumping iproute2_vrf_map")
158 self
.logger
.info(self
.iproute2_vrf_map
)
160 last_used_vrf_table
= None
161 for t
in range(self
.vrf_table_id_start
,
162 self
.vrf_table_id_end
):
163 if not self
.iproute2_vrf_map
.get(t
):
165 last_used_vrf_table
= t
166 self
.last_used_vrf_table
= last_used_vrf_table
167 self
._iproute
2_vrf
_map
_initialized
= True
168 self
.vrf_count
= len(self
.iproute2_vrf_map
)
170 def _iproute2_vrf_map_sync_to_disk(self
):
171 if (ifupdownflags
.flags
.DRYRUN
or
172 not self
.iproute2_vrf_map_sync_to_disk
):
174 self
.logger
.info('vrf: syncing table map to %s'
175 %self
.iproute2_vrf_filename
)
176 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
177 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
178 self
.vrf_table_id_end
))
179 for t
, v
in self
.iproute2_vrf_map
.iteritems():
180 f
.write('%s %s\n' %(t
, v
))
183 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
184 self
.logger
.info('vrf: syncing table map to %s'
185 %self
.iproute2_vrf_filename
)
186 if ifupdownflags
.flags
.DRYRUN
:
188 fmode
= 'a+' if append
else 'w'
190 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
192 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
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
, vrfifaceobj
, table_id
):
250 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
251 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
252 self
.log_error('table id %s already assigned to vrf dev %s'
253 %(table_id
, old_vrf_name
), vrfifaceobj
)
255 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
256 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
258 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
259 if self
.iproute2_vrf_map_fd
:
260 self
.iproute2_vrf_map_fd
.write('%s %s\n'
261 %(table_id
, vrfifaceobj
.name
))
262 self
.iproute2_vrf_map_fd
.flush()
266 if old_vrf_name
!= vrfifaceobj
.name
:
267 self
.log_error('table id %d already assigned to vrf dev %s'
268 %(table_id
, old_vrf_name
))
270 def _iproute2_vrf_table_entry_del(self
, table_id
):
272 # with any del of vrf map, we need to force sync to disk
273 self
.iproute2_vrf_map_sync_to_disk
= True
274 del self
.iproute2_vrf_map
[int(table_id
)]
276 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
280 def _is_vrf_dev(self
, ifacename
):
281 # Look at iproute2 map for now.
282 # If it was a master we knew about,
283 # it is definately there
284 if ifacename
in self
.iproute2_vrf_map
.values():
288 def _is_dhcp_slave(self
, ifaceobj
):
289 if (not ifaceobj
.addr_method
or
290 (ifaceobj
.addr_method
!= 'dhcp' and
291 ifaceobj
.addr_method
!= 'dhcp6')):
295 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
297 """ If we have a vrf slave that has dhcp configured, bring up the
298 vrf master now. This is needed because vrf has special handling
299 in dhclient hook which requires the vrf master to be present """
301 vrf_master
= ifaceobj
.upperifaces
[0]
303 self
.logger
.warn('%s: vrf master not found' %ifacename
)
305 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
306 self
.logger
.info('%s: vrf master %s exists returning'
307 %(ifacename
, vrf_master
))
309 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
310 if not vrf_master_objs
:
311 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
313 self
.logger
.info('%s: bringing up vrf master %s'
314 %(ifacename
, vrf_master
))
315 for mobj
in vrf_master_objs
:
316 vrf_table
= mobj
.get_attr_value_first('vrf-table')
318 if vrf_table
== 'auto':
319 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
321 self
.log_error('%s: unable to get an auto table id'
322 %mobj
.name
, ifaceobj
)
323 self
.logger
.info('%s: table id auto: selected table id %s\n'
324 %(mobj
.name
, vrf_table
))
326 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
330 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
331 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
334 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
336 dhclient_cmd_prefix
= None
337 if (vrfname
and self
.vrf_exec_cmd_prefix
and
338 self
.ipcmd
.link_exists(vrfname
)):
339 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
341 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
343 # ignore any dhclient release errors
346 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
347 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
349 if (self
.vrf_mgmt_devname
and
350 self
.vrf_mgmt_devname
== vrfname
):
351 self
._kill
_ssh
_connections
(ifaceobj
.name
)
352 if self
._is
_dhcp
_slave
(ifaceobj
):
353 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
355 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
356 ifaceobj_getfunc
=None, vrf_exists
=False):
359 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
360 upper
= self
.ipcmd
.link_get_upper(ifacename
)
361 if not upper
or upper
!= vrfname
:
362 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
363 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
364 elif ifupdownflags
.flags
.ALL
and ifaceobj
:
365 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
368 master_exists
= False
370 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
371 elif ifupdownflags
.flags
.ALL
:
372 self
.log_error('vrf %s not around, skipping vrf config'
373 %(vrfname), ifaceobj
)
375 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
377 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
379 ip_rule_out_format
= '%s: from all %s %s lookup %s'
380 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
382 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
383 if rule
in self
.ip_rule_cache
:
384 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
386 utils
.exec_command(rule_cmd
)
388 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
389 if rule
in self
.ip_rule_cache
:
390 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
392 utils
.exec_command(rule_cmd
)
394 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
395 if rule
in self
.ip6_rule_cache
:
396 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
398 utils
.exec_command(rule_cmd
)
400 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
401 if rule
in self
.ip6_rule_cache
:
402 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
404 utils
.exec_command(rule_cmd
)
406 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
408 ip_rule_out_format
= '%s: from all %s %s lookup %s'
409 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
410 if self
.vrf_fix_local_table
:
411 self
.vrf_fix_local_table
= False
412 rule
= '0: from all lookup local'
413 if rule
in self
.ip_rule_cache
:
415 utils
.exec_command('ip rule del pref 0')
416 utils
.exec_command('ip rule add pref 32765 table local')
418 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
420 if rule
in self
.ip6_rule_cache
:
422 utils
.exec_command('ip -6 rule del pref 0')
423 utils
.exec_command('ip -6 rule add pref 32765 table local')
425 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
429 #200: from all oif blue lookup blue
430 #200: from all iif blue lookup blue
432 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
433 if rule
not in self
.ip_rule_cache
:
434 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
436 utils
.exec_command(rule_cmd
)
438 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
439 if rule
not in self
.ip_rule_cache
:
440 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
442 utils
.exec_command(rule_cmd
)
444 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
445 if rule
not in self
.ip6_rule_cache
:
446 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
448 utils
.exec_command(rule_cmd
)
450 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
451 if rule
not in self
.ip6_rule_cache
:
452 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
454 utils
.exec_command(rule_cmd
)
456 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
457 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
458 config_slaves
= ifaceobj
.lowerifaces
459 if not config_slaves
and not running_slaves
:
462 if not config_slaves
: config_slaves
= []
463 if not running_slaves
: running_slaves
= []
464 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
465 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
469 if not self
.ipcmd
.link_exists(s
):
473 sobj
= ifaceobj_getfunc(s
)
474 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
475 sobj
[0] if sobj
else None,
476 ifaceobj_getfunc
, True)
478 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
485 sobj
= ifaceobj_getfunc(s
)
486 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
489 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
491 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
492 for s
in config_slaves
:
494 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
496 self
.logger
.debug('%s: %s: link set up (%s)'
497 %(ifaceobj
.name
, s
, str(e
)))
500 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
501 ifaceobj
.module_flags
[self
.name
] = \
502 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
503 vrfPrivFlags
.PROCESSED
505 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
506 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
510 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
511 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
512 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
513 self
.log_error('cannot use system reserved %s vrf names'
514 %(str(self
.system_reserved_rt_tables
.values())),
516 if self
.vrf_count
== self
.vrf_max_count
:
517 self
.log_error('%s: max vrf count %d hit...not '
518 'creating vrf' %(ifaceobj
.name
,
519 self
.vrf_count
), ifaceobj
)
520 if vrf_table
== 'auto':
521 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
523 self
.log_error('%s: unable to get an auto table id'
524 %ifaceobj
.name
, ifaceobj
)
525 self
.logger
.info('%s: table id auto: selected table id %s\n'
526 %(ifaceobj
.name
, vrf_table
))
528 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
529 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
530 self
.log_error('cannot use system reserved %s table ids'
531 %(str(self
.system_reserved_rt_tables
.keys())),
534 if not vrf_table
.isdigit():
535 self
.log_error('%s: vrf-table must be an integer or \'auto\''
536 %(ifaceobj
.name
), ifaceobj
)
538 # XXX: If we decide to not allow vrf id usages out of
539 # the reserved ifupdown range, then uncomment this code.
541 if (int(vrf_table
) < self
.vrf_table_id_start
or
542 int(vrf_table
) > self
.vrf_table_id_end
):
543 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
544 %(ifaceobj
.name
, vrf_table
,
545 self
.vrf_table_id_start
,
546 self
.vrf_table_id_end
), ifaceobj
)
548 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
549 {'table' : '%s' %vrf_table
})
551 self
.log_error('%s: create failed (%s)\n'
552 %(ifaceobj
.name
, str(e
)), ifaceobj
)
553 if vrf_table
!= 'auto':
554 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
556 if vrf_table
== 'auto':
557 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
559 self
.log_error('%s: unable to get vrf table id'
560 %ifaceobj
.name
, ifaceobj
)
562 # if the device exists, check if table id is same
563 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
565 running_table
= vrfdev_attrs
.get('table', None)
566 if vrf_table
!= running_table
:
567 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
568 running_table
, vrf_table
),
572 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
574 if ifupdownflags
.flags
.PERFMODE
:
577 utils
.exec_command('%s create %s %s %s' %
583 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
584 ifaceobj_getfunc
=None):
586 # if vrf dev is already processed return. This can happen
587 # if we the slave was configured before.
588 # see self._up_vrf_slave_without_master
589 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
593 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
595 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
598 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
599 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
601 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
602 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
603 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
605 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
607 def _kill_ssh_connections(self
, ifacename
):
609 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
610 if not runningaddrsdict
:
612 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
617 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
618 #users:(("sshd",pid=2528,fd=3))
619 cmdl
= ['/bin/ss', '-t', '-p']
620 for line
in utils
.exec_commandl(cmdl
).splitlines():
621 citems
= line
.split()
624 addr
= citems
[3].split('%')[0]
625 elif ':ssh' in citems
[3]:
626 addr
= citems
[3].split(':')[0]
631 proc
.append(citems
[5].split(',')[1].split('=')[1])
635 cmdl
= ['/bin/ps', '--no-headers', '-fp', str(os
.getppid())]
636 pid
= utils
.exec_commandl(cmdl
).split()[2]
637 self
.logger
.info("%s: killing active ssh sessions: %s"
638 %(ifacename
, str(proc
)))
640 if ifupdownflags
.flags
.DRYRUN
:
645 os
.kill(int(id), signal
.SIGINT
)
649 # Kill current SSH client
654 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
655 if (forkret
== 0): # The first child.
658 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
659 except OSError, (err_no
, err_message
):
660 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
661 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
663 self
.logger
.info("%s: killing our session: %s"
664 %(ifacename
, str(proc
)))
665 os
.kill(int(pid
), signal
.SIGINT
)
670 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
672 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
674 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
676 self
._iproute
2_vrf
_map
_initialize
()
677 # This is a vrf device
678 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
680 vrf
= ifaceobj
.get_attr_value_first('vrf')
682 self
._iproute
2_vrf
_map
_initialize
()
683 # This is a vrf slave
684 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
687 # check if we were a slave before
688 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
690 self
._iproute
2_vrf
_map
_initialize
()
691 if self
._is
_vrf
_dev
(master
):
692 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
695 self
.log_error(str(e
), ifaceobj
)
697 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
699 if ifupdownflags
.flags
.PERFMODE
:
702 utils
.exec_command('%s delete %s %s %s' %
708 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
710 if vrf_table
== 'auto':
711 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
713 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
715 for s
in running_slaves
:
717 sobj
= ifaceobj_getfunc(s
)
719 self
._handle
_existing
_connections
(sobj
[0]
723 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
726 self
.ipcmd
.addr_flush(s
)
727 rtnetlink_api
.rtnl_api
.link_set(s
, "down")
729 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
733 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
735 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
739 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
741 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
745 self
.ipcmd
.link_delete(ifaceobj
.name
)
747 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
751 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
753 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
757 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
759 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
760 self
.ipcmd
.link_set(ifacename
, 'nomaster')
761 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
763 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
765 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
767 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
769 self
._iproute
2_vrf
_map
_initialize
()
770 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
772 vrf
= ifaceobj
.get_attr_value_first('vrf')
774 self
._iproute
2_vrf
_map
_initialize
()
775 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
777 self
.log_warn(str(e
))
779 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
781 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
782 if not master
or master
!= vrf
:
783 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
785 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
787 self
.log_error(str(e
), ifaceobjcurr
)
789 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
791 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
792 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
794 if vrf_table
== 'auto':
795 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
797 config_table
= vrf_table
798 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
800 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
802 running_table
= vrfdev_attrs
.get('table')
803 if not running_table
:
804 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
806 if config_table
!= running_table
:
807 ifaceobjcurr
.update_config_with_status('vrf-table',
810 ifaceobjcurr
.update_config_with_status('vrf-table',
812 if not ifupdownflags
.flags
.WITHDEFAULTS
:
816 utils
.exec_command('%s verify %s %s'
818 ifaceobj
.name
, config_table
))
819 ifaceobjcurr
.update_config_with_status('vrf-helper',
825 ifaceobjcurr
.update_config_with_status('vrf-helper',
832 self
.log_warn(str(e
))
834 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
836 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
838 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
839 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
841 vrf
= ifaceobj
.get_attr_value_first('vrf')
843 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
844 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
846 self
.log_warn(str(e
))
848 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
850 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
852 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
854 running_table
= vrfdev_attrs
.get('table')
856 ifaceobjrunning
.update_config('vrf-table',
858 elif kind
== 'vrf_slave':
859 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
861 ifaceobjrunning
.update_config('vrf', vrf
)
863 self
.log_warn(str(e
))
865 def _query(self
, ifaceobj
, **kwargs
):
866 if not self
.vrf_helper
:
868 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
869 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
872 _run_ops
= {'pre-up' : _up
,
874 'query-running' : _query_running
,
875 'query-checkcurr' : _query_check
,
879 """ returns list of ops supported by this module """
880 return self
._run
_ops
.keys()
882 def _init_command_handlers(self
):
884 self
.ipcmd
= iproute2()
886 self
.bondcmd
= bondutil()
887 if not self
.dhclientcmd
:
888 self
.dhclientcmd
= dhclient()
890 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
891 ifaceobj_getfunc
=None, **extra_args
):
892 """ run bond configuration on the interface object passed as argument
895 **ifaceobj** (object): iface object
897 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
901 **query_ifaceobj** (object): query check ifaceobject. This is only
902 valid when op is 'query-checkcurr'. It is an object same as
903 ifaceobj, but contains running attribute values and its config
904 status. The modules can use it to return queried running state
905 of interfaces. status is success if the running state is same
906 as user required state in ifaceobj. error otherwise.
908 op_handler
= self
._run
_ops
.get(operation
)
911 self
._init
_command
_handlers
()
912 if operation
== 'query-checkcurr':
913 op_handler(self
, ifaceobj
, query_ifaceobj
)
915 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)