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()
305 if old_vrf_name
!= vrfifaceobj
.name
:
306 self
.log_error('table id %d already assigned to vrf dev %s'
307 %(table_id
, old_vrf_name
))
309 def _iproute2_vrf_table_entry_del(self
, table_id
):
311 # with any del of vrf map, we need to force sync to disk
312 self
.iproute2_vrf_map_sync_to_disk
= True
313 del self
.iproute2_vrf_map
[int(table_id
)]
315 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
319 def _is_vrf_dev(self
, ifacename
):
320 # Look at iproute2 map for now.
321 # If it was a master we knew about,
322 # it is definately there
323 if ifacename
in self
.iproute2_vrf_map
.values():
327 def _is_dhcp_slave(self
, ifaceobj
):
328 if (not ifaceobj
.addr_method
or
329 (ifaceobj
.addr_method
!= 'dhcp' and
330 ifaceobj
.addr_method
!= 'dhcp6')):
334 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
336 """ If we have a vrf slave that has dhcp configured, bring up the
337 vrf master now. This is needed because vrf has special handling
338 in dhclient hook which requires the vrf master to be present """
340 vrf_master
= ifaceobj
.upperifaces
[0]
342 self
.logger
.warn('%s: vrf master not found' %ifacename
)
344 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
345 self
.logger
.info('%s: vrf master %s exists returning'
346 %(ifacename
, vrf_master
))
348 self
.logger
.info('%s: bringing up vrf master %s'
349 %(ifacename
, vrf_master
))
350 for mobj
in vrf_master_objs
:
351 vrf_table
= mobj
.get_attr_value_first('vrf-table')
353 if vrf_table
== 'auto':
354 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
356 self
.log_error('%s: unable to get an auto table id'
357 %mobj
.name
, ifaceobj
)
358 self
.logger
.info('%s: table id auto: selected table id %s\n'
359 %(mobj
.name
, vrf_table
))
361 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
365 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
366 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
369 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
371 dhclient_cmd_prefix
= None
372 if (vrfname
and self
.vrf_exec_cmd_prefix
and
373 self
.ipcmd
.link_exists(vrfname
)):
374 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
376 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
378 # ignore any dhclient release errors
381 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
382 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
384 if (self
.vrf_mgmt_devname
and
385 self
.vrf_mgmt_devname
== vrfname
):
386 self
._kill
_ssh
_connections
(ifaceobj
.name
)
387 if self
._is
_dhcp
_slave
(ifaceobj
):
388 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
390 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
391 ifaceobj_getfunc
=None, vrf_exists
=False):
394 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
395 upper
= self
.ipcmd
.link_get_upper(ifacename
)
396 if not upper
or upper
!= vrfname
:
397 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
398 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
400 vrf_master_objs
= ifaceobj_getfunc(vrfname
)
401 if not vrf_master_objs
:
402 # this is the case where vrf is assigned to an interface
403 # but user has not provided a vrf interface.
404 # people expect you to warn them but go ahead with the
405 # rest of the config on that interface
406 netlink
.link_set_updown(ifacename
, "up")
407 self
.log_error('vrf master ifaceobj %s not found'
410 if (ifupdownflags
.flags
.ALL
or
411 (ifupdownflags
.flags
.CLASS
and
412 ifaceobj
.classes
and vrf_master_objs
[0].classes
and
413 Set(ifaceobj
.classes
).intersection(vrf_master_objs
[0].classes
))):
414 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
,
418 master_exists
= False
420 master_exists
= False
422 netlink
.link_set_updown(ifacename
, "up")
424 self
.log_error('vrf %s not around, skipping vrf config'
425 %(vrfname), ifaceobj
)
427 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
429 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
431 ip_rule_out_format
= '%s: from all %s %s lookup %s'
432 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
434 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
435 if rule
in self
.ip_rule_cache
:
436 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
438 utils
.exec_command(rule_cmd
)
440 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
441 if rule
in self
.ip_rule_cache
:
442 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
444 utils
.exec_command(rule_cmd
)
446 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
447 if rule
in self
.ip6_rule_cache
:
448 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
450 utils
.exec_command(rule_cmd
)
452 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
453 if rule
in self
.ip6_rule_cache
:
454 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
456 utils
.exec_command(rule_cmd
)
458 def _l3mdev_rule(self
, ip_rules
):
459 for rule
in ip_rules
:
460 if not re
.search(r
"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
466 def _rule_cache_fill(self
):
467 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
468 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
469 self
.l3mdev4_rule
= self
._l3mdev
_rule
(self
.ip_rule_cache
)
470 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
471 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
472 self
.l3mdev6_rule
= self
._l3mdev
_rule
(self
.ip6_rule_cache
)
474 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
476 ip_rule_out_format
= '%s: from all %s %s lookup %s'
477 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
478 if self
.vrf_fix_local_table
:
479 self
.vrf_fix_local_table
= False
480 rule
= '0: from all lookup local'
481 if rule
in self
.ip_rule_cache
:
483 utils
.exec_command('ip rule del pref 0')
484 utils
.exec_command('ip rule add pref 32765 table local')
486 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
488 if rule
in self
.ip6_rule_cache
:
490 utils
.exec_command('ip -6 rule del pref 0')
491 utils
.exec_command('ip -6 rule add pref 32765 table local')
493 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
496 if not self
.l3mdev_checked
:
497 self
._rule
_cache
_fill
()
498 self
.l3mdev_checked
= True
500 #200: from all oif blue lookup blue
501 #200: from all iif blue lookup blue
503 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
504 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
505 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
507 utils
.exec_command(rule_cmd
)
509 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
510 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
511 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
513 utils
.exec_command(rule_cmd
)
515 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
516 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
517 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
519 utils
.exec_command(rule_cmd
)
521 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
522 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
523 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
525 utils
.exec_command(rule_cmd
)
527 def _is_address_virtual_slaves(self
, vrfobj
, config_vrfslaves
,
529 # Address virtual lines on a vrf slave will create
530 # macvlan devices on the vrf slave and enslave them
531 # to the vrf master. This function checks if the
532 # vrf slave is such a macvlan interface.
533 # XXX: additional possible checks that can be done here
535 # - check if it is also a macvlan device of the
536 # format <vrf_slave>-v<int> created by the
537 # address virtual module
538 vrfslave_lowers
= self
.ipcmd
.link_get_lowers(vrfslave
)
540 if vrfslave_lowers
[0] in config_vrfslaves
:
544 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
545 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
546 config_slaves
= ifaceobj
.lowerifaces
547 if not config_slaves
and not running_slaves
:
550 if not config_slaves
: config_slaves
= []
551 if not running_slaves
: running_slaves
= []
552 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
553 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
557 if not self
.ipcmd
.link_exists(s
):
561 sobj
= ifaceobj_getfunc(s
)
562 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
563 sobj
[0] if sobj
else None,
564 ifaceobj_getfunc
, True)
566 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
571 if self
._is
_address
_virtual
_slaves
(ifaceobj
,
576 sobj
= ifaceobj_getfunc(s
)
577 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
580 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
582 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
583 for s
in config_slaves
:
585 netlink
.link_set_updown(s
, "up")
587 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
590 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
591 ifaceobj
.module_flags
[self
.name
] = \
592 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
593 vrfPrivFlags
.PROCESSED
595 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
596 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
600 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
601 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
602 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
603 self
.log_error('cannot use system reserved %s vrf names'
604 %(str(self
.system_reserved_rt_tables
.values())),
606 if self
.vrf_count
== self
.vrf_max_count
:
607 self
.log_error('%s: max vrf count %d hit...not '
608 'creating vrf' %(ifaceobj
.name
,
609 self
.vrf_count
), ifaceobj
)
610 if vrf_table
== 'auto':
611 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
613 self
.log_error('%s: unable to get an auto table id'
614 %ifaceobj
.name
, ifaceobj
)
615 self
.logger
.info('%s: table id auto: selected table id %s\n'
616 %(ifaceobj
.name
, vrf_table
))
618 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
619 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
620 self
.log_error('cannot use system reserved %s table ids'
621 %(str(self
.system_reserved_rt_tables
.keys())),
624 if not vrf_table
.isdigit():
625 self
.log_error('%s: vrf-table must be an integer or \'auto\''
626 %(ifaceobj
.name
), ifaceobj
)
628 # XXX: If we decide to not allow vrf id usages out of
629 # the reserved ifupdown range, then uncomment this code.
631 if (int(vrf_table
) < self
.vrf_table_id_start
or
632 int(vrf_table
) > self
.vrf_table_id_end
):
633 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
634 %(ifaceobj
.name
, vrf_table
,
635 self
.vrf_table_id_start
,
636 self
.vrf_table_id_end
), ifaceobj
)
638 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
639 {'table' : '%s' %vrf_table
})
641 self
.log_error('%s: create failed (%s)\n'
642 %(ifaceobj
.name
, str(e
)), ifaceobj
)
643 if vrf_table
!= 'auto':
644 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
646 if vrf_table
== 'auto':
647 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
649 self
.log_error('%s: unable to get vrf table id'
650 %ifaceobj
.name
, ifaceobj
)
652 # if the device exists, check if table id is same
653 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
655 running_table
= vrfdev_attrs
.get('table', None)
656 if vrf_table
!= running_table
:
657 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
658 running_table
, vrf_table
),
662 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
664 if ifupdownflags
.flags
.PERFMODE
:
667 utils
.exec_command('%s create %s %s %s' %
673 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
674 ifaceobj_getfunc
=None):
676 # if vrf dev is already processed return. This can happen
677 # if we the slave was configured before.
678 # see self._up_vrf_slave_without_master
679 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
683 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
685 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
688 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
689 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
691 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
692 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
693 netlink
.link_set_updown(ifaceobj
.name
, "up")
695 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
697 def _kill_ssh_connections(self
, ifacename
):
699 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
700 if not runningaddrsdict
:
702 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
707 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
708 #users:(("sshd",pid=2528,fd=3))
709 cmdl
= ['/bin/ss', '-t', '-p']
710 for line
in utils
.exec_commandl(cmdl
).splitlines():
711 citems
= line
.split()
714 addr
= citems
[3].split('%')[0]
715 elif ':ssh' in citems
[3]:
716 addr
= citems
[3].split(':')[0]
721 proc
.append(citems
[5].split(',')[1].split('=')[1])
726 # outpt of '/usr/bin/pstree -Aps <pid>':
727 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
728 # get the above output to following format
729 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
730 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
731 for index
, process
in enumerate(pstree
):
732 # check the parent of SSH process to make sure
733 # we don't kill SSH server or systemd process
734 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
735 pid
= filter(lambda x
: x
.isdigit(), process
)
737 self
.logger
.info("%s: killing active ssh sessions: %s"
738 %(ifacename
, str(proc
)))
740 if ifupdownflags
.flags
.DRYRUN
:
745 os
.kill(int(id), signal
.SIGINT
)
749 # Kill current SSH client
754 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
755 if (forkret
== 0): # The first child.
758 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
759 except OSError, (err_no
, err_message
):
760 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
761 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
763 self
.logger
.info("%s: killing our session: %s"
764 %(ifacename
, str(proc
)))
765 os
.kill(int(pid
), signal
.SIGINT
)
770 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
772 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
774 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
776 self
._iproute
2_vrf
_map
_initialize
()
777 # This is a vrf device
778 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
780 vrf
= ifaceobj
.get_attr_value_first('vrf')
782 self
._iproute
2_vrf
_map
_initialize
()
783 # This is a vrf slave
784 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
787 # check if we were a slave before
788 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
790 self
._iproute
2_vrf
_map
_initialize
()
791 if self
._is
_vrf
_dev
(master
):
792 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
795 self
.log_error(str(e
), ifaceobj
)
797 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
799 if ifupdownflags
.flags
.PERFMODE
:
802 utils
.exec_command('%s delete %s %s %s' %
808 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
810 if vrf_table
== 'auto':
811 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
813 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
815 for s
in running_slaves
:
817 sobj
= ifaceobj_getfunc(s
)
819 self
._handle
_existing
_connections
(sobj
[0]
823 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
826 self
.ipcmd
.addr_flush(s
)
827 netlink
.link_set_updown(s
, "down")
829 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
833 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
835 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
839 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
841 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
845 self
.ipcmd
.link_delete(ifaceobj
.name
)
847 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
851 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
853 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
857 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
859 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
860 self
.ipcmd
.link_set(ifacename
, 'nomaster')
861 netlink
.link_set_updown(ifacename
, "down")
863 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
865 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
867 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
869 self
._iproute
2_vrf
_map
_initialize
()
870 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
872 vrf
= ifaceobj
.get_attr_value_first('vrf')
874 self
._iproute
2_vrf
_map
_initialize
()
875 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
877 self
.log_warn(str(e
))
879 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
881 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
882 if not master
or master
!= vrf
:
883 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
885 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
887 self
.log_error(str(e
), ifaceobjcurr
)
889 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
891 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
892 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
894 if vrf_table
== 'auto':
895 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
897 config_table
= vrf_table
898 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
900 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
902 running_table
= vrfdev_attrs
.get('table')
903 if not running_table
:
904 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
906 if config_table
!= running_table
:
907 ifaceobjcurr
.update_config_with_status('vrf-table',
910 ifaceobjcurr
.update_config_with_status('vrf-table',
912 if not ifupdownflags
.flags
.WITHDEFAULTS
:
916 utils
.exec_command('%s verify %s %s'
918 ifaceobj
.name
, config_table
))
919 ifaceobjcurr
.update_config_with_status('vrf-helper',
925 ifaceobjcurr
.update_config_with_status('vrf-helper',
932 self
.log_warn(str(e
))
934 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
936 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
938 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
939 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
941 vrf
= ifaceobj
.get_attr_value_first('vrf')
943 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
944 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
946 self
.log_warn(str(e
))
948 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
950 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
952 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
954 running_table
= vrfdev_attrs
.get('table')
956 ifaceobjrunning
.update_config('vrf-table',
958 elif kind
== 'vrf_slave':
959 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
961 ifaceobjrunning
.update_config('vrf', vrf
)
963 self
.log_warn(str(e
))
965 def _query(self
, ifaceobj
, **kwargs
):
966 if not self
.vrf_helper
:
968 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
969 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
972 _run_ops
= {'pre-up' : _up
,
974 'query-running' : _query_running
,
975 'query-checkcurr' : _query_check
,
979 """ returns list of ops supported by this module """
980 return self
._run
_ops
.keys()
982 def _init_command_handlers(self
):
984 self
.ipcmd
= iproute2()
986 self
.bondcmd
= bondutil()
987 if not self
.dhclientcmd
:
988 self
.dhclientcmd
= dhclient()
990 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
991 ifaceobj_getfunc
=None, **extra_args
):
992 """ run bond configuration on the interface object passed as argument
995 **ifaceobj** (object): iface object
997 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1001 **query_ifaceobj** (object): query check ifaceobject. This is only
1002 valid when op is 'query-checkcurr'. It is an object same as
1003 ifaceobj, but contains running attribute values and its config
1004 status. The modules can use it to return queried running state
1005 of interfaces. status is success if the running state is same
1006 as user required state in ifaceobj. error otherwise.
1008 op_handler
= self
._run
_ops
.get(operation
)
1011 self
._init
_command
_handlers
()
1012 if operation
== 'query-checkcurr':
1013 op_handler(self
, ifaceobj
, query_ifaceobj
)
1015 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)