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 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
63 if (ifupdownflags
.flags
.PERFMODE
and
64 not (self
.vrf_mgmt_devname
and os
.path
.exists('/sys/class/net/%s'
65 %self
.vrf_mgmt_devname
))):
66 # if perf mode is set (PERFMODE is set at boot), and this is the first
67 # time we are calling ifup at boot (check for mgmt vrf existance at
68 # boot, make sure this is really the first invocation at boot.
69 # ifup is called with PERFMODE at boot multiple times (once for mgmt vrf
70 # and the second time with all auto interfaces). We want to delete
71 # the map file only the first time. This is to avoid accidently
72 # deleting map file with a valid mgmt vrf entry
73 if os
.path
.exists(self
.iproute2_vrf_filename
):
75 self
.logger
.info('vrf: removing file %s'
76 %self
.iproute2_vrf_filename
)
77 os
.remove(self
.iproute2_vrf_filename
)
79 self
.logger
.debug('vrf: removing file failed (%s)'
82 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
83 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
85 self
.ip_rule_cache
= []
86 self
.logger
.warn('vrf: cache v4: %s' % str(e
))
89 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
90 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
92 self
.ip6_rule_cache
= []
93 self
.logger
.warn('vrf: cache v6: %s' % str(e
))
95 #self.logger.debug("vrf: ip rule cache")
96 #self.logger.info(self.ip_rule_cache)
98 #self.logger.info("vrf: ip -6 rule cache")
99 #self.logger.info(self.ip6_rule_cache)
101 self
.l3mdev_checked
= False
102 self
.l3mdev4_rule
= False
103 if self
._l3mdev
_rule
(self
.ip_rule_cache
):
104 self
.l3mdev4_rule
= True
105 self
.l3mdev_checked
= True
106 self
.l3mdev6_rule
= False
107 if self
._l3mdev
_rule
(self
.ip6_rule_cache
):
108 self
.l3mdev6_rule
= True
109 self
.l3mdev_checked
= True
110 self
._iproute
2_vrf
_map
_initialized
= False
111 self
.iproute2_vrf_map
= {}
112 self
.iproute2_vrf_map_fd
= None
113 self
.iproute2_vrf_map_sync_to_disk
= False
115 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
116 if not self
.vrf_table_id_start
:
117 self
.vrf_table_id_start
= self
.VRF_TABLE_START
118 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
119 if not self
.vrf_table_id_end
:
120 self
.vrf_table_id_end
= self
.VRF_TABLE_END
121 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
123 self
.vrf_fix_local_table
= True
125 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
127 self
.warn_on_vrf_map_write_err
= True
129 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
130 if self
._iproute
2_vrf
_map
_initialized
:
133 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
134 self
.iproute2_vrf_map
= {}
135 iproute2_vrf_map_force_rewrite
= False
136 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
137 if os
.path
.exists(self
.iproute2_vrf_filename
):
138 with
open(self
.iproute2_vrf_filename
, 'r+') as vrf_map_fd
:
139 lines
= vrf_map_fd
.readlines()
145 (table
, vrf_name
) = l
.strip().split()
146 if self
.iproute2_vrf_map
.get(int(table
)):
147 # looks like the existing file has
148 # duplicate entries, force rewrite of the
150 iproute2_vrf_map_force_rewrite
= True
152 self
.iproute2_vrf_map
[int(table
)] = vrf_name
154 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
158 vrfs
= self
.ipcmd
.link_get_vrfs()
161 for v
, lattrs
in vrfs
.iteritems():
162 table
= lattrs
.get('table', None)
164 running_vrf_map
[int(table
)] = v
166 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
167 self
.iproute2_vrf_map
= running_vrf_map
168 iproute2_vrf_map_force_rewrite
= True
170 self
.iproute2_vrf_map_fd
= None
172 if iproute2_vrf_map_force_rewrite
:
173 # reopen the file and rewrite the map
174 self
._iproute
2_vrf
_map
_open
(True, False)
176 self
._iproute
2_vrf
_map
_open
(False, True)
178 self
.iproute2_vrf_map_sync_to_disk
= False
179 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
181 self
.logger
.info("vrf: dumping iproute2_vrf_map")
182 self
.logger
.info(self
.iproute2_vrf_map
)
184 last_used_vrf_table
= None
185 for t
in range(self
.vrf_table_id_start
,
186 self
.vrf_table_id_end
):
187 if not self
.iproute2_vrf_map
.get(t
):
189 last_used_vrf_table
= t
190 self
.last_used_vrf_table
= last_used_vrf_table
191 self
._iproute
2_vrf
_map
_initialized
= True
192 self
.vrf_count
= len(self
.iproute2_vrf_map
)
194 def _iproute2_map_warn(self
, errstr
):
195 if self
.warn_on_vrf_map_write_err
:
196 if not os
.path
.exists('/etc/iproute2/rt_tables.d/'):
197 self
.logger
.info('unable to save iproute2 vrf to table ' +
198 'map (%s)\n' %errstr
)
199 self
.logger
.info('cannot find /etc/iproute2/rt_tables.d.' +
200 ' pls check if your iproute2 version' +
201 ' supports rt_tables.d')
203 self
.logger
.warn('unable to open iproute2 vrf to table ' +
204 'map (%s)\n' %errstr
)
205 self
.warn_on_vrf_map_write_err
= False
207 def _iproute2_vrf_map_sync_to_disk(self
):
208 if (ifupdownflags
.flags
.DRYRUN
or
209 not self
.iproute2_vrf_map_sync_to_disk
):
211 self
.logger
.info('vrf: syncing table map to %s'
212 %self
.iproute2_vrf_filename
)
214 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
215 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
216 self
.vrf_table_id_end
))
217 for t
, v
in self
.iproute2_vrf_map
.iteritems():
218 f
.write('%s %s\n' %(t
, v
))
221 self
._iproute
2_map
_warn
(str(e
))
224 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
225 self
.logger
.info('vrf: syncing table map to %s'
226 %self
.iproute2_vrf_filename
)
227 if ifupdownflags
.flags
.DRYRUN
:
229 fmode
= 'a+' if append
else 'w'
231 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
233 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
235 self
._iproute
2_map
_warn
(str(e
))
240 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
241 %(self
.vrf_table_id_start
,
242 self
.vrf_table_id_end
))
243 for t
, v
in self
.iproute2_vrf_map
.iteritems():
244 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
245 self
.iproute2_vrf_map_fd
.flush()
247 def _is_vrf(self
, ifaceobj
):
248 if ifaceobj
.get_attr_value_first('vrf-table'):
252 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
253 """ Returns list of interfaces dependent on ifaceobj """
255 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
257 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
258 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
259 ifaceobj
.role |
= ifaceRole
.MASTER
260 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
261 if not vrf_iface_name
:
263 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
264 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
266 return [vrf_iface_name
]
268 def get_upper_ifacenames_running(self
, ifaceobj
):
271 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
272 for t
, v
in self
.iproute2_vrf_map
.iteritems():
273 if v
== vrf_dev_name
:
277 def _get_avail_vrf_table_id(self
):
278 if self
.last_used_vrf_table
== None:
279 table_id_start
= self
.vrf_table_id_start
281 table_id_start
= self
.last_used_vrf_table
+ 1
282 for t
in range(table_id_start
,
283 self
.vrf_table_id_end
):
284 if not self
.iproute2_vrf_map
.get(t
):
285 self
.last_used_vrf_table
= t
289 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
290 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
291 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
292 self
.log_error('table id %s already assigned to vrf dev %s'
293 %(table_id
, old_vrf_name
), vrfifaceobj
)
295 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
296 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
298 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
299 if self
.iproute2_vrf_map_fd
:
300 self
.iproute2_vrf_map_fd
.write('%s %s\n'
301 %(table_id
, vrfifaceobj
.name
))
302 self
.iproute2_vrf_map_fd
.flush()
306 if old_vrf_name
!= vrfifaceobj
.name
:
307 self
.log_error('table id %d already assigned to vrf dev %s'
308 %(table_id
, old_vrf_name
))
310 def _iproute2_vrf_table_entry_del(self
, table_id
):
312 # with any del of vrf map, we need to force sync to disk
313 self
.iproute2_vrf_map_sync_to_disk
= True
314 del self
.iproute2_vrf_map
[int(table_id
)]
316 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
320 def _is_vrf_dev(self
, ifacename
):
321 # Look at iproute2 map for now.
322 # If it was a master we knew about,
323 # it is definately there
324 if ifacename
in self
.iproute2_vrf_map
.values():
328 def _is_dhcp_slave(self
, ifaceobj
):
329 if (not ifaceobj
.addr_method
or
330 (ifaceobj
.addr_method
!= 'dhcp' and
331 ifaceobj
.addr_method
!= 'dhcp6')):
335 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
337 """ If we have a vrf slave that has dhcp configured, bring up the
338 vrf master now. This is needed because vrf has special handling
339 in dhclient hook which requires the vrf master to be present """
341 vrf_master
= ifaceobj
.upperifaces
[0]
343 self
.logger
.warn('%s: vrf master not found' %ifacename
)
345 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
346 self
.logger
.info('%s: vrf master %s exists returning'
347 %(ifacename
, vrf_master
))
349 self
.logger
.info('%s: bringing up vrf master %s'
350 %(ifacename
, vrf_master
))
351 for mobj
in vrf_master_objs
:
352 vrf_table
= mobj
.get_attr_value_first('vrf-table')
354 if vrf_table
== 'auto':
355 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
357 self
.log_error('%s: unable to get an auto table id'
358 %mobj
.name
, ifaceobj
)
359 self
.logger
.info('%s: table id auto: selected table id %s\n'
360 %(mobj
.name
, vrf_table
))
362 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
366 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
367 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
370 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
372 dhclient_cmd_prefix
= None
373 if (vrfname
and self
.vrf_exec_cmd_prefix
and
374 self
.ipcmd
.link_exists(vrfname
)):
375 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
377 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
379 # ignore any dhclient release errors
382 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
383 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
385 if (self
.vrf_mgmt_devname
and
386 self
.vrf_mgmt_devname
== vrfname
):
387 self
._kill
_ssh
_connections
(ifaceobj
.name
)
388 if self
._is
_dhcp
_slave
(ifaceobj
):
389 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
391 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
392 ifaceobj_getfunc
=None, vrf_exists
=False):
395 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
396 upper
= self
.ipcmd
.link_get_upper(ifacename
)
397 if not upper
or upper
!= vrfname
:
398 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
399 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
401 vrf_master_objs
= ifaceobj_getfunc(vrfname
)
402 if not vrf_master_objs
:
403 # this is the case where vrf is assigned to an interface
404 # but user has not provided a vrf interface.
405 # people expect you to warn them but go ahead with the
406 # rest of the config on that interface
407 netlink
.link_set_updown(ifacename
, "up")
408 self
.log_error('vrf master ifaceobj %s not found'
411 if (ifupdownflags
.flags
.ALL
or
412 (ifupdownflags
.flags
.CLASS
and
413 ifaceobj
.classes
and vrf_master_objs
[0].classes
and
414 Set(ifaceobj
.classes
).intersection(vrf_master_objs
[0].classes
))):
415 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
,
419 master_exists
= False
421 master_exists
= False
423 netlink
.link_set_updown(ifacename
, "up")
425 self
.log_error('vrf %s not around, skipping vrf config'
426 %(vrfname), ifaceobj
)
428 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
430 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
432 ip_rule_out_format
= '%s: from all %s %s lookup %s'
433 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
435 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
436 if rule
in self
.ip_rule_cache
:
437 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
439 utils
.exec_command(rule_cmd
)
441 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
442 if rule
in self
.ip_rule_cache
:
443 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
445 utils
.exec_command(rule_cmd
)
447 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
448 if rule
in self
.ip6_rule_cache
:
449 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
451 utils
.exec_command(rule_cmd
)
453 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
454 if rule
in self
.ip6_rule_cache
:
455 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
457 utils
.exec_command(rule_cmd
)
459 def _l3mdev_rule(self
, ip_rules
):
460 for rule
in ip_rules
:
461 if not re
.search(r
"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
467 def _rule_cache_fill(self
):
468 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
469 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
470 self
.l3mdev4_rule
= self
._l3mdev
_rule
(self
.ip_rule_cache
)
471 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
472 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
473 self
.l3mdev6_rule
= self
._l3mdev
_rule
(self
.ip6_rule_cache
)
475 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
477 ip_rule_out_format
= '%s: from all %s %s lookup %s'
478 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
479 if self
.vrf_fix_local_table
:
480 self
.vrf_fix_local_table
= False
481 rule
= '0: from all lookup local'
482 if rule
in self
.ip_rule_cache
:
484 utils
.exec_command('ip rule del pref 0')
485 utils
.exec_command('ip rule add pref 32765 table local')
487 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
489 if rule
in self
.ip6_rule_cache
:
491 utils
.exec_command('ip -6 rule del pref 0')
492 utils
.exec_command('ip -6 rule add pref 32765 table local')
494 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
497 if not self
.l3mdev_checked
:
498 self
._rule
_cache
_fill
()
499 self
.l3mdev_checked
= True
501 #200: from all oif blue lookup blue
502 #200: from all iif blue lookup blue
504 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
505 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
506 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
508 utils
.exec_command(rule_cmd
)
510 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
511 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
512 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
514 utils
.exec_command(rule_cmd
)
516 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
517 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
518 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
520 utils
.exec_command(rule_cmd
)
522 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
523 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
524 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
526 utils
.exec_command(rule_cmd
)
528 def _is_address_virtual_slaves(self
, vrfobj
, config_vrfslaves
,
530 # Address virtual lines on a vrf slave will create
531 # macvlan devices on the vrf slave and enslave them
532 # to the vrf master. This function checks if the
533 # vrf slave is such a macvlan interface.
534 # XXX: additional possible checks that can be done here
536 # - check if it is also a macvlan device of the
537 # format <vrf_slave>-v<int> created by the
538 # address virtual module
539 vrfslave_lowers
= self
.ipcmd
.link_get_lowers(vrfslave
)
541 if vrfslave_lowers
[0] in config_vrfslaves
:
545 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
546 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
547 config_slaves
= ifaceobj
.lowerifaces
548 if not config_slaves
and not running_slaves
:
551 if not config_slaves
: config_slaves
= []
552 if not running_slaves
: running_slaves
= []
553 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
554 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
558 if not self
.ipcmd
.link_exists(s
):
562 sobj
= ifaceobj_getfunc(s
)
563 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
564 sobj
[0] if sobj
else None,
565 ifaceobj_getfunc
, True)
567 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
572 if self
._is
_address
_virtual
_slaves
(ifaceobj
,
577 sobj
= ifaceobj_getfunc(s
)
578 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
581 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
583 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
584 for s
in config_slaves
:
586 netlink
.link_set_updown(s
, "up")
588 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
591 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
592 ifaceobj
.module_flags
[self
.name
] = \
593 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
594 vrfPrivFlags
.PROCESSED
596 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
597 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
601 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
602 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
603 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
604 self
.log_error('cannot use system reserved %s vrf names'
605 %(str(self
.system_reserved_rt_tables
.values())),
607 if self
.vrf_count
== self
.vrf_max_count
:
608 self
.log_error('%s: max vrf count %d hit...not '
609 'creating vrf' %(ifaceobj
.name
,
610 self
.vrf_count
), ifaceobj
)
611 if vrf_table
== 'auto':
612 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
614 self
.log_error('%s: unable to get an auto table id'
615 %ifaceobj
.name
, ifaceobj
)
616 self
.logger
.info('%s: table id auto: selected table id %s\n'
617 %(ifaceobj
.name
, vrf_table
))
619 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
620 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
621 self
.log_error('cannot use system reserved %s table ids'
622 %(str(self
.system_reserved_rt_tables
.keys())),
625 if not vrf_table
.isdigit():
626 self
.log_error('%s: vrf-table must be an integer or \'auto\''
627 %(ifaceobj
.name
), ifaceobj
)
629 # XXX: If we decide to not allow vrf id usages out of
630 # the reserved ifupdown range, then uncomment this code.
632 if (int(vrf_table
) < self
.vrf_table_id_start
or
633 int(vrf_table
) > self
.vrf_table_id_end
):
634 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
635 %(ifaceobj
.name
, vrf_table
,
636 self
.vrf_table_id_start
,
637 self
.vrf_table_id_end
), ifaceobj
)
639 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
640 {'table' : '%s' %vrf_table
})
642 self
.log_error('%s: create failed (%s)\n'
643 %(ifaceobj
.name
, str(e
)), ifaceobj
)
644 if vrf_table
!= 'auto':
645 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
647 if vrf_table
== 'auto':
648 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
650 self
.log_error('%s: unable to get vrf table id'
651 %ifaceobj
.name
, ifaceobj
)
653 # if the device exists, check if table id is same
654 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
656 running_table
= vrfdev_attrs
.get('table', None)
657 if vrf_table
!= running_table
:
658 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
659 running_table
, vrf_table
),
663 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
665 if ifupdownflags
.flags
.PERFMODE
:
668 utils
.exec_command('%s create %s %s %s' %
674 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
675 ifaceobj_getfunc
=None):
677 # if vrf dev is already processed return. This can happen
678 # if we the slave was configured before.
679 # see self._up_vrf_slave_without_master
680 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
684 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
686 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
689 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
690 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
692 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
693 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
694 netlink
.link_set_updown(ifaceobj
.name
, "up")
696 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
698 def _kill_ssh_connections(self
, ifacename
):
700 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
701 if not runningaddrsdict
:
703 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
708 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
709 #users:(("sshd",pid=2528,fd=3))
710 cmdl
= ['/bin/ss', '-t', '-p']
711 for line
in utils
.exec_commandl(cmdl
).splitlines():
712 citems
= line
.split()
715 addr
= citems
[3].split('%')[0]
716 elif ':ssh' in citems
[3]:
717 addr
= citems
[3].split(':')[0]
722 proc
.append(citems
[5].split(',')[1].split('=')[1])
727 # outpt of '/usr/bin/pstree -Aps <pid>':
728 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
729 # get the above output to following format
730 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
731 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
732 for index
, process
in enumerate(pstree
):
733 # check the parent of SSH process to make sure
734 # we don't kill SSH server or systemd process
735 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
736 pid
= filter(lambda x
: x
.isdigit(), process
)
738 self
.logger
.info("%s: killing active ssh sessions: %s"
739 %(ifacename
, str(proc
)))
741 if ifupdownflags
.flags
.DRYRUN
:
746 os
.kill(int(id), signal
.SIGINT
)
750 # Kill current SSH client
755 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
756 if (forkret
== 0): # The first child.
759 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
760 except OSError, (err_no
, err_message
):
761 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
762 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
764 self
.logger
.info("%s: killing our session: %s"
765 %(ifacename
, str(proc
)))
766 os
.kill(int(pid
), signal
.SIGINT
)
771 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
773 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
775 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
777 self
._iproute
2_vrf
_map
_initialize
()
778 # This is a vrf device
779 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
781 vrf
= ifaceobj
.get_attr_value_first('vrf')
783 self
._iproute
2_vrf
_map
_initialize
()
784 # This is a vrf slave
785 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
788 # check if we were a slave before
789 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
791 self
._iproute
2_vrf
_map
_initialize
()
792 if self
._is
_vrf
_dev
(master
):
793 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
796 self
.log_error(str(e
), ifaceobj
)
798 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
800 if ifupdownflags
.flags
.PERFMODE
:
803 utils
.exec_command('%s delete %s %s %s' %
809 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
811 if vrf_table
== 'auto':
812 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
814 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
816 for s
in running_slaves
:
818 sobj
= ifaceobj_getfunc(s
)
820 self
._handle
_existing
_connections
(sobj
[0]
824 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
827 self
.ipcmd
.addr_flush(s
)
828 netlink
.link_set_updown(s
, "down")
830 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
834 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
836 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
840 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
842 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
846 self
.ipcmd
.link_delete(ifaceobj
.name
)
848 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
852 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
854 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
858 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
860 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
861 self
.ipcmd
.link_set(ifacename
, 'nomaster')
862 netlink
.link_set_updown(ifacename
, "down")
864 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
866 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
868 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
870 self
._iproute
2_vrf
_map
_initialize
()
871 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
873 vrf
= ifaceobj
.get_attr_value_first('vrf')
875 self
._iproute
2_vrf
_map
_initialize
()
876 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
878 self
.log_warn(str(e
))
880 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
882 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
883 if not master
or master
!= vrf
:
884 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
886 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
888 self
.log_error(str(e
), ifaceobjcurr
)
890 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
892 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
893 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
895 if vrf_table
== 'auto':
896 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
898 config_table
= vrf_table
899 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
901 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
903 running_table
= vrfdev_attrs
.get('table')
904 if not running_table
:
905 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
907 if config_table
!= running_table
:
908 ifaceobjcurr
.update_config_with_status('vrf-table',
911 ifaceobjcurr
.update_config_with_status('vrf-table',
913 if not ifupdownflags
.flags
.WITHDEFAULTS
:
917 utils
.exec_command('%s verify %s %s'
919 ifaceobj
.name
, config_table
))
920 ifaceobjcurr
.update_config_with_status('vrf-helper',
926 ifaceobjcurr
.update_config_with_status('vrf-helper',
933 self
.log_warn(str(e
))
935 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
937 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
939 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
940 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
942 vrf
= ifaceobj
.get_attr_value_first('vrf')
944 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
945 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
947 self
.log_warn(str(e
))
949 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
951 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
953 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
955 running_table
= vrfdev_attrs
.get('table')
957 ifaceobjrunning
.update_config('vrf-table',
959 elif kind
== 'vrf_slave':
960 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
962 ifaceobjrunning
.update_config('vrf', vrf
)
964 self
.log_warn(str(e
))
966 def _query(self
, ifaceobj
, **kwargs
):
967 if not self
.vrf_helper
:
969 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
970 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
973 _run_ops
= {'pre-up' : _up
,
975 'query-running' : _query_running
,
976 'query-checkcurr' : _query_check
,
980 """ returns list of ops supported by this module """
981 return self
._run
_ops
.keys()
983 def _init_command_handlers(self
):
985 self
.ipcmd
= iproute2()
987 self
.bondcmd
= bondutil()
988 if not self
.dhclientcmd
:
989 self
.dhclientcmd
= dhclient()
991 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
992 ifaceobj_getfunc
=None, **extra_args
):
993 """ run bond configuration on the interface object passed as argument
996 **ifaceobj** (object): iface object
998 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1002 **query_ifaceobj** (object): query check ifaceobject. This is only
1003 valid when op is 'query-checkcurr'. It is an object same as
1004 ifaceobj, but contains running attribute values and its config
1005 status. The modules can use it to return queried running state
1006 of interfaces. status is success if the running state is same
1007 as user required state in ifaceobj. error otherwise.
1009 op_handler
= self
._run
_ops
.get(operation
)
1012 self
._init
_command
_handlers
()
1013 if operation
== 'query-checkcurr':
1014 op_handler(self
, ifaceobj
, query_ifaceobj
)
1016 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)