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 from ifupdownaddons
.modulebase
import moduleBase
17 from ifupdownaddons
.bondutil
import bondutil
18 from ifupdownaddons
.iproute2
import iproute2
19 from ifupdownaddons
.dhclient
import dhclient
24 class vrf(moduleBase
):
25 """ ifupdown2 addon module to configure vrfs """
26 _modinfo
= { 'mhelp' : 'vrf configuration module',
29 {'help' : 'vrf device table id. key to ' +
30 'creating a vrf device',
31 'example': ['vrf-table-id 1']},
33 {'help' : 'vrf device default route ' +
34 'to avoid communication outside the vrf device',
35 'example': ['vrf-default-route yes/no']},
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 def __init__(self
, *args
, **kargs
):
48 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
51 self
.dhclientcmd
= None
52 self
.name
= self
.__class
__.__name
__
54 # if perf mode is set, remove vrf map file.
55 # start afresh. PERFMODE is set at boot
56 if os
.path
.exists(self
.iproute2_vrf_filename
):
58 self
.logger
.info('vrf: removing file %s'
59 %self
.iproute2_vrf_filename
)
60 os
.remove(self
.iproute2_vrf_filename
)
62 self
.logger
.debug('vrf: removing file failed (%s)'
65 ip_rules
= self
.exec_command('/sbin/ip rule show').splitlines()
66 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
68 self
.ip_rule_cache
= []
69 self
.logger
.warn('%s' %str
(e
))
72 ip_rules
= self
.exec_command('/sbin/ip -6 rule show').splitlines()
73 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
75 self
.ip6_rule_cache
= []
76 self
.logger
.warn('%s' %str
(e
))
78 #self.logger.debug("vrf: ip rule cache")
79 #self.logger.info(self.ip_rule_cache)
81 #self.logger.info("vrf: ip -6 rule cache")
82 #self.logger.info(self.ip6_rule_cache)
84 self
._iproute
2_vrf
_map
_initialized
= False
85 self
.iproute2_vrf_map
= {}
86 self
.iproute2_vrf_map_fd
= None
87 self
.iproute2_vrf_map_sync_to_disk
= False
89 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
90 if not self
.vrf_table_id_start
:
91 self
.vrf_table_id_start
= self
.VRF_TABLE_START
92 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
93 if not self
.vrf_table_id_end
:
94 self
.vrf_table_id_end
= self
.VRF_TABLE_END
95 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
97 self
.vrf_fix_local_table
= True
99 self
.vrf_cgroup_create
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-cgroup-create')
100 if not self
.vrf_cgroup_create
:
101 self
.vrf_cgroup_create
= False
102 elif self
.vrf_cgroup_create
== 'yes':
103 self
.vrf_cgroup_create
= True
105 self
.vrf_cgroup_create
= False
106 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
108 def _iproute2_vrf_map_initialize(self
):
109 if self
._iproute
2_vrf
_map
_initialized
:
112 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
113 self
.iproute2_vrf_map
= {}
114 iproute2_vrf_map_force_rewrite
= False
115 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
116 if os
.path
.exists(self
.iproute2_vrf_filename
):
117 vrf_map_fd
= open(self
.iproute2_vrf_filename
, 'r+')
118 lines
= vrf_map_fd
.readlines()
124 (table
, vrf_name
) = l
.strip().split()
125 if self
.iproute2_vrf_map
.get(int(table
)):
126 # looks like the existing file has
127 # duplicate entries, force rewrite of the
129 iproute2_vrf_map_force_rewrite
= True
131 self
.iproute2_vrf_map
[int(table
)] = vrf_name
133 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
137 vrfs
= self
.ipcmd
.link_get_vrfs()
140 for v
, lattrs
in vrfs
.iteritems():
141 table
= lattrs
.get('table', None)
143 running_vrf_map
[int(table
)] = v
145 if running_vrf_map
and (running_vrf_map
!= self
.iproute2_vrf_map
):
146 self
.iproute2_vrf_map
= running_vrf_map
147 iproute2_vrf_map_force_rewrite
= True
149 self
.iproute2_vrf_map_fd
= None
150 if iproute2_vrf_map_force_rewrite
:
151 # reopen the file and rewrite the map
152 self
._iproute
2_vrf
_map
_open
(True, False)
154 self
._iproute
2_vrf
_map
_open
(False, True)
156 self
.iproute2_vrf_map_sync_to_disk
= False
157 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
159 self
.logger
.info("vrf: dumping iproute2_vrf_map")
160 self
.logger
.info(self
.iproute2_vrf_map
)
162 last_used_vrf_table
= None
163 for t
in range(self
.vrf_table_id_start
,
164 self
.vrf_table_id_end
):
165 if not self
.iproute2_vrf_map
.get(t
):
167 last_used_vrf_table
= t
168 self
.last_used_vrf_table
= last_used_vrf_table
169 self
._iproute
2_vrf
_map
_initialized
= True
171 def _iproute2_vrf_map_sync_to_disk(self
):
172 if 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 fmode
= 'a+' if append
else 'w'
188 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
191 self
.log_warn('vrf: error opening %s (%s)'
192 %(self
.iproute2_vrf_filename
, str(e
)))
197 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
198 %(self
.vrf_table_id_start
,
199 self
.vrf_table_id_end
))
200 for t
, v
in self
.iproute2_vrf_map
.iteritems():
201 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
202 self
.iproute2_vrf_map_fd
.flush()
204 def _is_vrf(self
, ifaceobj
):
205 if ifaceobj
.get_attr_value_first('vrf-table'):
209 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
210 """ Returns list of interfaces dependent on ifaceobj """
212 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
214 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
215 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
216 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
217 if not vrf_iface_name
:
219 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
220 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
222 return [vrf_iface_name
]
224 def get_upper_ifacenames_running(self
, ifaceobj
):
227 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
228 for t
, v
in self
.iproute2_vrf_map
.iteritems():
229 if v
== vrf_dev_name
:
233 def _get_avail_vrf_table_id(self
):
234 if self
.last_used_vrf_table
== None:
235 table_id_start
= self
.vrf_table_id_start
237 table_id_start
= self
.last_used_vrf_table
+ 1
238 for t
in range(table_id_start
,
239 self
.vrf_table_id_end
):
240 if not self
.iproute2_vrf_map
.get(t
):
241 self
.last_used_vrf_table
= t
245 def _iproute2_vrf_table_entry_add(self
, vrf_dev_name
, table_id
):
246 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
247 if not old_vrf_name
or (old_vrf_name
!= vrf_dev_name
):
248 self
.iproute2_vrf_map
[int(table_id
)] = vrf_dev_name
249 if self
.iproute2_vrf_map_fd
:
250 self
.iproute2_vrf_map_fd
.write('%s %s\n'
251 %(table_id
, vrf_dev_name
))
252 self
.iproute2_vrf_map_fd
.flush()
254 def _iproute2_vrf_table_entry_del(self
, table_id
):
256 # with any del of vrf map, we need to force sync to disk
257 self
.iproute2_vrf_map_sync_to_disk
= True
258 del self
.iproute2_vrf_map
[int(table_id
)]
260 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
264 def _is_vrf_dev(self
, ifacename
):
265 # Look at iproute2 map for now.
266 # If it was a master we knew about,
267 # it is definately there
268 if ifacename
in self
.iproute2_vrf_map
.values():
272 def _is_dhcp_slave(self
, ifaceobj
):
273 if (not ifaceobj
.addr_method
or
274 (ifaceobj
.addr_method
!= 'dhcp' and
275 ifaceobj
.addr_method
!= 'dhcp6')):
279 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
281 """ If we have a vrf slave that has dhcp configured, bring up the
282 vrf master now. This is needed because vrf has special handling
283 in dhclient hook which requires the vrf master to be present """
285 vrf_master
= ifaceobj
.upperifaces
[0]
287 self
.logger
.warn('%s: vrf master not found' %ifacename
)
289 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
290 self
.logger
.info('%s: vrf master %s exists returning'
291 %(ifacename
, vrf_master
))
293 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
294 if not vrf_master_objs
:
295 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
297 self
.logger
.info('%s: bringing up vrf master %s'
298 %(ifacename
, vrf_master
))
299 for mobj
in vrf_master_objs
:
300 vrf_table
= mobj
.get_attr_value_first('vrf-table')
302 if vrf_table
== 'auto':
303 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
305 self
.log_error('%s: unable to get an auto table id'
307 self
.logger
.info('%s: table id auto: selected table id %s\n'
308 %(mobj
.name
, vrf_table
))
309 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
311 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
312 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
315 def _down_dhcp_slave(self
, ifaceobj
):
317 self
.dhclientcmd
.release(ifaceobj
.name
)
319 # ignore any dhclient release errors
322 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
323 if not ifaceobj
or self
.PERFMODE
:
325 if (self
.vrf_mgmt_devname
and
326 self
.vrf_mgmt_devname
== vrfname
):
327 self
._kill
_ssh
_connections
(ifaceobj
.name
)
328 if self
._is
_dhcp
_slave
(ifaceobj
):
329 self
._down
_dhcp
_slave
(ifaceobj
)
331 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
332 ifaceobj_getfunc
=None, vrf_exists
=False):
334 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
335 upper
= self
.ipcmd
.link_get_upper(ifacename
)
336 if not upper
or upper
!= vrfname
:
337 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
338 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
340 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
342 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "up")
344 self
.log_error('%s: %s' %(ifacename
, str(e
)))
346 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
348 ip_rule_out_format
= '%s: from all %s %s lookup %s'
349 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
351 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
352 if rule
in self
.ip_rule_cache
:
353 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
, vrf_table
)
354 self
.exec_command(rule_cmd
)
356 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
357 if rule
in self
.ip_rule_cache
:
358 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
, vrf_table
)
359 self
.exec_command(rule_cmd
)
361 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
362 if rule
in self
.ip6_rule_cache
:
363 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
365 self
.exec_command(rule_cmd
)
367 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
368 if rule
in self
.ip6_rule_cache
:
369 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
371 self
.exec_command(rule_cmd
)
373 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
375 ip_rule_out_format
= '%s: from all %s %s lookup %s'
376 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
377 if self
.vrf_fix_local_table
:
378 self
.vrf_fix_local_table
= False
379 rule
= '0: from all lookup local'
380 if rule
in self
.ip_rule_cache
:
382 self
.exec_command('ip rule del pref 0')
383 self
.exec_command('ip rule add pref 32765 table local')
385 self
.logger
.info('%s' %str
(e
))
387 if rule
in self
.ip6_rule_cache
:
389 self
.exec_command('ip -6 rule del pref 0')
390 self
.exec_command('ip -6 rule add pref 32765 table local')
392 self
.logger
.info('%s' %str
(e
))
396 #200: from all oif blue lookup blue
397 #200: from all iif blue lookup blue
399 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
400 if rule
not in self
.ip_rule_cache
:
401 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
, vrf_table
)
402 self
.exec_command(rule_cmd
)
404 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
405 if rule
not in self
.ip_rule_cache
:
406 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
, vrf_table
)
407 self
.exec_command(rule_cmd
)
409 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
410 if rule
not in self
.ip6_rule_cache
:
411 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
, vrf_table
)
412 self
.exec_command(rule_cmd
)
414 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
415 if rule
not in self
.ip6_rule_cache
:
416 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
418 self
.exec_command(rule_cmd
)
420 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
421 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
422 config_slaves
= ifaceobj
.lowerifaces
423 if not config_slaves
and not running_slaves
:
426 if not config_slaves
: config_slaves
= []
427 if not running_slaves
: running_slaves
= []
428 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
429 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
435 sobj
= ifaceobj_getfunc(s
)
436 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
437 sobj
[0] if sobj
else None,
438 ifaceobj_getfunc
, True)
440 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
447 sobj
= ifaceobj_getfunc(s
)
448 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
451 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
453 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
454 for s
in config_slaves
:
456 rtnetlink_api
.rtnl_api
.link_set(s
, "up")
458 self
.logger
.debug('%s: %s: link set up (%s)'
459 %(ifaceobj
.name
, s
, str(e
)))
462 def _create_cgroup(self
, ifaceobj
):
463 if not self
.vrf_cgroup_create
:
466 if not os
.path
.exists('/sys/fs/cgroup/l3mdev/%s' %ifaceobj
.name
):
467 self
.exec_command('/usr/bin/cgcreate -g l3mdev:%s' %ifaceobj
.name
)
469 self
.log_error('%s: cgroup create failed (%s)\n'
470 %(ifaceobj
.name
, str(e
)), ifaceobj
)
472 self
.exec_command('/usr/bin/cgset -r l3mdev.master-device=%s %s'
473 %(ifaceobj
.name
, ifaceobj
.name
))
475 self
.log_warn('%s: cgset failed (%s)\n'
476 %(ifaceobj
.name
, str(e
)), ifaceobj
)
478 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
479 ifaceobj
.module_flags
[self
.name
] = \
480 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
481 vrfPrivFlags
.PROCESSED
483 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
484 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) & vrfPrivFlags
.PROCESSED
):
488 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
489 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
490 if vrf_table
== 'auto':
491 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
493 self
.log_error('%s: unable to get an auto table id'
495 self
.logger
.info('%s: table id auto: selected table id %s\n'
496 %(ifaceobj
.name
, vrf_table
))
498 if not vrf_table
.isdigit():
499 self
.log_error('%s: vrf-table must be an integer or \'auto\''
500 %(ifaceobj
.name
), ifaceobj
)
502 # XXX: If we decide to not allow vrf id usages out of
503 # the reserved ifupdown range, then uncomment this code.
505 if (int(vrf_table
) < self
.vrf_table_id_start
or
506 int(vrf_table
) > self
.vrf_table_id_end
):
507 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
508 %(ifaceobj
.name
, vrf_table
,
509 self
.vrf_table_id_start
,
510 self
.vrf_table_id_end
))
512 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
513 {'table' : '%s' %vrf_table
})
515 self
.log_error('%s: create failed (%s)\n'
516 %(ifaceobj
.name
, str(e
)))
518 if vrf_table
== 'auto':
519 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
521 self
.log_error('%s: unable to get vrf table id'
524 # if the device exists, check if table id is same
525 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
527 running_table
= vrfdev_attrs
.get('table', None)
528 if vrf_table
!= running_table
:
529 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
530 running_table
, vrf_table
))
531 if vrf_table
!= 'auto':
532 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
.name
, vrf_table
)
536 def _add_del_vrf_default_route(self
, ifaceobj
, vrf_table
, add
=True):
537 vrf_default_route
= ifaceobj
.get_attr_value_first('vrf-default-route')
538 if not vrf_default_route
:
539 vrf_default_route
= policymanager
.policymanager_api
.get_attr_default(
540 module_name
=self
.__class
__.__name
__,
541 attr
='vrf-default-route')
542 if not vrf_default_route
:
544 if str(vrf_default_route
).lower() == "yes":
547 self
.exec_command('ip route add table %s unreachable '
548 'default metric %d' %(vrf_table
, 240))
550 self
.exec_command('ip route del table %s unreachable '
551 'default metric %d' %(vrf_table
, 240))
553 if add
and e
.errno
!= 17:
556 self
.logger
.info('%s: error deleting default route (%s)'
557 %(ifaceobj
.name
, str(e
)))
562 self
.exec_command('ip -6 route add table %s unreachable '
563 'default metric %d' %(vrf_table
, 240))
565 self
.exec_command('ip -6 route del table %s unreachable '
566 'default metric %d' %(vrf_table
, 240))
568 if add
and e
.errno
!= 17:
571 self
.logger
.info('%s: error deleting default route (%s)'
572 %(ifaceobj
.name
, str(e
)))
575 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
576 ifaceobj_getfunc
=None):
578 # if vrf dev is already processed return. This can happen
579 # if we the slave was configured before.
580 # see self._up_vrf_slave_without_master
581 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
584 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
586 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
587 self
._create
_cgroup
(ifaceobj
)
589 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
590 self
._add
_del
_vrf
_default
_route
(ifaceobj
, vrf_table
)
591 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
592 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
594 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)))
596 def _kill_ssh_connections(self
, ifacename
):
598 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
599 if not runningaddrsdict
:
601 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
606 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
607 #users:(("sshd",pid=2528,fd=3))
608 cmdl
= ['/bin/ss', '-t', '-p']
609 for line
in subprocess
.check_output(cmdl
, stderr
=subprocess
.STDOUT
,
610 shell
=False).splitlines():
611 citems
= line
.split()
614 addr
= citems
[3].split('%')[0]
615 elif ':ssh' in citems
[3]:
616 addr
= citems
[3].split(':')[0]
621 proc
.append(citems
[5].split(',')[1].split('=')[1])
625 pid
= subprocess
.check_output(['/bin/ps', '--no-headers',
626 '-fp', str(os
.getppid())],
627 stderr
=subprocess
.STDOUT
,
628 shell
=False).split()[2]
629 self
.logger
.info("%s: killing active ssh sessions: %s"
630 %(ifacename
, str(proc
)))
634 os
.kill(int(id), signal
.SIGINT
)
638 # Kill current SSH client
643 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
644 if (forkret
== 0): # The first child.
647 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
648 except OSError, (err_no
, err_message
):
649 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
650 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
652 self
.logger
.info("%s: killing our session: %s"
653 %(ifacename
, str(proc
)))
654 os
.kill(int(pid
), signal
.SIGINT
)
659 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
661 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
663 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
665 self
._iproute
2_vrf
_map
_initialize
()
666 # This is a vrf device
667 if self
.vrf_count
== self
.vrf_max_count
:
668 self
.log_error('%s: max vrf count %d hit...not '
669 'creating vrf' %(ifaceobj
.name
,
671 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
673 vrf
= ifaceobj
.get_attr_value_first('vrf')
675 self
._iproute
2_vrf
_map
_initialize
()
676 # This is a vrf slave
677 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
680 # check if we were a slave before
681 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
683 if self
._is
_vrf
_dev
(master
):
684 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
687 self
.log_error(str(e
))
689 def _delete_cgroup(self
, ifaceobj
):
691 if os
.path
.exists('/sys/fs/cgroup/l3mdev/%s' %ifaceobj
.name
):
692 self
.exec_command('/usr/bin/cgdelete -g l3mdev:%s' %ifaceobj
.name
)
694 self
.log_info('%s: cgroup delete failed (%s)\n'
695 %(ifaceobj
.name
, str(e
)), ifaceobj
)
697 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
699 if vrf_table
== 'auto':
700 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
703 self
.exec_command('/usr/cumulus/bin/cl-vrf service disable %s' %ifaceobj
.name
)
705 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
709 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
711 for s
in running_slaves
:
713 sobj
= ifaceobj_getfunc(s
)
714 self
._handle
_existing
_connections
(sobj
[0] if sobj
else None,
717 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
721 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
723 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
727 self
.ipcmd
.link_delete(ifaceobj
.name
)
729 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
733 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
734 self
._add
_del
_vrf
_default
_route
(ifaceobj
, vrf_table
, False)
735 self
._delete
_cgroup
(ifaceobj
)
737 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
741 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
743 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
744 self
.ipcmd
.link_set(ifacename
, 'nomaster')
745 rtnetlink_api
.rtnl_api
.link_set(ifacename
, "down")
747 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
749 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
751 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
753 self
._iproute
2_vrf
_map
_initialize
()
754 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
756 vrf
= ifaceobj
.get_attr_value_first('vrf')
758 self
._iproute
2_vrf
_map
_initialize
()
759 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
761 self
.log_warn(str(e
))
763 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
765 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
766 if not master
or master
!= vrf
:
767 ifaceobjcurr
.update_config_with_status('vrf', master
, 1)
769 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
771 self
.log_warn(str(e
))
773 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
775 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
776 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
778 if vrf_table
== 'auto':
779 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
781 config_table
= vrf_table
782 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
784 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
786 running_table
= vrfdev_attrs
.get('table')
787 if not running_table
:
788 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
790 if config_table
!= running_table
:
791 ifaceobjcurr
.update_config_with_status('vrf-table',
794 ifaceobjcurr
.update_config_with_status('vrf-table',
797 self
.log_warn(str(e
))
799 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
801 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
803 self
._iproute
2_vrf
_map
_initialize
()
804 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
806 vrf
= ifaceobj
.get_attr_value_first('vrf')
808 self
._iproute
2_vrf
_map
_initialize
()
809 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
811 self
.log_warn(str(e
))
813 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
815 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
817 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
819 running_table
= vrfdev_attrs
.get('table')
821 ifaceobjrunning
.update_config('vrf-table',
823 elif kind
== 'vrf_slave':
824 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
826 ifaceobjrunning
.update_config('vrf', vrf
)
828 self
.log_warn(str(e
))
830 _run_ops
= {'pre-up' : _up
,
832 'query-running' : _query_running
,
833 'query-checkcurr' : _query_check
}
836 """ returns list of ops supported by this module """
837 return self
._run
_ops
.keys()
839 def _init_command_handlers(self
):
840 flags
= self
.get_flags()
842 self
.ipcmd
= iproute2(**flags
)
844 self
.bondcmd
= bondutil(**flags
)
845 if not self
.dhclientcmd
:
846 self
.dhclientcmd
= dhclient(**flags
)
848 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
849 ifaceobj_getfunc
=None, **extra_args
):
850 """ run bond configuration on the interface object passed as argument
853 **ifaceobj** (object): iface object
855 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
859 **query_ifaceobj** (object): query check ifaceobject. This is only
860 valid when op is 'query-checkcurr'. It is an object same as
861 ifaceobj, but contains running attribute values and its config
862 status. The modules can use it to return queried running state
863 of interfaces. status is success if the running state is same
864 as user required state in ifaceobj. error otherwise.
866 op_handler
= self
._run
_ops
.get(operation
)
869 self
._init
_command
_handlers
()
870 if operation
== 'query-checkcurr':
871 op_handler(self
, ifaceobj
, query_ifaceobj
)
873 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)