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 routing table id. key to ' +
31 'creating a vrf device. ' +
32 'Table id is either \'auto\' or '+
33 '\'valid routing table id\'',
34 'example': ['vrf-table auto', 'vrf-table 1001']},
36 {'help' : 'vrf the interface is part of.',
37 'example': ['vrf blue']}}}
39 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
40 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
41 '# It contains the vrf name to table mapping.\n' + \
42 '# Reserved table range %s %s\n'
43 VRF_TABLE_START
= 1001
46 system_reserved_rt_tables
= {'255' : 'local', '254' : 'main',
47 '253' : 'default', '0' : 'unspec'}
49 def __init__(self
, *args
, **kargs
):
50 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
53 self
.dhclientcmd
= None
54 self
.name
= self
.__class
__.__name
__
55 if ifupdownflags
.flags
.PERFMODE
:
56 # if perf mode is set, remove vrf map file.
57 # start afresh. PERFMODE is set at boot
58 if os
.path
.exists(self
.iproute2_vrf_filename
):
60 self
.logger
.info('vrf: removing file %s'
61 %self
.iproute2_vrf_filename
)
62 os
.remove(self
.iproute2_vrf_filename
)
64 self
.logger
.debug('vrf: removing file failed (%s)'
67 ip_rules
= self
.exec_command('/sbin/ip rule show').splitlines()
68 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
70 self
.ip_rule_cache
= []
71 self
.logger
.warn('%s' %str
(e
))
74 ip_rules
= self
.exec_command('/sbin/ip -6 rule show').splitlines()
75 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
77 self
.ip6_rule_cache
= []
78 self
.logger
.warn('%s' %str
(e
))
80 #self.logger.debug("vrf: ip rule cache")
81 #self.logger.info(self.ip_rule_cache)
83 #self.logger.info("vrf: ip -6 rule cache")
84 #self.logger.info(self.ip6_rule_cache)
86 self
._iproute
2_vrf
_map
_initialized
= False
87 self
.iproute2_vrf_map
= {}
88 self
.iproute2_vrf_map_fd
= None
89 self
.iproute2_vrf_map_sync_to_disk
= False
91 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
92 if not self
.vrf_table_id_start
:
93 self
.vrf_table_id_start
= self
.VRF_TABLE_START
94 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
95 if not self
.vrf_table_id_end
:
96 self
.vrf_table_id_end
= self
.VRF_TABLE_END
97 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
99 self
.vrf_fix_local_table
= True
101 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
102 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
104 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
105 if self
._iproute
2_vrf
_map
_initialized
:
108 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
109 self
.iproute2_vrf_map
= {}
110 iproute2_vrf_map_force_rewrite
= False
111 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
112 if os
.path
.exists(self
.iproute2_vrf_filename
):
113 vrf_map_fd
= open(self
.iproute2_vrf_filename
, 'r+')
114 lines
= vrf_map_fd
.readlines()
120 (table
, vrf_name
) = l
.strip().split()
121 if self
.iproute2_vrf_map
.get(int(table
)):
122 # looks like the existing file has
123 # duplicate entries, force rewrite of the
125 iproute2_vrf_map_force_rewrite
= True
127 self
.iproute2_vrf_map
[int(table
)] = vrf_name
129 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
133 vrfs
= self
.ipcmd
.link_get_vrfs()
136 for v
, lattrs
in vrfs
.iteritems():
137 table
= lattrs
.get('table', None)
139 running_vrf_map
[int(table
)] = v
141 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
142 self
.iproute2_vrf_map
= running_vrf_map
143 iproute2_vrf_map_force_rewrite
= True
145 self
.iproute2_vrf_map_fd
= None
147 if iproute2_vrf_map_force_rewrite
:
148 # reopen the file and rewrite the map
149 self
._iproute
2_vrf
_map
_open
(True, False)
151 self
._iproute
2_vrf
_map
_open
(False, True)
153 self
.iproute2_vrf_map_sync_to_disk
= False
154 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
156 self
.logger
.info("vrf: dumping iproute2_vrf_map")
157 self
.logger
.info(self
.iproute2_vrf_map
)
159 last_used_vrf_table
= None
160 for t
in range(self
.vrf_table_id_start
,
161 self
.vrf_table_id_end
):
162 if not self
.iproute2_vrf_map
.get(t
):
164 last_used_vrf_table
= t
165 self
.last_used_vrf_table
= last_used_vrf_table
166 self
._iproute
2_vrf
_map
_initialized
= True
167 self
.vrf_count
= len(self
.iproute2_vrf_map
)
169 def _iproute2_vrf_map_sync_to_disk(self
):
170 if (ifupdownflags
.flags
.DRYRUN
or
171 not self
.iproute2_vrf_map_sync_to_disk
):
173 self
.logger
.info('vrf: syncing table map to %s'
174 %self
.iproute2_vrf_filename
)
175 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
176 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
177 self
.vrf_table_id_end
))
178 for t
, v
in self
.iproute2_vrf_map
.iteritems():
179 f
.write('%s %s\n' %(t
, v
))
182 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
183 self
.logger
.info('vrf: syncing table map to %s'
184 %self
.iproute2_vrf_filename
)
185 if ifupdownflags
.flags
.DRYRUN
:
187 fmode
= 'a+' if append
else 'w'
189 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
192 self
.log_warn('vrf: error opening %s (%s)'
193 %(self
.iproute2_vrf_filename
, str(e
)))
198 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
199 %(self
.vrf_table_id_start
,
200 self
.vrf_table_id_end
))
201 for t
, v
in self
.iproute2_vrf_map
.iteritems():
202 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
203 self
.iproute2_vrf_map_fd
.flush()
205 def _is_vrf(self
, ifaceobj
):
206 if ifaceobj
.get_attr_value_first('vrf-table'):
210 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
211 """ Returns list of interfaces dependent on ifaceobj """
213 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
215 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
216 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
217 ifaceobj
.role |
= ifaceRole
.MASTER
218 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
219 if not vrf_iface_name
:
221 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
222 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
224 return [vrf_iface_name
]
226 def get_upper_ifacenames_running(self
, ifaceobj
):
229 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
230 for t
, v
in self
.iproute2_vrf_map
.iteritems():
231 if v
== vrf_dev_name
:
235 def _get_avail_vrf_table_id(self
):
236 if self
.last_used_vrf_table
== None:
237 table_id_start
= self
.vrf_table_id_start
239 table_id_start
= self
.last_used_vrf_table
+ 1
240 for t
in range(table_id_start
,
241 self
.vrf_table_id_end
):
242 if not self
.iproute2_vrf_map
.get(t
):
243 self
.last_used_vrf_table
= t
247 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
248 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
249 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
250 self
.log_error('table id %s already assigned to vrf dev %s'
251 %(table_id
, old_vrf_name
), vrfifaceobj
)
253 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
254 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
256 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
257 if self
.iproute2_vrf_map_fd
:
258 self
.iproute2_vrf_map_fd
.write('%s %s\n'
259 %(table_id
, vrfifaceobj
.name
))
260 self
.iproute2_vrf_map_fd
.flush()
263 if old_vrf_name
!= vrfifaceobj
.name
:
264 self
.log_error('table id %d already assigned to vrf dev %s'
265 %(table_id
, old_vrf_name
))
267 def _iproute2_vrf_table_entry_del(self
, table_id
):
269 # with any del of vrf map, we need to force sync to disk
270 self
.iproute2_vrf_map_sync_to_disk
= True
271 del self
.iproute2_vrf_map
[int(table_id
)]
273 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
277 def _is_vrf_dev(self
, ifacename
):
278 # Look at iproute2 map for now.
279 # If it was a master we knew about,
280 # it is definately there
281 if ifacename
in self
.iproute2_vrf_map
.values():
285 def _is_dhcp_slave(self
, ifaceobj
):
286 if (not ifaceobj
.addr_method
or
287 (ifaceobj
.addr_method
!= 'dhcp' and
288 ifaceobj
.addr_method
!= 'dhcp6')):
292 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
294 """ If we have a vrf slave that has dhcp configured, bring up the
295 vrf master now. This is needed because vrf has special handling
296 in dhclient hook which requires the vrf master to be present """
298 vrf_master
= ifaceobj
.upperifaces
[0]
300 self
.logger
.warn('%s: vrf master not found' %ifacename
)
302 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
303 self
.logger
.info('%s: vrf master %s exists returning'
304 %(ifacename
, vrf_master
))
306 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
307 if not vrf_master_objs
:
308 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
310 self
.logger
.info('%s: bringing up vrf master %s'
311 %(ifacename
, vrf_master
))
312 for mobj
in vrf_master_objs
:
313 vrf_table
= mobj
.get_attr_value_first('vrf-table')
315 if vrf_table
== 'auto':
316 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
318 self
.log_error('%s: unable to get an auto table id'
319 %mobj
.name
, ifaceobj
)
320 self
.logger
.info('%s: table id auto: selected table id %s\n'
321 %(mobj
.name
, vrf_table
))
323 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
327 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
328 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
331 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
333 dhclient_cmd_prefix
= None
334 if (vrfname
and self
.vrf_exec_cmd_prefix
and
335 self
.ipcmd
.link_exists(vrfname
)):
336 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
338 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
340 # ignore any dhclient release errors
343 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
344 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
346 if (self
.vrf_mgmt_devname
and
347 self
.vrf_mgmt_devname
== vrfname
):
348 self
._kill
_ssh
_connections
(ifaceobj
.name
)
349 if self
._is
_dhcp
_slave
(ifaceobj
):
350 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
352 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
353 ifaceobj_getfunc
=None, vrf_exists
=False):
356 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
357 upper
= self
.ipcmd
.link_get_upper(ifacename
)
358 if not upper
or upper
!= vrfname
:
359 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
360 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
361 elif ifupdownflags
.flags
.ALL
and ifaceobj
:
362 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
365 master_exists
= False
367 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
368 elif ifupdownflags
.flags
.ALL
:
369 self
.log_error('vrf %s not around, skipping vrf config'
370 %(vrfname), ifaceobj
)
372 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
374 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
376 ip_rule_out_format
= '%s: from all %s %s lookup %s'
377 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
379 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
380 if rule
in self
.ip_rule_cache
:
381 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
383 self
.exec_command(rule_cmd
)
385 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
386 if rule
in self
.ip_rule_cache
:
387 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
389 self
.exec_command(rule_cmd
)
391 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
392 if rule
in self
.ip6_rule_cache
:
393 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
395 self
.exec_command(rule_cmd
)
397 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
398 if rule
in self
.ip6_rule_cache
:
399 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
401 self
.exec_command(rule_cmd
)
403 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
405 ip_rule_out_format
= '%s: from all %s %s lookup %s'
406 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
407 if self
.vrf_fix_local_table
:
408 self
.vrf_fix_local_table
= False
409 rule
= '0: from all lookup local'
410 if rule
in self
.ip_rule_cache
:
412 self
.exec_command('ip rule del pref 0')
413 self
.exec_command('ip rule add pref 32765 table local')
415 self
.logger
.info('%s' %str
(e
))
417 if rule
in self
.ip6_rule_cache
:
419 self
.exec_command('ip -6 rule del pref 0')
420 self
.exec_command('ip -6 rule add pref 32765 table local')
422 self
.logger
.info('%s' %str
(e
))
426 #200: from all oif blue lookup blue
427 #200: from all iif blue lookup blue
429 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
430 if rule
not in self
.ip_rule_cache
:
431 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
433 self
.exec_command(rule_cmd
)
435 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
436 if rule
not in self
.ip_rule_cache
:
437 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
439 self
.exec_command(rule_cmd
)
441 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
442 if rule
not in self
.ip6_rule_cache
:
443 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
445 self
.exec_command(rule_cmd
)
447 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
448 if rule
not in self
.ip6_rule_cache
:
449 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
451 self
.exec_command(rule_cmd
)
453 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
454 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
455 config_slaves
= ifaceobj
.lowerifaces
456 if not config_slaves
and not running_slaves
:
459 if not config_slaves
: config_slaves
= []
460 if not running_slaves
: running_slaves
= []
461 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
462 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
466 if not self
.ipcmd
.link_exists(s
):
470 sobj
= ifaceobj_getfunc(s
)
471 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
472 sobj
[0] if sobj
else None,
473 ifaceobj_getfunc
, True)
475 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
482 sobj
= ifaceobj_getfunc(s
)
483 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
486 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
488 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
489 for s
in config_slaves
:
491 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
493 self
.logger
.debug('%s: %s: link set up (%s)'
494 %(ifaceobj
.name
, s
, str(e
)))
497 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
498 ifaceobj
.module_flags
[self
.name
] = \
499 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
500 vrfPrivFlags
.PROCESSED
502 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
503 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
507 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
508 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
509 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
510 self
.log_error('cannot use system reserved %s vrf names'
511 %(str(self
.system_reserved_rt_tables
.values())),
513 if self
.vrf_count
== self
.vrf_max_count
:
514 self
.log_error('%s: max vrf count %d hit...not '
515 'creating vrf' %(ifaceobj
.name
,
516 self
.vrf_count
), ifaceobj
)
517 if vrf_table
== 'auto':
518 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
520 self
.log_error('%s: unable to get an auto table id'
521 %ifaceobj
.name
, ifaceobj
)
522 self
.logger
.info('%s: table id auto: selected table id %s\n'
523 %(ifaceobj
.name
, vrf_table
))
525 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
526 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
527 self
.log_error('cannot use system reserved %s table ids'
528 %(str(self
.system_reserved_rt_tables
.keys())),
531 if not vrf_table
.isdigit():
532 self
.log_error('%s: vrf-table must be an integer or \'auto\''
533 %(ifaceobj
.name
), ifaceobj
)
535 # XXX: If we decide to not allow vrf id usages out of
536 # the reserved ifupdown range, then uncomment this code.
538 if (int(vrf_table
) < self
.vrf_table_id_start
or
539 int(vrf_table
) > self
.vrf_table_id_end
):
540 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
541 %(ifaceobj
.name
, vrf_table
,
542 self
.vrf_table_id_start
,
543 self
.vrf_table_id_end
), ifaceobj
)
545 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
546 {'table' : '%s' %vrf_table
})
548 self
.log_error('%s: create failed (%s)\n'
549 %(ifaceobj
.name
, str(e
)), ifaceobj
)
550 if vrf_table
!= 'auto':
551 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
553 if vrf_table
== 'auto':
554 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
556 self
.log_error('%s: unable to get vrf table id'
557 %ifaceobj
.name
, ifaceobj
)
559 # if the device exists, check if table id is same
560 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
562 running_table
= vrfdev_attrs
.get('table', None)
563 if vrf_table
!= running_table
:
564 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
565 running_table
, vrf_table
),
569 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
571 if ifupdownflags
.flags
.PERFMODE
:
574 self
.exec_command('%s create %s %s %s' %(self
.vrf_helper
,
575 ifaceobj
.name
, vrf_table
, mode
))
577 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
578 ifaceobj_getfunc
=None):
580 # if vrf dev is already processed return. This can happen
581 # if we the slave was configured before.
582 # see self._up_vrf_slave_without_master
583 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
587 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
589 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
592 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
593 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
595 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
596 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
597 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
599 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
601 def _kill_ssh_connections(self
, ifacename
):
603 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
604 if not runningaddrsdict
:
606 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
611 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
612 #users:(("sshd",pid=2528,fd=3))
613 cmdl
= ['/bin/ss', '-t', '-p']
614 for line
in subprocess
.check_output(cmdl
, stderr
=subprocess
.STDOUT
,
615 shell
=False).splitlines():
616 citems
= line
.split()
619 addr
= citems
[3].split('%')[0]
620 elif ':ssh' in citems
[3]:
621 addr
= citems
[3].split(':')[0]
626 proc
.append(citems
[5].split(',')[1].split('=')[1])
630 pid
= subprocess
.check_output(['/bin/ps', '--no-headers',
631 '-fp', str(os
.getppid())],
632 stderr
=subprocess
.STDOUT
,
633 shell
=False).split()[2]
634 self
.logger
.info("%s: killing active ssh sessions: %s"
635 %(ifacename
, str(proc
)))
637 if ifupdownflags
.flags
.DRYRUN
:
642 os
.kill(int(id), signal
.SIGINT
)
646 # Kill current SSH client
651 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
652 if (forkret
== 0): # The first child.
655 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
656 except OSError, (err_no
, err_message
):
657 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
658 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
660 self
.logger
.info("%s: killing our session: %s"
661 %(ifacename
, str(proc
)))
662 os
.kill(int(pid
), signal
.SIGINT
)
667 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
669 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
671 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
673 self
._iproute
2_vrf
_map
_initialize
()
674 # This is a vrf device
675 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
677 vrf
= ifaceobj
.get_attr_value_first('vrf')
679 self
._iproute
2_vrf
_map
_initialize
()
680 # This is a vrf slave
681 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
684 # check if we were a slave before
685 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
687 self
._iproute
2_vrf
_map
_initialize
()
688 if self
._is
_vrf
_dev
(master
):
689 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
692 self
.log_error(str(e
), ifaceobj
)
694 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
696 if ifupdownflags
.flags
.PERFMODE
:
699 self
.exec_command('%s delete %s %s %s' %(self
.vrf_helper
,
700 ifaceobj
.name
, vrf_table
, mode
))
702 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
704 if vrf_table
== 'auto':
705 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
707 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
709 for s
in running_slaves
:
711 sobj
= ifaceobj_getfunc(s
)
713 self
._handle
_existing
_connections
(sobj
[0]
717 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
720 self
.ipcmd
.addr_flush(s
)
721 rtnetlink_api
.rtnl_api
.link_set(s
, "down")
723 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
726 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
729 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
731 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
735 self
.ipcmd
.link_delete(ifaceobj
.name
)
737 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
741 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
743 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
747 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
749 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
750 self
.ipcmd
.link_set(ifacename
, 'nomaster')
751 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
753 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
755 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
757 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
759 self
._iproute
2_vrf
_map
_initialize
()
760 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
762 vrf
= ifaceobj
.get_attr_value_first('vrf')
764 self
._iproute
2_vrf
_map
_initialize
()
765 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
767 self
.log_warn(str(e
))
769 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
771 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
772 if not master
or master
!= vrf
:
773 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
775 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
777 self
.log_error(str(e
), ifaceobjcurr
)
779 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
781 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
782 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
784 if vrf_table
== 'auto':
785 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
787 config_table
= vrf_table
788 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
790 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
792 running_table
= vrfdev_attrs
.get('table')
793 if not running_table
:
794 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
796 if config_table
!= running_table
:
797 ifaceobjcurr
.update_config_with_status('vrf-table',
800 ifaceobjcurr
.update_config_with_status('vrf-table',
802 if not ifupdownflags
.flags
.WITHDEFAULTS
:
806 self
.exec_command('%s verify %s %s'
808 ifaceobj
.name
, config_table
))
809 ifaceobjcurr
.update_config_with_status('vrf-helper',
815 ifaceobjcurr
.update_config_with_status('vrf-helper',
822 self
.log_warn(str(e
))
824 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
826 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
828 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
829 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
831 vrf
= ifaceobj
.get_attr_value_first('vrf')
833 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
834 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
836 self
.log_warn(str(e
))
838 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
840 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
842 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
844 running_table
= vrfdev_attrs
.get('table')
846 ifaceobjrunning
.update_config('vrf-table',
848 elif kind
== 'vrf_slave':
849 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
851 ifaceobjrunning
.update_config('vrf', vrf
)
853 self
.log_warn(str(e
))
855 def _query(self
, ifaceobj
, **kwargs
):
856 if not self
.vrf_helper
:
858 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
859 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
862 _run_ops
= {'pre-up' : _up
,
864 'query-running' : _query_running
,
865 'query-checkcurr' : _query_check
,
869 """ returns list of ops supported by this module """
870 return self
._run
_ops
.keys()
872 def _init_command_handlers(self
):
874 self
.ipcmd
= iproute2()
876 self
.bondcmd
= bondutil()
877 if not self
.dhclientcmd
:
878 self
.dhclientcmd
= dhclient()
880 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
881 ifaceobj_getfunc
=None, **extra_args
):
882 """ run bond configuration on the interface object passed as argument
885 **ifaceobj** (object): iface object
887 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
891 **query_ifaceobj** (object): query check ifaceobject. This is only
892 valid when op is 'query-checkcurr'. It is an object same as
893 ifaceobj, but contains running attribute values and its config
894 status. The modules can use it to return queried running state
895 of interfaces. status is success if the running state is same
896 as user required state in ifaceobj. error otherwise.
898 op_handler
= self
._run
_ops
.get(operation
)
901 self
._init
_command
_handlers
()
902 if operation
== 'query-checkcurr':
903 op_handler(self
, ifaceobj
, query_ifaceobj
)
905 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)