3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
14 from ifupdown
.iface
import *
15 from ifupdown
.utils
import utils
16 import ifupdown
.policymanager
as policymanager
18 from ifupdown
.netlink
import netlink
19 import ifupdown
.ifupdownflags
as ifupdownflags
20 from ifupdownaddons
.modulebase
import moduleBase
21 from ifupdownaddons
.bondutil
import bondutil
22 from ifupdownaddons
.iproute2
import iproute2
23 from ifupdownaddons
.dhclient
import dhclient
24 from ifupdownaddons
.utilsbase
import *
29 class vrf(moduleBase
):
30 """ ifupdown2 addon module to configure vrfs """
31 _modinfo
= { 'mhelp' : 'vrf configuration module',
34 {'help' : 'vrf device routing table id. key to ' +
35 'creating a vrf device. ' +
36 'Table id is either \'auto\' or '+
37 '\'valid routing table id\'',
38 'validvals': ['auto', '<number>'],
39 'example': ['vrf-table auto', 'vrf-table 1001']},
41 {'help' : 'vrf the interface is part of.',
42 'validvals': ['<text>'],
43 'example': ['vrf blue']}}}
45 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
46 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
47 '# It contains the vrf name to table mapping.\n' + \
48 '# Reserved table range %s %s\n'
49 VRF_TABLE_START
= 1001
52 system_reserved_rt_tables
= {'255' : 'local', '254' : 'main',
53 '253' : 'default', '0' : 'unspec'}
55 def __init__(self
, *args
, **kargs
):
56 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
59 self
.dhclientcmd
= None
60 self
.name
= self
.__class
__.__name
__
61 if ifupdownflags
.flags
.PERFMODE
:
62 # if perf mode is set, remove vrf map file.
63 # start afresh. PERFMODE is set at boot
64 if os
.path
.exists(self
.iproute2_vrf_filename
):
66 self
.logger
.info('vrf: removing file %s'
67 %self
.iproute2_vrf_filename
)
68 os
.remove(self
.iproute2_vrf_filename
)
70 self
.logger
.debug('vrf: removing file failed (%s)'
73 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
74 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
76 self
.ip_rule_cache
= []
77 self
.logger
.warn('vrf: cache v4: %s' % str(e
))
80 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
81 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
83 self
.ip6_rule_cache
= []
84 self
.logger
.warn('vrf: cache v6: %s' % str(e
))
86 #self.logger.debug("vrf: ip rule cache")
87 #self.logger.info(self.ip_rule_cache)
89 #self.logger.info("vrf: ip -6 rule cache")
90 #self.logger.info(self.ip6_rule_cache)
92 self
.l3mdev_checked
= False
93 self
.l3mdev4_rule
= False
94 if self
._l3mdev
_rule
(self
.ip_rule_cache
):
95 self
.l3mdev4_rule
= True
96 self
.l3mdev_checked
= True
97 self
.l3mdev6_rule
= False
98 if self
._l3mdev
_rule
(self
.ip6_rule_cache
):
99 self
.l3mdev6_rule
= True
100 self
.l3mdev_checked
= True
101 self
._iproute
2_vrf
_map
_initialized
= False
102 self
.iproute2_vrf_map
= {}
103 self
.iproute2_vrf_map_fd
= None
104 self
.iproute2_vrf_map_sync_to_disk
= False
106 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
107 if not self
.vrf_table_id_start
:
108 self
.vrf_table_id_start
= self
.VRF_TABLE_START
109 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
110 if not self
.vrf_table_id_end
:
111 self
.vrf_table_id_end
= self
.VRF_TABLE_END
112 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
114 self
.vrf_fix_local_table
= True
116 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
117 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
119 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
120 if self
._iproute
2_vrf
_map
_initialized
:
123 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
124 self
.iproute2_vrf_map
= {}
125 iproute2_vrf_map_force_rewrite
= False
126 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
127 if os
.path
.exists(self
.iproute2_vrf_filename
):
128 with
open(self
.iproute2_vrf_filename
, 'r+') as vrf_map_fd
:
129 lines
= vrf_map_fd
.readlines()
135 (table
, vrf_name
) = l
.strip().split()
136 if self
.iproute2_vrf_map
.get(int(table
)):
137 # looks like the existing file has
138 # duplicate entries, force rewrite of the
140 iproute2_vrf_map_force_rewrite
= True
142 self
.iproute2_vrf_map
[int(table
)] = vrf_name
144 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
148 vrfs
= self
.ipcmd
.link_get_vrfs()
151 for v
, lattrs
in vrfs
.iteritems():
152 table
= lattrs
.get('table', None)
154 running_vrf_map
[int(table
)] = v
156 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
157 self
.iproute2_vrf_map
= running_vrf_map
158 iproute2_vrf_map_force_rewrite
= True
160 self
.iproute2_vrf_map_fd
= None
162 if iproute2_vrf_map_force_rewrite
:
163 # reopen the file and rewrite the map
164 self
._iproute
2_vrf
_map
_open
(True, False)
166 self
._iproute
2_vrf
_map
_open
(False, True)
168 self
.iproute2_vrf_map_sync_to_disk
= False
169 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
171 self
.logger
.info("vrf: dumping iproute2_vrf_map")
172 self
.logger
.info(self
.iproute2_vrf_map
)
174 last_used_vrf_table
= None
175 for t
in range(self
.vrf_table_id_start
,
176 self
.vrf_table_id_end
):
177 if not self
.iproute2_vrf_map
.get(t
):
179 last_used_vrf_table
= t
180 self
.last_used_vrf_table
= last_used_vrf_table
181 self
._iproute
2_vrf
_map
_initialized
= True
182 self
.vrf_count
= len(self
.iproute2_vrf_map
)
184 def _iproute2_vrf_map_sync_to_disk(self
):
185 if (ifupdownflags
.flags
.DRYRUN
or
186 not self
.iproute2_vrf_map_sync_to_disk
):
188 self
.logger
.info('vrf: syncing table map to %s'
189 %self
.iproute2_vrf_filename
)
190 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
191 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
192 self
.vrf_table_id_end
))
193 for t
, v
in self
.iproute2_vrf_map
.iteritems():
194 f
.write('%s %s\n' %(t
, v
))
197 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
198 self
.logger
.info('vrf: syncing table map to %s'
199 %self
.iproute2_vrf_filename
)
200 if ifupdownflags
.flags
.DRYRUN
:
202 fmode
= 'a+' if append
else 'w'
204 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
206 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
208 self
.log_warn('vrf: error opening %s (%s)'
209 %(self
.iproute2_vrf_filename
, str(e
)))
214 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
215 %(self
.vrf_table_id_start
,
216 self
.vrf_table_id_end
))
217 for t
, v
in self
.iproute2_vrf_map
.iteritems():
218 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
219 self
.iproute2_vrf_map_fd
.flush()
221 def _is_vrf(self
, ifaceobj
):
222 if ifaceobj
.get_attr_value_first('vrf-table'):
226 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
227 """ Returns list of interfaces dependent on ifaceobj """
229 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
231 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
232 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
233 ifaceobj
.role |
= ifaceRole
.MASTER
234 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
235 if not vrf_iface_name
:
237 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
238 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
240 return [vrf_iface_name
]
242 def get_upper_ifacenames_running(self
, ifaceobj
):
245 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
246 for t
, v
in self
.iproute2_vrf_map
.iteritems():
247 if v
== vrf_dev_name
:
251 def _get_avail_vrf_table_id(self
):
252 if self
.last_used_vrf_table
== None:
253 table_id_start
= self
.vrf_table_id_start
255 table_id_start
= self
.last_used_vrf_table
+ 1
256 for t
in range(table_id_start
,
257 self
.vrf_table_id_end
):
258 if not self
.iproute2_vrf_map
.get(t
):
259 self
.last_used_vrf_table
= t
263 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
264 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
265 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
266 self
.log_error('table id %s already assigned to vrf dev %s'
267 %(table_id
, old_vrf_name
), vrfifaceobj
)
269 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
270 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
272 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
273 if self
.iproute2_vrf_map_fd
:
274 self
.iproute2_vrf_map_fd
.write('%s %s\n'
275 %(table_id
, vrfifaceobj
.name
))
276 self
.iproute2_vrf_map_fd
.flush()
279 if old_vrf_name
!= vrfifaceobj
.name
:
280 self
.log_error('table id %d already assigned to vrf dev %s'
281 %(table_id
, old_vrf_name
))
283 def _iproute2_vrf_table_entry_del(self
, table_id
):
285 # with any del of vrf map, we need to force sync to disk
286 self
.iproute2_vrf_map_sync_to_disk
= True
287 del self
.iproute2_vrf_map
[int(table_id
)]
289 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
293 def _is_vrf_dev(self
, ifacename
):
294 # Look at iproute2 map for now.
295 # If it was a master we knew about,
296 # it is definately there
297 if ifacename
in self
.iproute2_vrf_map
.values():
301 def _is_dhcp_slave(self
, ifaceobj
):
302 if (not ifaceobj
.addr_method
or
303 (ifaceobj
.addr_method
!= 'dhcp' and
304 ifaceobj
.addr_method
!= 'dhcp6')):
308 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
310 """ If we have a vrf slave that has dhcp configured, bring up the
311 vrf master now. This is needed because vrf has special handling
312 in dhclient hook which requires the vrf master to be present """
314 vrf_master
= ifaceobj
.upperifaces
[0]
316 self
.logger
.warn('%s: vrf master not found' %ifacename
)
318 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
319 self
.logger
.info('%s: vrf master %s exists returning'
320 %(ifacename
, vrf_master
))
322 self
.logger
.info('%s: bringing up vrf master %s'
323 %(ifacename
, vrf_master
))
324 for mobj
in vrf_master_objs
:
325 vrf_table
= mobj
.get_attr_value_first('vrf-table')
327 if vrf_table
== 'auto':
328 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
330 self
.log_error('%s: unable to get an auto table id'
331 %mobj
.name
, ifaceobj
)
332 self
.logger
.info('%s: table id auto: selected table id %s\n'
333 %(mobj
.name
, vrf_table
))
335 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
339 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
340 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
343 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
345 dhclient_cmd_prefix
= None
346 if (vrfname
and self
.vrf_exec_cmd_prefix
and
347 self
.ipcmd
.link_exists(vrfname
)):
348 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
350 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
352 # ignore any dhclient release errors
355 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
356 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
358 if (self
.vrf_mgmt_devname
and
359 self
.vrf_mgmt_devname
== vrfname
):
360 self
._kill
_ssh
_connections
(ifaceobj
.name
)
361 if self
._is
_dhcp
_slave
(ifaceobj
):
362 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
364 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
365 ifaceobj_getfunc
=None, vrf_exists
=False):
368 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
369 upper
= self
.ipcmd
.link_get_upper(ifacename
)
370 if not upper
or upper
!= vrfname
:
371 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
372 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
374 vrf_master_objs
= ifaceobj_getfunc(vrfname
)
375 if not vrf_master_objs
:
376 # this is the case where vrf is assigned to an interface
377 # but user has not provided a vrf interface.
378 # people expect you to warn them but go ahead with the
379 # rest of the config on that interface
380 netlink
.link_set_updown(ifacename
, "up")
381 self
.log_error('vrf master ifaceobj %s not found'
384 if (ifupdownflags
.flags
.ALL
or
385 (ifupdownflags
.flags
.CLASS
and
386 ifaceobj
.classes
and vrf_master_objs
[0].classes
and
387 Set(ifaceobj
.classes
).intersection(vrf_master_objs
[0].classes
))):
388 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
,
392 master_exists
= False
394 master_exists
= False
396 netlink
.link_set_updown(ifacename
, "up")
398 self
.log_error('vrf %s not around, skipping vrf config'
399 %(vrfname), ifaceobj
)
401 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
403 def _del_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 del pref %s %s %s table %s'
408 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
409 if rule
in self
.ip_rule_cache
:
410 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
412 utils
.exec_command(rule_cmd
)
414 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
415 if rule
in self
.ip_rule_cache
:
416 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
418 utils
.exec_command(rule_cmd
)
420 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
421 if rule
in self
.ip6_rule_cache
:
422 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
424 utils
.exec_command(rule_cmd
)
426 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
427 if rule
in self
.ip6_rule_cache
:
428 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
430 utils
.exec_command(rule_cmd
)
432 def _l3mdev_rule(self
, ip_rules
):
433 for rule
in ip_rules
:
434 if not re
.search(r
"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
440 def _rule_cache_fill(self
):
441 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
442 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
443 self
.l3mdev4_rule
= self
._l3mdev
_rule
(self
.ip_rule_cache
)
444 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
445 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
446 self
.l3mdev6_rule
= self
._l3mdev
_rule
(self
.ip6_rule_cache
)
448 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
450 ip_rule_out_format
= '%s: from all %s %s lookup %s'
451 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
452 if self
.vrf_fix_local_table
:
453 self
.vrf_fix_local_table
= False
454 rule
= '0: from all lookup local'
455 if rule
in self
.ip_rule_cache
:
457 utils
.exec_command('ip rule del pref 0')
458 utils
.exec_command('ip rule add pref 32765 table local')
460 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
462 if rule
in self
.ip6_rule_cache
:
464 utils
.exec_command('ip -6 rule del pref 0')
465 utils
.exec_command('ip -6 rule add pref 32765 table local')
467 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
470 if not self
.l3mdev_checked
:
471 self
._rule
_cache
_fill
()
472 self
.l3mdev_checked
= True
474 #200: from all oif blue lookup blue
475 #200: from all iif blue lookup blue
477 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
478 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
479 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
481 utils
.exec_command(rule_cmd
)
483 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
484 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
485 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
487 utils
.exec_command(rule_cmd
)
489 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
490 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
491 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
493 utils
.exec_command(rule_cmd
)
495 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
496 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
497 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
499 utils
.exec_command(rule_cmd
)
501 def _is_address_virtual_slaves(self
, vrfobj
, config_vrfslaves
,
503 # Address virtual lines on a vrf slave will create
504 # macvlan devices on the vrf slave and enslave them
505 # to the vrf master. This function checks if the
506 # vrf slave is such a macvlan interface.
507 # XXX: additional possible checks that can be done here
509 # - check if it is also a macvlan device of the
510 # format <vrf_slave>-v<int> created by the
511 # address virtual module
512 vrfslave_lowers
= self
.ipcmd
.link_get_lowers(vrfslave
)
514 if vrfslave_lowers
[0] in config_vrfslaves
:
518 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
519 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
520 config_slaves
= ifaceobj
.lowerifaces
521 if not config_slaves
and not running_slaves
:
524 if not config_slaves
: config_slaves
= []
525 if not running_slaves
: running_slaves
= []
526 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
527 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
531 if not self
.ipcmd
.link_exists(s
):
535 sobj
= ifaceobj_getfunc(s
)
536 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
537 sobj
[0] if sobj
else None,
538 ifaceobj_getfunc
, True)
540 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
545 if self
._is
_address
_virtual
_slaves
(ifaceobj
,
550 sobj
= ifaceobj_getfunc(s
)
551 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
554 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
556 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
557 for s
in config_slaves
:
559 netlink
.link_set_updown(s
, "up")
561 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
564 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
565 ifaceobj
.module_flags
[self
.name
] = \
566 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
567 vrfPrivFlags
.PROCESSED
569 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
570 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
574 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
575 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
576 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
577 self
.log_error('cannot use system reserved %s vrf names'
578 %(str(self
.system_reserved_rt_tables
.values())),
580 if self
.vrf_count
== self
.vrf_max_count
:
581 self
.log_error('%s: max vrf count %d hit...not '
582 'creating vrf' %(ifaceobj
.name
,
583 self
.vrf_count
), ifaceobj
)
584 if vrf_table
== 'auto':
585 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
587 self
.log_error('%s: unable to get an auto table id'
588 %ifaceobj
.name
, ifaceobj
)
589 self
.logger
.info('%s: table id auto: selected table id %s\n'
590 %(ifaceobj
.name
, vrf_table
))
592 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
593 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
594 self
.log_error('cannot use system reserved %s table ids'
595 %(str(self
.system_reserved_rt_tables
.keys())),
598 if not vrf_table
.isdigit():
599 self
.log_error('%s: vrf-table must be an integer or \'auto\''
600 %(ifaceobj
.name
), ifaceobj
)
602 # XXX: If we decide to not allow vrf id usages out of
603 # the reserved ifupdown range, then uncomment this code.
605 if (int(vrf_table
) < self
.vrf_table_id_start
or
606 int(vrf_table
) > self
.vrf_table_id_end
):
607 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
608 %(ifaceobj
.name
, vrf_table
,
609 self
.vrf_table_id_start
,
610 self
.vrf_table_id_end
), ifaceobj
)
612 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
613 {'table' : '%s' %vrf_table
})
615 self
.log_error('%s: create failed (%s)\n'
616 %(ifaceobj
.name
, str(e
)), ifaceobj
)
617 if vrf_table
!= 'auto':
618 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
620 if vrf_table
== 'auto':
621 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
623 self
.log_error('%s: unable to get vrf table id'
624 %ifaceobj
.name
, ifaceobj
)
626 # if the device exists, check if table id is same
627 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
629 running_table
= vrfdev_attrs
.get('table', None)
630 if vrf_table
!= running_table
:
631 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
632 running_table
, vrf_table
),
636 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
638 if ifupdownflags
.flags
.PERFMODE
:
641 utils
.exec_command('%s create %s %s %s' %
647 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
648 ifaceobj_getfunc
=None):
650 # if vrf dev is already processed return. This can happen
651 # if we the slave was configured before.
652 # see self._up_vrf_slave_without_master
653 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
657 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
659 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
662 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
663 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
665 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
666 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
667 netlink
.link_set_updown(ifaceobj
.name
, "up")
669 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
671 def _kill_ssh_connections(self
, ifacename
):
673 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
674 if not runningaddrsdict
:
676 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
681 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
682 #users:(("sshd",pid=2528,fd=3))
683 cmdl
= ['/bin/ss', '-t', '-p']
684 for line
in utils
.exec_commandl(cmdl
).splitlines():
685 citems
= line
.split()
688 addr
= citems
[3].split('%')[0]
689 elif ':ssh' in citems
[3]:
690 addr
= citems
[3].split(':')[0]
695 proc
.append(citems
[5].split(',')[1].split('=')[1])
700 # outpt of '/usr/bin/pstree -Aps <pid>':
701 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
702 # get the above output to following format
703 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
704 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
705 for index
, process
in enumerate(pstree
):
706 # check the parent of SSH process to make sure
707 # we don't kill SSH server or systemd process
708 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
709 pid
= filter(lambda x
: x
.isdigit(), process
)
711 self
.logger
.info("%s: killing active ssh sessions: %s"
712 %(ifacename
, str(proc
)))
714 if ifupdownflags
.flags
.DRYRUN
:
719 os
.kill(int(id), signal
.SIGINT
)
723 # Kill current SSH client
728 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
729 if (forkret
== 0): # The first child.
732 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
733 except OSError, (err_no
, err_message
):
734 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
735 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
737 self
.logger
.info("%s: killing our session: %s"
738 %(ifacename
, str(proc
)))
739 os
.kill(int(pid
), signal
.SIGINT
)
744 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
746 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
748 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
750 self
._iproute
2_vrf
_map
_initialize
()
751 # This is a vrf device
752 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
754 vrf
= ifaceobj
.get_attr_value_first('vrf')
756 self
._iproute
2_vrf
_map
_initialize
()
757 # This is a vrf slave
758 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
761 # check if we were a slave before
762 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
764 self
._iproute
2_vrf
_map
_initialize
()
765 if self
._is
_vrf
_dev
(master
):
766 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
769 self
.log_error(str(e
), ifaceobj
)
771 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
773 if ifupdownflags
.flags
.PERFMODE
:
776 utils
.exec_command('%s delete %s %s %s' %
782 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
784 if vrf_table
== 'auto':
785 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
787 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
789 for s
in running_slaves
:
791 sobj
= ifaceobj_getfunc(s
)
793 self
._handle
_existing
_connections
(sobj
[0]
797 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
800 self
.ipcmd
.addr_flush(s
)
801 netlink
.link_set_updown(s
, "down")
803 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
807 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
809 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
813 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
815 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
819 self
.ipcmd
.link_delete(ifaceobj
.name
)
821 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
825 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
827 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
831 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
833 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
834 self
.ipcmd
.link_set(ifacename
, 'nomaster')
835 netlink
.link_set_updown(ifacename
, "down")
837 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
839 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
841 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
843 self
._iproute
2_vrf
_map
_initialize
()
844 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
846 vrf
= ifaceobj
.get_attr_value_first('vrf')
848 self
._iproute
2_vrf
_map
_initialize
()
849 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
851 self
.log_warn(str(e
))
853 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
855 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
856 if not master
or master
!= vrf
:
857 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
859 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
861 self
.log_error(str(e
), ifaceobjcurr
)
863 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
865 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
866 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
868 if vrf_table
== 'auto':
869 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
871 config_table
= vrf_table
872 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
874 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
876 running_table
= vrfdev_attrs
.get('table')
877 if not running_table
:
878 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
880 if config_table
!= running_table
:
881 ifaceobjcurr
.update_config_with_status('vrf-table',
884 ifaceobjcurr
.update_config_with_status('vrf-table',
886 if not ifupdownflags
.flags
.WITHDEFAULTS
:
890 utils
.exec_command('%s verify %s %s'
892 ifaceobj
.name
, config_table
))
893 ifaceobjcurr
.update_config_with_status('vrf-helper',
899 ifaceobjcurr
.update_config_with_status('vrf-helper',
906 self
.log_warn(str(e
))
908 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
910 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
912 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
913 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
915 vrf
= ifaceobj
.get_attr_value_first('vrf')
917 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
918 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
920 self
.log_warn(str(e
))
922 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
924 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
926 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
928 running_table
= vrfdev_attrs
.get('table')
930 ifaceobjrunning
.update_config('vrf-table',
932 elif kind
== 'vrf_slave':
933 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
935 ifaceobjrunning
.update_config('vrf', vrf
)
937 self
.log_warn(str(e
))
939 def _query(self
, ifaceobj
, **kwargs
):
940 if not self
.vrf_helper
:
942 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
943 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
946 _run_ops
= {'pre-up' : _up
,
948 'query-running' : _query_running
,
949 'query-checkcurr' : _query_check
,
953 """ returns list of ops supported by this module """
954 return self
._run
_ops
.keys()
956 def _init_command_handlers(self
):
958 self
.ipcmd
= iproute2()
960 self
.bondcmd
= bondutil()
961 if not self
.dhclientcmd
:
962 self
.dhclientcmd
= dhclient()
964 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
965 ifaceobj_getfunc
=None, **extra_args
):
966 """ run bond configuration on the interface object passed as argument
969 **ifaceobj** (object): iface object
971 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
975 **query_ifaceobj** (object): query check ifaceobject. This is only
976 valid when op is 'query-checkcurr'. It is an object same as
977 ifaceobj, but contains running attribute values and its config
978 status. The modules can use it to return queried running state
979 of interfaces. status is success if the running state is same
980 as user required state in ifaceobj. error otherwise.
982 op_handler
= self
._run
_ops
.get(operation
)
985 self
._init
_command
_handlers
()
986 if operation
== 'query-checkcurr':
987 op_handler(self
, ifaceobj
, query_ifaceobj
)
989 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)