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()
264 if old_vrf_name
!= vrfifaceobj
.name
:
265 self
.log_error('table id %d already assigned to vrf dev %s'
266 %(table_id
, old_vrf_name
))
268 def _iproute2_vrf_table_entry_del(self
, table_id
):
270 # with any del of vrf map, we need to force sync to disk
271 self
.iproute2_vrf_map_sync_to_disk
= True
272 del self
.iproute2_vrf_map
[int(table_id
)]
274 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
278 def _is_vrf_dev(self
, ifacename
):
279 # Look at iproute2 map for now.
280 # If it was a master we knew about,
281 # it is definately there
282 if ifacename
in self
.iproute2_vrf_map
.values():
286 def _is_dhcp_slave(self
, ifaceobj
):
287 if (not ifaceobj
.addr_method
or
288 (ifaceobj
.addr_method
!= 'dhcp' and
289 ifaceobj
.addr_method
!= 'dhcp6')):
293 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
295 """ If we have a vrf slave that has dhcp configured, bring up the
296 vrf master now. This is needed because vrf has special handling
297 in dhclient hook which requires the vrf master to be present """
299 vrf_master
= ifaceobj
.upperifaces
[0]
301 self
.logger
.warn('%s: vrf master not found' %ifacename
)
303 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
304 self
.logger
.info('%s: vrf master %s exists returning'
305 %(ifacename
, vrf_master
))
307 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
308 if not vrf_master_objs
:
309 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
311 self
.logger
.info('%s: bringing up vrf master %s'
312 %(ifacename
, vrf_master
))
313 for mobj
in vrf_master_objs
:
314 vrf_table
= mobj
.get_attr_value_first('vrf-table')
316 if vrf_table
== 'auto':
317 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
319 self
.log_error('%s: unable to get an auto table id'
320 %mobj
.name
, ifaceobj
)
321 self
.logger
.info('%s: table id auto: selected table id %s\n'
322 %(mobj
.name
, vrf_table
))
324 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
328 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
329 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
332 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
334 dhclient_cmd_prefix
= None
335 if (vrfname
and self
.vrf_exec_cmd_prefix
and
336 self
.ipcmd
.link_exists(vrfname
)):
337 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
339 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
341 # ignore any dhclient release errors
344 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
345 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
347 if (self
.vrf_mgmt_devname
and
348 self
.vrf_mgmt_devname
== vrfname
):
349 self
._kill
_ssh
_connections
(ifaceobj
.name
)
350 if self
._is
_dhcp
_slave
(ifaceobj
):
351 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
353 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
354 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
)
362 elif ifupdownflags
.flags
.ALL
and ifaceobj
:
363 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
366 master_exists
= False
368 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
369 elif ifupdownflags
.flags
.ALL
:
370 self
.log_error('vrf %s not around, skipping vrf config'
371 %(vrfname), ifaceobj
)
373 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
375 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
377 ip_rule_out_format
= '%s: from all %s %s lookup %s'
378 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
380 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
381 if rule
in self
.ip_rule_cache
:
382 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
384 self
.exec_command(rule_cmd
)
386 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
387 if rule
in self
.ip_rule_cache
:
388 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
390 self
.exec_command(rule_cmd
)
392 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
393 if rule
in self
.ip6_rule_cache
:
394 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
396 self
.exec_command(rule_cmd
)
398 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
399 if rule
in self
.ip6_rule_cache
:
400 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
402 self
.exec_command(rule_cmd
)
404 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
406 ip_rule_out_format
= '%s: from all %s %s lookup %s'
407 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
408 if self
.vrf_fix_local_table
:
409 self
.vrf_fix_local_table
= False
410 rule
= '0: from all lookup local'
411 if rule
in self
.ip_rule_cache
:
413 self
.exec_command('ip rule del pref 0')
414 self
.exec_command('ip rule add pref 32765 table local')
416 self
.logger
.info('%s' %str
(e
))
418 if rule
in self
.ip6_rule_cache
:
420 self
.exec_command('ip -6 rule del pref 0')
421 self
.exec_command('ip -6 rule add pref 32765 table local')
423 self
.logger
.info('%s' %str
(e
))
427 #200: from all oif blue lookup blue
428 #200: from all iif blue lookup blue
430 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
431 if rule
not in self
.ip_rule_cache
:
432 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
434 self
.exec_command(rule_cmd
)
436 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
437 if rule
not in self
.ip_rule_cache
:
438 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
440 self
.exec_command(rule_cmd
)
442 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
443 if rule
not in self
.ip6_rule_cache
:
444 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
446 self
.exec_command(rule_cmd
)
448 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
449 if rule
not in self
.ip6_rule_cache
:
450 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
452 self
.exec_command(rule_cmd
)
454 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
455 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
456 config_slaves
= ifaceobj
.lowerifaces
457 if not config_slaves
and not running_slaves
:
460 if not config_slaves
: config_slaves
= []
461 if not running_slaves
: running_slaves
= []
462 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
463 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
467 if not self
.ipcmd
.link_exists(s
):
471 sobj
= ifaceobj_getfunc(s
)
472 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
473 sobj
[0] if sobj
else None,
474 ifaceobj_getfunc
, True)
476 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
483 sobj
= ifaceobj_getfunc(s
)
484 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
487 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
489 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
490 for s
in config_slaves
:
492 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
494 self
.logger
.debug('%s: %s: link set up (%s)'
495 %(ifaceobj
.name
, s
, str(e
)))
498 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
499 ifaceobj
.module_flags
[self
.name
] = \
500 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
501 vrfPrivFlags
.PROCESSED
503 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
504 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
508 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
509 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
510 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
511 self
.log_error('cannot use system reserved %s vrf names'
512 %(str(self
.system_reserved_rt_tables
.values())),
514 if self
.vrf_count
== self
.vrf_max_count
:
515 self
.log_error('%s: max vrf count %d hit...not '
516 'creating vrf' %(ifaceobj
.name
,
517 self
.vrf_count
), ifaceobj
)
518 if vrf_table
== 'auto':
519 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
521 self
.log_error('%s: unable to get an auto table id'
522 %ifaceobj
.name
, ifaceobj
)
523 self
.logger
.info('%s: table id auto: selected table id %s\n'
524 %(ifaceobj
.name
, vrf_table
))
526 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
527 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
528 self
.log_error('cannot use system reserved %s table ids'
529 %(str(self
.system_reserved_rt_tables
.keys())),
532 if not vrf_table
.isdigit():
533 self
.log_error('%s: vrf-table must be an integer or \'auto\''
534 %(ifaceobj
.name
), ifaceobj
)
536 # XXX: If we decide to not allow vrf id usages out of
537 # the reserved ifupdown range, then uncomment this code.
539 if (int(vrf_table
) < self
.vrf_table_id_start
or
540 int(vrf_table
) > self
.vrf_table_id_end
):
541 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
542 %(ifaceobj
.name
, vrf_table
,
543 self
.vrf_table_id_start
,
544 self
.vrf_table_id_end
), ifaceobj
)
546 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
547 {'table' : '%s' %vrf_table
})
549 self
.log_error('%s: create failed (%s)\n'
550 %(ifaceobj
.name
, str(e
)), ifaceobj
)
551 if vrf_table
!= 'auto':
552 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
554 if vrf_table
== 'auto':
555 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
557 self
.log_error('%s: unable to get vrf table id'
558 %ifaceobj
.name
, ifaceobj
)
560 # if the device exists, check if table id is same
561 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
563 running_table
= vrfdev_attrs
.get('table', None)
564 if vrf_table
!= running_table
:
565 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
566 running_table
, vrf_table
),
570 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
572 if ifupdownflags
.flags
.PERFMODE
:
575 self
.exec_command('%s create %s %s %s' %(self
.vrf_helper
,
576 ifaceobj
.name
, vrf_table
, mode
))
578 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
579 ifaceobj_getfunc
=None):
581 # if vrf dev is already processed return. This can happen
582 # if we the slave was configured before.
583 # see self._up_vrf_slave_without_master
584 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
588 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
590 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
593 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
594 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
596 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
597 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
598 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
600 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
602 def _kill_ssh_connections(self
, ifacename
):
604 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
605 if not runningaddrsdict
:
607 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
612 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
613 #users:(("sshd",pid=2528,fd=3))
614 cmdl
= ['/bin/ss', '-t', '-p']
615 for line
in subprocess
.check_output(cmdl
, stderr
=subprocess
.STDOUT
,
616 shell
=False).splitlines():
617 citems
= line
.split()
620 addr
= citems
[3].split('%')[0]
621 elif ':ssh' in citems
[3]:
622 addr
= citems
[3].split(':')[0]
627 proc
.append(citems
[5].split(',')[1].split('=')[1])
631 pid
= subprocess
.check_output(['/bin/ps', '--no-headers',
632 '-fp', str(os
.getppid())],
633 stderr
=subprocess
.STDOUT
,
634 shell
=False).split()[2]
635 self
.logger
.info("%s: killing active ssh sessions: %s"
636 %(ifacename
, str(proc
)))
638 if ifupdownflags
.flags
.DRYRUN
:
643 os
.kill(int(id), signal
.SIGINT
)
647 # Kill current SSH client
652 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
653 if (forkret
== 0): # The first child.
656 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
657 except OSError, (err_no
, err_message
):
658 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
659 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
661 self
.logger
.info("%s: killing our session: %s"
662 %(ifacename
, str(proc
)))
663 os
.kill(int(pid
), signal
.SIGINT
)
668 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
670 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
672 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
674 self
._iproute
2_vrf
_map
_initialize
()
675 # This is a vrf device
676 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
678 vrf
= ifaceobj
.get_attr_value_first('vrf')
680 self
._iproute
2_vrf
_map
_initialize
()
681 # This is a vrf slave
682 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
685 # check if we were a slave before
686 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
688 self
._iproute
2_vrf
_map
_initialize
()
689 if self
._is
_vrf
_dev
(master
):
690 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
693 self
.log_error(str(e
), ifaceobj
)
695 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
697 if ifupdownflags
.flags
.PERFMODE
:
700 self
.exec_command('%s delete %s %s %s' %(self
.vrf_helper
,
701 ifaceobj
.name
, vrf_table
, mode
))
703 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
705 if vrf_table
== 'auto':
706 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
708 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
710 for s
in running_slaves
:
712 sobj
= ifaceobj_getfunc(s
)
714 self
._handle
_existing
_connections
(sobj
[0]
718 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
721 self
.ipcmd
.addr_flush(s
)
722 rtnetlink_api
.rtnl_api
.link_set(s
, "down")
724 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
727 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
730 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
732 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
736 self
.ipcmd
.link_delete(ifaceobj
.name
)
738 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
742 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
744 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
748 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
750 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
751 self
.ipcmd
.link_set(ifacename
, 'nomaster')
752 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
754 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
756 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
758 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
760 self
._iproute
2_vrf
_map
_initialize
()
761 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
763 vrf
= ifaceobj
.get_attr_value_first('vrf')
765 self
._iproute
2_vrf
_map
_initialize
()
766 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
768 self
.log_warn(str(e
))
770 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
772 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
773 if not master
or master
!= vrf
:
774 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
776 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
778 self
.log_error(str(e
), ifaceobjcurr
)
780 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
782 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
783 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
785 if vrf_table
== 'auto':
786 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
788 config_table
= vrf_table
789 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
791 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
793 running_table
= vrfdev_attrs
.get('table')
794 if not running_table
:
795 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
797 if config_table
!= running_table
:
798 ifaceobjcurr
.update_config_with_status('vrf-table',
801 ifaceobjcurr
.update_config_with_status('vrf-table',
803 if not ifupdownflags
.flags
.WITHDEFAULTS
:
807 self
.exec_command('%s verify %s %s'
809 ifaceobj
.name
, config_table
))
810 ifaceobjcurr
.update_config_with_status('vrf-helper',
816 ifaceobjcurr
.update_config_with_status('vrf-helper',
823 self
.log_warn(str(e
))
825 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
827 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
829 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
830 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
832 vrf
= ifaceobj
.get_attr_value_first('vrf')
834 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
835 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
837 self
.log_warn(str(e
))
839 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
841 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
843 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
845 running_table
= vrfdev_attrs
.get('table')
847 ifaceobjrunning
.update_config('vrf-table',
849 elif kind
== 'vrf_slave':
850 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
852 ifaceobjrunning
.update_config('vrf', vrf
)
854 self
.log_warn(str(e
))
856 def _query(self
, ifaceobj
, **kwargs
):
857 if not self
.vrf_helper
:
859 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
860 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
863 _run_ops
= {'pre-up' : _up
,
865 'query-running' : _query_running
,
866 'query-checkcurr' : _query_check
,
870 """ returns list of ops supported by this module """
871 return self
._run
_ops
.keys()
873 def _init_command_handlers(self
):
875 self
.ipcmd
= iproute2()
877 self
.bondcmd
= bondutil()
878 if not self
.dhclientcmd
:
879 self
.dhclientcmd
= dhclient()
881 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
882 ifaceobj_getfunc
=None, **extra_args
):
883 """ run bond configuration on the interface object passed as argument
886 **ifaceobj** (object): iface object
888 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
892 **query_ifaceobj** (object): query check ifaceobject. This is only
893 valid when op is 'query-checkcurr'. It is an object same as
894 ifaceobj, but contains running attribute values and its config
895 status. The modules can use it to return queried running state
896 of interfaces. status is success if the running state is same
897 as user required state in ifaceobj. error otherwise.
899 op_handler
= self
._run
_ops
.get(operation
)
902 self
._init
_command
_handlers
()
903 if operation
== 'query-checkcurr':
904 op_handler(self
, ifaceobj
, query_ifaceobj
)
906 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)