3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from ifupdown
.iface
import *
13 import ifupdown
.policymanager
as policymanager
15 import ifupdown
.rtnetlink_api
as rtnetlink_api
16 import ifupdown
.ifupdownflags
as ifupdownflags
17 from ifupdownaddons
.modulebase
import moduleBase
18 from ifupdownaddons
.bondutil
import bondutil
19 from ifupdownaddons
.iproute2
import iproute2
20 from ifupdownaddons
.dhclient
import dhclient
25 class vrf(moduleBase
):
26 """ ifupdown2 addon module to configure vrfs """
27 _modinfo
= { 'mhelp' : 'vrf configuration module',
30 {'help' : 'vrf device table id. key to ' +
31 'creating a vrf device',
32 'example': ['vrf-table-id 1']},
34 {'help' : 'vrf device default route ' +
35 'to avoid communication outside the vrf device',
36 'example': ['vrf-default-route yes/no']},
38 {'help' : 'vrf the interface is part of.',
39 'example': ['vrf blue']}}}
41 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
42 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
43 '# It contains the vrf name to table mapping.\n' + \
44 '# Reserved table range %s %s\n'
45 VRF_TABLE_START
= 1001
48 def __init__(self
, *args
, **kargs
):
49 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
52 self
.dhclientcmd
= None
53 self
.name
= self
.__class
__.__name
__
54 if ifupdownflags
.flags
.PERFMODE
:
55 # if perf mode is set, remove vrf map file.
56 # start afresh. PERFMODE is set at boot
57 if os
.path
.exists(self
.iproute2_vrf_filename
):
59 self
.logger
.info('vrf: removing file %s'
60 %self
.iproute2_vrf_filename
)
61 os
.remove(self
.iproute2_vrf_filename
)
63 self
.logger
.debug('vrf: removing file failed (%s)'
66 ip_rules
= self
.exec_command('/sbin/ip rule show').splitlines()
67 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
69 self
.ip_rule_cache
= []
70 self
.logger
.warn('%s' %str
(e
))
73 ip_rules
= self
.exec_command('/sbin/ip -6 rule show').splitlines()
74 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
76 self
.ip6_rule_cache
= []
77 self
.logger
.warn('%s' %str
(e
))
79 #self.logger.debug("vrf: ip rule cache")
80 #self.logger.info(self.ip_rule_cache)
82 #self.logger.info("vrf: ip -6 rule cache")
83 #self.logger.info(self.ip6_rule_cache)
85 self
._iproute
2_vrf
_map
_initialized
= False
86 self
.iproute2_vrf_map
= {}
87 self
.iproute2_vrf_map_fd
= None
88 self
.iproute2_vrf_map_sync_to_disk
= False
90 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
91 if not self
.vrf_table_id_start
:
92 self
.vrf_table_id_start
= self
.VRF_TABLE_START
93 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
94 if not self
.vrf_table_id_end
:
95 self
.vrf_table_id_end
= self
.VRF_TABLE_END
96 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
98 self
.vrf_fix_local_table
= True
100 self
.vrf_cgroup_create
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-cgroup-create')
102 if not self
.vrf_cgroup_create
:
103 self
.vrf_cgroup_create
= False
104 elif self
.vrf_cgroup_create
== 'yes':
105 self
.vrf_cgroup_create
= True
107 self
.vrf_cgroup_create
= False
108 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
109 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
111 def _iproute2_vrf_map_initialize(self
):
112 if self
._iproute
2_vrf
_map
_initialized
:
115 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
116 self
.iproute2_vrf_map
= {}
117 iproute2_vrf_map_force_rewrite
= False
118 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
119 if os
.path
.exists(self
.iproute2_vrf_filename
):
120 vrf_map_fd
= open(self
.iproute2_vrf_filename
, 'r+')
121 lines
= vrf_map_fd
.readlines()
127 (table
, vrf_name
) = l
.strip().split()
128 if self
.iproute2_vrf_map
.get(int(table
)):
129 # looks like the existing file has
130 # duplicate entries, force rewrite of the
132 iproute2_vrf_map_force_rewrite
= True
134 self
.iproute2_vrf_map
[int(table
)] = vrf_name
136 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
140 vrfs
= self
.ipcmd
.link_get_vrfs()
143 for v
, lattrs
in vrfs
.iteritems():
144 table
= lattrs
.get('table', None)
146 running_vrf_map
[int(table
)] = v
148 if running_vrf_map
and (running_vrf_map
!= self
.iproute2_vrf_map
):
149 self
.iproute2_vrf_map
= running_vrf_map
150 iproute2_vrf_map_force_rewrite
= True
152 self
.iproute2_vrf_map_fd
= None
153 if iproute2_vrf_map_force_rewrite
:
154 # reopen the file and rewrite the map
155 self
._iproute
2_vrf
_map
_open
(True, False)
157 self
._iproute
2_vrf
_map
_open
(False, True)
159 self
.iproute2_vrf_map_sync_to_disk
= False
160 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
162 self
.logger
.info("vrf: dumping iproute2_vrf_map")
163 self
.logger
.info(self
.iproute2_vrf_map
)
165 last_used_vrf_table
= None
166 for t
in range(self
.vrf_table_id_start
,
167 self
.vrf_table_id_end
):
168 if not self
.iproute2_vrf_map
.get(t
):
170 last_used_vrf_table
= t
171 self
.last_used_vrf_table
= last_used_vrf_table
172 self
._iproute
2_vrf
_map
_initialized
= True
174 def _iproute2_vrf_map_sync_to_disk(self
):
175 if not self
.iproute2_vrf_map_sync_to_disk
:
177 self
.logger
.info('vrf: syncing table map to %s'
178 %self
.iproute2_vrf_filename
)
179 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
180 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
181 self
.vrf_table_id_end
))
182 for t
, v
in self
.iproute2_vrf_map
.iteritems():
183 f
.write('%s %s\n' %(t
, v
))
186 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
187 self
.logger
.info('vrf: syncing table map to %s'
188 %self
.iproute2_vrf_filename
)
189 fmode
= 'a+' if append
else 'w'
191 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
194 self
.log_warn('vrf: error opening %s (%s)'
195 %(self
.iproute2_vrf_filename
, str(e
)))
200 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
201 %(self
.vrf_table_id_start
,
202 self
.vrf_table_id_end
))
203 for t
, v
in self
.iproute2_vrf_map
.iteritems():
204 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
205 self
.iproute2_vrf_map_fd
.flush()
207 def _is_vrf(self
, ifaceobj
):
208 if ifaceobj
.get_attr_value_first('vrf-table'):
212 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
213 """ Returns list of interfaces dependent on ifaceobj """
215 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
217 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
218 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
219 ifaceobj
.role |
= ifaceRole
.MASTER
220 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
221 if not vrf_iface_name
:
223 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
224 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
226 return [vrf_iface_name
]
228 def get_upper_ifacenames_running(self
, ifaceobj
):
231 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
232 for t
, v
in self
.iproute2_vrf_map
.iteritems():
233 if v
== vrf_dev_name
:
237 def _get_avail_vrf_table_id(self
):
238 if self
.last_used_vrf_table
== None:
239 table_id_start
= self
.vrf_table_id_start
241 table_id_start
= self
.last_used_vrf_table
+ 1
242 for t
in range(table_id_start
,
243 self
.vrf_table_id_end
):
244 if not self
.iproute2_vrf_map
.get(t
):
245 self
.last_used_vrf_table
= t
249 def _iproute2_is_vrf_tableid_inuse(self
, vrf_dev_name
, table_id
):
250 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
251 if old_vrf_name
and old_vrf_name
!= vrf_dev_name
:
252 self
.log_error('table id %s already assigned to vrf dev %s'
253 %(table_id
, old_vrf_name
))
255 def _iproute2_vrf_table_entry_add(self
, vrf_dev_name
, table_id
):
256 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
258 self
.iproute2_vrf_map
[int(table_id
)] = vrf_dev_name
259 if self
.iproute2_vrf_map_fd
:
260 self
.iproute2_vrf_map_fd
.write('%s %s\n'
261 %(table_id
, vrf_dev_name
))
262 self
.iproute2_vrf_map_fd
.flush()
264 if old_vrf_name
!= vrf_dev_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'
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):
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
)
362 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
364 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
366 self
.log_error('%s: %s' %(ifacename
, str(e
)))
368 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
370 ip_rule_out_format
= '%s: from all %s %s lookup %s'
371 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
373 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
374 if rule
in self
.ip_rule_cache
:
375 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
377 self
.exec_command(rule_cmd
)
379 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
380 if rule
in self
.ip_rule_cache
:
381 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
383 self
.exec_command(rule_cmd
)
385 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
386 if rule
in self
.ip6_rule_cache
:
387 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
389 self
.exec_command(rule_cmd
)
391 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
392 if rule
in self
.ip6_rule_cache
:
393 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
395 self
.exec_command(rule_cmd
)
397 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
399 ip_rule_out_format
= '%s: from all %s %s lookup %s'
400 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
401 if self
.vrf_fix_local_table
:
402 self
.vrf_fix_local_table
= False
403 rule
= '0: from all lookup local'
404 if rule
in self
.ip_rule_cache
:
406 self
.exec_command('ip rule del pref 0')
407 self
.exec_command('ip rule add pref 32765 table local')
409 self
.logger
.info('%s' %str
(e
))
411 if rule
in self
.ip6_rule_cache
:
413 self
.exec_command('ip -6 rule del pref 0')
414 self
.exec_command('ip -6 rule add pref 32765 table local')
416 self
.logger
.info('%s' %str
(e
))
420 #200: from all oif blue lookup blue
421 #200: from all iif blue lookup blue
423 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
424 if rule
not in self
.ip_rule_cache
:
425 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
427 self
.exec_command(rule_cmd
)
429 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
430 if rule
not in self
.ip_rule_cache
:
431 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
433 self
.exec_command(rule_cmd
)
435 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
436 if rule
not in self
.ip6_rule_cache
:
437 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
439 self
.exec_command(rule_cmd
)
441 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
442 if rule
not in self
.ip6_rule_cache
:
443 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
445 self
.exec_command(rule_cmd
)
447 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
448 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
449 config_slaves
= ifaceobj
.lowerifaces
450 if not config_slaves
and not running_slaves
:
453 if not config_slaves
: config_slaves
= []
454 if not running_slaves
: running_slaves
= []
455 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
456 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
462 sobj
= ifaceobj_getfunc(s
)
463 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
464 sobj
[0] if sobj
else None,
465 ifaceobj_getfunc
, True)
467 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
474 sobj
= ifaceobj_getfunc(s
)
475 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
478 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
480 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
481 for s
in config_slaves
:
483 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
485 self
.logger
.debug('%s: %s: link set up (%s)'
486 %(ifaceobj
.name
, s
, str(e
)))
489 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
490 ifaceobj
.module_flags
[self
.name
] = \
491 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
492 vrfPrivFlags
.PROCESSED
494 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
495 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
499 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
500 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
501 if vrf_table
== 'auto':
502 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
504 self
.log_error('%s: unable to get an auto table id'
506 self
.logger
.info('%s: table id auto: selected table id %s\n'
507 %(ifaceobj
.name
, vrf_table
))
509 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
.name
, vrf_table
)
511 if not vrf_table
.isdigit():
512 self
.log_error('%s: vrf-table must be an integer or \'auto\''
513 %(ifaceobj
.name
), ifaceobj
)
515 # XXX: If we decide to not allow vrf id usages out of
516 # the reserved ifupdown range, then uncomment this code.
518 if (int(vrf_table
) < self
.vrf_table_id_start
or
519 int(vrf_table
) > self
.vrf_table_id_end
):
520 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
521 %(ifaceobj
.name
, vrf_table
,
522 self
.vrf_table_id_start
,
523 self
.vrf_table_id_end
))
525 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
526 {'table' : '%s' %vrf_table
})
528 self
.log_error('%s: create failed (%s)\n'
529 %(ifaceobj
.name
, str(e
)))
530 if vrf_table
!= 'auto':
531 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
.name
, vrf_table
)
533 if vrf_table
== 'auto':
534 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
536 self
.log_error('%s: unable to get vrf table id'
539 # if the device exists, check if table id is same
540 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
542 running_table
= vrfdev_attrs
.get('table', None)
543 if vrf_table
!= running_table
:
544 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
545 running_table
, vrf_table
))
548 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
550 self
.exec_command('%s create %s %s' %(self
.vrf_helper
,
551 ifaceobj
.name
, vrf_table
))
553 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
554 ifaceobj_getfunc
=None):
556 # if vrf dev is already processed return. This can happen
557 # if we the slave was configured before.
558 # see self._up_vrf_slave_without_master
559 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
563 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
565 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)))
568 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
569 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
571 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
572 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
573 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
575 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)))
577 def _kill_ssh_connections(self
, ifacename
):
579 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
580 if not runningaddrsdict
:
582 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
587 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
588 #users:(("sshd",pid=2528,fd=3))
589 cmdl
= ['/bin/ss', '-t', '-p']
590 for line
in subprocess
.check_output(cmdl
, stderr
=subprocess
.STDOUT
,
591 shell
=False).splitlines():
592 citems
= line
.split()
595 addr
= citems
[3].split('%')[0]
596 elif ':ssh' in citems
[3]:
597 addr
= citems
[3].split(':')[0]
602 proc
.append(citems
[5].split(',')[1].split('=')[1])
606 pid
= subprocess
.check_output(['/bin/ps', '--no-headers',
607 '-fp', str(os
.getppid())],
608 stderr
=subprocess
.STDOUT
,
609 shell
=False).split()[2]
610 self
.logger
.info("%s: killing active ssh sessions: %s"
611 %(ifacename
, str(proc
)))
615 os
.kill(int(id), signal
.SIGINT
)
619 # Kill current SSH client
624 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
625 if (forkret
== 0): # The first child.
628 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
629 except OSError, (err_no
, err_message
):
630 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
631 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
633 self
.logger
.info("%s: killing our session: %s"
634 %(ifacename
, str(proc
)))
635 os
.kill(int(pid
), signal
.SIGINT
)
640 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
642 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
644 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
646 self
._iproute
2_vrf
_map
_initialize
()
647 # This is a vrf device
648 if self
.vrf_count
== self
.vrf_max_count
:
649 self
.log_error('%s: max vrf count %d hit...not '
650 'creating vrf' %(ifaceobj
.name
,
652 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
654 vrf
= ifaceobj
.get_attr_value_first('vrf')
656 self
._iproute
2_vrf
_map
_initialize
()
657 # This is a vrf slave
658 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
661 # check if we were a slave before
662 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
664 self
._iproute
2_vrf
_map
_initialize
()
665 if self
._is
_vrf
_dev
(master
):
666 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
669 self
.log_error(str(e
))
671 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
673 self
.exec_command('%s delete %s %s' %(self
.vrf_helper
,
674 ifaceobj
.name
, vrf_table
))
676 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
678 if vrf_table
== 'auto':
679 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
682 self
.exec_command('/usr/bin/vrf service disable %s' %ifaceobj
.name
)
684 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
688 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
690 for s
in running_slaves
:
692 sobj
= ifaceobj_getfunc(s
)
693 self
._handle
_existing
_connections
(sobj
[0] if sobj
else None,
696 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
699 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
702 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
704 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
708 self
.ipcmd
.link_delete(ifaceobj
.name
)
710 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
714 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
716 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
720 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
722 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
723 self
.ipcmd
.link_set(ifacename
, 'nomaster')
724 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
726 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
728 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
730 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
732 self
._iproute
2_vrf
_map
_initialize
()
733 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
735 vrf
= ifaceobj
.get_attr_value_first('vrf')
737 self
._iproute
2_vrf
_map
_initialize
()
738 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
740 self
.log_warn(str(e
))
742 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
744 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
745 if not master
or master
!= vrf
:
746 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
748 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
750 self
.log_warn(str(e
))
752 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
754 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
755 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
757 if vrf_table
== 'auto':
758 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
760 config_table
= vrf_table
761 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
763 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
765 running_table
= vrfdev_attrs
.get('table')
766 if not running_table
:
767 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
769 if config_table
!= running_table
:
770 ifaceobjcurr
.update_config_with_status('vrf-table',
773 ifaceobjcurr
.update_config_with_status('vrf-table',
776 self
.log_warn(str(e
))
778 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
780 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
782 self
._iproute
2_vrf
_map
_initialize
()
783 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
785 vrf
= ifaceobj
.get_attr_value_first('vrf')
787 self
._iproute
2_vrf
_map
_initialize
()
788 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
790 self
.log_warn(str(e
))
792 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
794 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
796 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
798 running_table
= vrfdev_attrs
.get('table')
800 ifaceobjrunning
.update_config('vrf-table',
802 elif kind
== 'vrf_slave':
803 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
805 ifaceobjrunning
.update_config('vrf', vrf
)
807 self
.log_warn(str(e
))
809 _run_ops
= {'pre-up' : _up
,
811 'query-running' : _query_running
,
812 'query-checkcurr' : _query_check
}
815 """ returns list of ops supported by this module """
816 return self
._run
_ops
.keys()
818 def _init_command_handlers(self
):
820 self
.ipcmd
= iproute2()
822 self
.bondcmd
= bondutil()
823 if not self
.dhclientcmd
:
824 self
.dhclientcmd
= dhclient()
826 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
827 ifaceobj_getfunc
=None, **extra_args
):
828 """ run bond configuration on the interface object passed as argument
831 **ifaceobj** (object): iface object
833 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
837 **query_ifaceobj** (object): query check ifaceobject. This is only
838 valid when op is 'query-checkcurr'. It is an object same as
839 ifaceobj, but contains running attribute values and its config
840 status. The modules can use it to return queried running state
841 of interfaces. status is success if the running state is same
842 as user required state in ifaceobj. error otherwise.
844 op_handler
= self
._run
_ops
.get(operation
)
847 self
._init
_command
_handlers
()
848 if operation
== 'query-checkcurr':
849 op_handler(self
, ifaceobj
, query_ifaceobj
)
851 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)