3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
13 from ifupdown
.iface
import *
14 from ifupdown
.utils
import utils
15 import ifupdown
.policymanager
as policymanager
17 from ifupdown
.netlink
import netlink
18 import ifupdown
.ifupdownflags
as ifupdownflags
19 from ifupdownaddons
.modulebase
import moduleBase
20 from ifupdownaddons
.bondutil
import bondutil
21 from ifupdownaddons
.iproute2
import iproute2
22 from ifupdownaddons
.dhclient
import dhclient
23 from ifupdownaddons
.utilsbase
import *
28 class vrf(moduleBase
):
29 """ ifupdown2 addon module to configure vrfs """
30 _modinfo
= { 'mhelp' : 'vrf configuration module',
33 {'help' : 'vrf device routing table id. key to ' +
34 'creating a vrf device. ' +
35 'Table id is either \'auto\' or '+
36 '\'valid routing table id\'',
37 'example': ['vrf-table auto', 'vrf-table 1001']},
39 {'help' : 'vrf the interface is part of.',
40 'example': ['vrf blue']}}}
42 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
43 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
44 '# It contains the vrf name to table mapping.\n' + \
45 '# Reserved table range %s %s\n'
46 VRF_TABLE_START
= 1001
49 system_reserved_rt_tables
= {'255' : 'local', '254' : 'main',
50 '253' : 'default', '0' : 'unspec'}
52 def __init__(self
, *args
, **kargs
):
53 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
56 self
.dhclientcmd
= None
57 self
.name
= self
.__class
__.__name
__
58 if ifupdownflags
.flags
.PERFMODE
:
59 # if perf mode is set, remove vrf map file.
60 # start afresh. PERFMODE is set at boot
61 if os
.path
.exists(self
.iproute2_vrf_filename
):
63 self
.logger
.info('vrf: removing file %s'
64 %self
.iproute2_vrf_filename
)
65 os
.remove(self
.iproute2_vrf_filename
)
67 self
.logger
.debug('vrf: removing file failed (%s)'
70 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
71 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
73 self
.ip_rule_cache
= []
74 self
.logger
.warn('vrf: cache v4: %s' % str(e
))
77 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
78 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
80 self
.ip6_rule_cache
= []
81 self
.logger
.warn('vrf: cache v6: %s' % str(e
))
83 #self.logger.debug("vrf: ip rule cache")
84 #self.logger.info(self.ip_rule_cache)
86 #self.logger.info("vrf: ip -6 rule cache")
87 #self.logger.info(self.ip6_rule_cache)
89 self
.l3mdev_checked
= False
90 self
.l3mdev4_rule
= False
91 if self
._l3mdev
_rule
(self
.ip_rule_cache
):
92 self
.l3mdev4_rule
= True
93 self
.l3mdev_checked
= True
94 self
.l3mdev6_rule
= False
95 if self
._l3mdev
_rule
(self
.ip6_rule_cache
):
96 self
.l3mdev6_rule
= True
97 self
.l3mdev_checked
= True
98 self
._iproute
2_vrf
_map
_initialized
= False
99 self
.iproute2_vrf_map
= {}
100 self
.iproute2_vrf_map_fd
= None
101 self
.iproute2_vrf_map_sync_to_disk
= False
103 self
.vrf_table_id_start
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-start')
104 if not self
.vrf_table_id_start
:
105 self
.vrf_table_id_start
= self
.VRF_TABLE_START
106 self
.vrf_table_id_end
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-table-id-end')
107 if not self
.vrf_table_id_end
:
108 self
.vrf_table_id_end
= self
.VRF_TABLE_END
109 self
.vrf_max_count
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-max-count')
111 self
.vrf_fix_local_table
= True
113 self
.vrf_mgmt_devname
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-mgmt-devname')
114 self
.vrf_helper
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-helper')
116 def _iproute2_vrf_map_initialize(self
, writetodisk
=True):
117 if self
._iproute
2_vrf
_map
_initialized
:
120 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
121 self
.iproute2_vrf_map
= {}
122 iproute2_vrf_map_force_rewrite
= False
123 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
124 if os
.path
.exists(self
.iproute2_vrf_filename
):
125 with
open(self
.iproute2_vrf_filename
, 'r+') as vrf_map_fd
:
126 lines
= vrf_map_fd
.readlines()
132 (table
, vrf_name
) = l
.strip().split()
133 if self
.iproute2_vrf_map
.get(int(table
)):
134 # looks like the existing file has
135 # duplicate entries, force rewrite of the
137 iproute2_vrf_map_force_rewrite
= True
139 self
.iproute2_vrf_map
[int(table
)] = vrf_name
141 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
145 vrfs
= self
.ipcmd
.link_get_vrfs()
148 for v
, lattrs
in vrfs
.iteritems():
149 table
= lattrs
.get('table', None)
151 running_vrf_map
[int(table
)] = v
153 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
154 self
.iproute2_vrf_map
= running_vrf_map
155 iproute2_vrf_map_force_rewrite
= True
157 self
.iproute2_vrf_map_fd
= None
159 if iproute2_vrf_map_force_rewrite
:
160 # reopen the file and rewrite the map
161 self
._iproute
2_vrf
_map
_open
(True, False)
163 self
._iproute
2_vrf
_map
_open
(False, True)
165 self
.iproute2_vrf_map_sync_to_disk
= False
166 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
168 self
.logger
.info("vrf: dumping iproute2_vrf_map")
169 self
.logger
.info(self
.iproute2_vrf_map
)
171 last_used_vrf_table
= None
172 for t
in range(self
.vrf_table_id_start
,
173 self
.vrf_table_id_end
):
174 if not self
.iproute2_vrf_map
.get(t
):
176 last_used_vrf_table
= t
177 self
.last_used_vrf_table
= last_used_vrf_table
178 self
._iproute
2_vrf
_map
_initialized
= True
179 self
.vrf_count
= len(self
.iproute2_vrf_map
)
181 def _iproute2_vrf_map_sync_to_disk(self
):
182 if (ifupdownflags
.flags
.DRYRUN
or
183 not self
.iproute2_vrf_map_sync_to_disk
):
185 self
.logger
.info('vrf: syncing table map to %s'
186 %self
.iproute2_vrf_filename
)
187 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
188 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
189 self
.vrf_table_id_end
))
190 for t
, v
in self
.iproute2_vrf_map
.iteritems():
191 f
.write('%s %s\n' %(t
, v
))
194 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
195 self
.logger
.info('vrf: syncing table map to %s'
196 %self
.iproute2_vrf_filename
)
197 if ifupdownflags
.flags
.DRYRUN
:
199 fmode
= 'a+' if append
else 'w'
201 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
203 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
205 self
.log_warn('vrf: error opening %s (%s)'
206 %(self
.iproute2_vrf_filename
, str(e
)))
211 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
212 %(self
.vrf_table_id_start
,
213 self
.vrf_table_id_end
))
214 for t
, v
in self
.iproute2_vrf_map
.iteritems():
215 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
216 self
.iproute2_vrf_map_fd
.flush()
218 def _is_vrf(self
, ifaceobj
):
219 if ifaceobj
.get_attr_value_first('vrf-table'):
223 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
224 """ Returns list of interfaces dependent on ifaceobj """
226 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
228 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
229 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
230 ifaceobj
.role |
= ifaceRole
.MASTER
231 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
232 if not vrf_iface_name
:
234 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
235 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
237 return [vrf_iface_name
]
239 def get_upper_ifacenames_running(self
, ifaceobj
):
242 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
243 for t
, v
in self
.iproute2_vrf_map
.iteritems():
244 if v
== vrf_dev_name
:
248 def _get_avail_vrf_table_id(self
):
249 if self
.last_used_vrf_table
== None:
250 table_id_start
= self
.vrf_table_id_start
252 table_id_start
= self
.last_used_vrf_table
+ 1
253 for t
in range(table_id_start
,
254 self
.vrf_table_id_end
):
255 if not self
.iproute2_vrf_map
.get(t
):
256 self
.last_used_vrf_table
= t
260 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
261 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
262 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
263 self
.log_error('table id %s already assigned to vrf dev %s'
264 %(table_id
, old_vrf_name
), vrfifaceobj
)
266 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
267 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
269 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
270 if self
.iproute2_vrf_map_fd
:
271 self
.iproute2_vrf_map_fd
.write('%s %s\n'
272 %(table_id
, vrfifaceobj
.name
))
273 self
.iproute2_vrf_map_fd
.flush()
277 if old_vrf_name
!= vrfifaceobj
.name
:
278 self
.log_error('table id %d already assigned to vrf dev %s'
279 %(table_id
, old_vrf_name
))
281 def _iproute2_vrf_table_entry_del(self
, table_id
):
283 # with any del of vrf map, we need to force sync to disk
284 self
.iproute2_vrf_map_sync_to_disk
= True
285 del self
.iproute2_vrf_map
[int(table_id
)]
287 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
291 def _is_vrf_dev(self
, ifacename
):
292 # Look at iproute2 map for now.
293 # If it was a master we knew about,
294 # it is definately there
295 if ifacename
in self
.iproute2_vrf_map
.values():
299 def _is_dhcp_slave(self
, ifaceobj
):
300 if (not ifaceobj
.addr_method
or
301 (ifaceobj
.addr_method
!= 'dhcp' and
302 ifaceobj
.addr_method
!= 'dhcp6')):
306 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
308 """ If we have a vrf slave that has dhcp configured, bring up the
309 vrf master now. This is needed because vrf has special handling
310 in dhclient hook which requires the vrf master to be present """
312 vrf_master
= ifaceobj
.upperifaces
[0]
314 self
.logger
.warn('%s: vrf master not found' %ifacename
)
316 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
317 self
.logger
.info('%s: vrf master %s exists returning'
318 %(ifacename
, vrf_master
))
320 vrf_master_objs
= ifaceobj_getfunc(vrf_master
)
321 if not vrf_master_objs
:
322 self
.logger
.warn('%s: vrf master ifaceobj not found' %ifacename
)
324 self
.logger
.info('%s: bringing up vrf master %s'
325 %(ifacename
, vrf_master
))
326 for mobj
in vrf_master_objs
:
327 vrf_table
= mobj
.get_attr_value_first('vrf-table')
329 if vrf_table
== 'auto':
330 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
332 self
.log_error('%s: unable to get an auto table id'
333 %mobj
.name
, ifaceobj
)
334 self
.logger
.info('%s: table id auto: selected table id %s\n'
335 %(mobj
.name
, vrf_table
))
337 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
341 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
342 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
345 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
347 dhclient_cmd_prefix
= None
348 if (vrfname
and self
.vrf_exec_cmd_prefix
and
349 self
.ipcmd
.link_exists(vrfname
)):
350 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
352 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
354 # ignore any dhclient release errors
357 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
358 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
360 if (self
.vrf_mgmt_devname
and
361 self
.vrf_mgmt_devname
== vrfname
):
362 self
._kill
_ssh
_connections
(ifaceobj
.name
)
363 if self
._is
_dhcp
_slave
(ifaceobj
):
364 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
366 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
367 ifaceobj_getfunc
=None, vrf_exists
=False):
370 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
371 upper
= self
.ipcmd
.link_get_upper(ifacename
)
372 if not upper
or upper
!= vrfname
:
373 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
374 self
.ipcmd
.link_set(ifacename
, 'master', vrfname
)
375 elif ifupdownflags
.flags
.ALL
and ifaceobj
:
376 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
, ifaceobj
,
379 master_exists
= False
381 netlink
.link_set_updown(ifacename
, "up")
382 elif ifupdownflags
.flags
.ALL
:
383 self
.log_error('vrf %s not around, skipping vrf config'
384 %(vrfname), ifaceobj
)
386 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
388 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
390 ip_rule_out_format
= '%s: from all %s %s lookup %s'
391 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
393 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
394 if rule
in self
.ip_rule_cache
:
395 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
397 utils
.exec_command(rule_cmd
)
399 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
400 if rule
in self
.ip_rule_cache
:
401 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
403 utils
.exec_command(rule_cmd
)
405 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
406 if rule
in self
.ip6_rule_cache
:
407 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
409 utils
.exec_command(rule_cmd
)
411 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
412 if rule
in self
.ip6_rule_cache
:
413 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
415 utils
.exec_command(rule_cmd
)
417 def _l3mdev_rule(self
, ip_rules
):
418 for rule
in ip_rules
:
419 if not re
.search(r
"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
425 def _rule_cache_fill(self
):
426 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
427 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
428 self
.l3mdev4_rule
= self
._l3mdev
_rule
(self
.ip_rule_cache
)
429 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
430 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
431 self
.l3mdev6_rule
= self
._l3mdev
_rule
(self
.ip6_rule_cache
)
433 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
435 ip_rule_out_format
= '%s: from all %s %s lookup %s'
436 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
437 if self
.vrf_fix_local_table
:
438 self
.vrf_fix_local_table
= False
439 rule
= '0: from all lookup local'
440 if rule
in self
.ip_rule_cache
:
442 utils
.exec_command('ip rule del pref 0')
443 utils
.exec_command('ip rule add pref 32765 table local')
445 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
447 if rule
in self
.ip6_rule_cache
:
449 utils
.exec_command('ip -6 rule del pref 0')
450 utils
.exec_command('ip -6 rule add pref 32765 table local')
452 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
455 if not self
.l3mdev_checked
:
456 self
._rule
_cache
_fill
()
457 self
.l3mdev_checked
= True
459 #200: from all oif blue lookup blue
460 #200: from all iif blue lookup blue
462 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
463 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
464 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
466 utils
.exec_command(rule_cmd
)
468 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
469 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
470 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
472 utils
.exec_command(rule_cmd
)
474 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
475 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
476 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
478 utils
.exec_command(rule_cmd
)
480 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
481 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
482 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
484 utils
.exec_command(rule_cmd
)
486 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
487 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
488 config_slaves
= ifaceobj
.lowerifaces
489 if not config_slaves
and not running_slaves
:
492 if not config_slaves
: config_slaves
= []
493 if not running_slaves
: running_slaves
= []
494 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
495 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
499 if not self
.ipcmd
.link_exists(s
):
503 sobj
= ifaceobj_getfunc(s
)
504 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
505 sobj
[0] if sobj
else None,
506 ifaceobj_getfunc
, True)
508 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
515 sobj
= ifaceobj_getfunc(s
)
516 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
519 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
521 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
522 for s
in config_slaves
:
524 netlink
.link_set_updown(s
, "up")
526 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
529 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
530 ifaceobj
.module_flags
[self
.name
] = \
531 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
532 vrfPrivFlags
.PROCESSED
534 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
535 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
539 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
540 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
541 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
542 self
.log_error('cannot use system reserved %s vrf names'
543 %(str(self
.system_reserved_rt_tables
.values())),
545 if self
.vrf_count
== self
.vrf_max_count
:
546 self
.log_error('%s: max vrf count %d hit...not '
547 'creating vrf' %(ifaceobj
.name
,
548 self
.vrf_count
), ifaceobj
)
549 if vrf_table
== 'auto':
550 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
552 self
.log_error('%s: unable to get an auto table id'
553 %ifaceobj
.name
, ifaceobj
)
554 self
.logger
.info('%s: table id auto: selected table id %s\n'
555 %(ifaceobj
.name
, vrf_table
))
557 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
558 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
559 self
.log_error('cannot use system reserved %s table ids'
560 %(str(self
.system_reserved_rt_tables
.keys())),
563 if not vrf_table
.isdigit():
564 self
.log_error('%s: vrf-table must be an integer or \'auto\''
565 %(ifaceobj
.name
), ifaceobj
)
567 # XXX: If we decide to not allow vrf id usages out of
568 # the reserved ifupdown range, then uncomment this code.
570 if (int(vrf_table
) < self
.vrf_table_id_start
or
571 int(vrf_table
) > self
.vrf_table_id_end
):
572 self
.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
573 %(ifaceobj
.name
, vrf_table
,
574 self
.vrf_table_id_start
,
575 self
.vrf_table_id_end
), ifaceobj
)
577 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
578 {'table' : '%s' %vrf_table
})
580 self
.log_error('%s: create failed (%s)\n'
581 %(ifaceobj
.name
, str(e
)), ifaceobj
)
582 if vrf_table
!= 'auto':
583 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
585 if vrf_table
== 'auto':
586 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
588 self
.log_error('%s: unable to get vrf table id'
589 %ifaceobj
.name
, ifaceobj
)
591 # if the device exists, check if table id is same
592 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
594 running_table
= vrfdev_attrs
.get('table', None)
595 if vrf_table
!= running_table
:
596 self
.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj
.name
,
597 running_table
, vrf_table
),
601 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
603 if ifupdownflags
.flags
.PERFMODE
:
606 utils
.exec_command('%s create %s %s %s' %
612 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
613 ifaceobj_getfunc
=None):
615 # if vrf dev is already processed return. This can happen
616 # if we the slave was configured before.
617 # see self._up_vrf_slave_without_master
618 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
622 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
624 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
627 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
628 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
630 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
631 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
632 netlink
.link_set_updown(ifaceobj
.name
, "up")
634 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
636 def _kill_ssh_connections(self
, ifacename
):
638 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
639 if not runningaddrsdict
:
641 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
646 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
647 #users:(("sshd",pid=2528,fd=3))
648 cmdl
= ['/bin/ss', '-t', '-p']
649 for line
in utils
.exec_commandl(cmdl
).splitlines():
650 citems
= line
.split()
653 addr
= citems
[3].split('%')[0]
654 elif ':ssh' in citems
[3]:
655 addr
= citems
[3].split(':')[0]
660 proc
.append(citems
[5].split(',')[1].split('=')[1])
665 # outpt of '/usr/bin/pstree -Aps <pid>':
666 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
667 # get the above output to following format
668 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
669 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
670 for index
, process
in enumerate(pstree
):
671 # check the parent of SSH process to make sure
672 # we don't kill SSH server or systemd process
673 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
674 pid
= filter(lambda x
: x
.isdigit(), process
)
676 self
.logger
.info("%s: killing active ssh sessions: %s"
677 %(ifacename
, str(proc
)))
679 if ifupdownflags
.flags
.DRYRUN
:
684 os
.kill(int(id), signal
.SIGINT
)
688 # Kill current SSH client
693 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
694 if (forkret
== 0): # The first child.
697 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
698 except OSError, (err_no
, err_message
):
699 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
700 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
702 self
.logger
.info("%s: killing our session: %s"
703 %(ifacename
, str(proc
)))
704 os
.kill(int(pid
), signal
.SIGINT
)
709 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
711 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
713 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
715 self
._iproute
2_vrf
_map
_initialize
()
716 # This is a vrf device
717 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
719 vrf
= ifaceobj
.get_attr_value_first('vrf')
721 self
._iproute
2_vrf
_map
_initialize
()
722 # This is a vrf slave
723 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
726 # check if we were a slave before
727 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
729 self
._iproute
2_vrf
_map
_initialize
()
730 if self
._is
_vrf
_dev
(master
):
731 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
734 self
.log_error(str(e
), ifaceobj
)
736 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
738 if ifupdownflags
.flags
.PERFMODE
:
741 utils
.exec_command('%s delete %s %s %s' %
747 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
749 if vrf_table
== 'auto':
750 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
752 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
754 for s
in running_slaves
:
756 sobj
= ifaceobj_getfunc(s
)
758 self
._handle
_existing
_connections
(sobj
[0]
762 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
765 self
.ipcmd
.addr_flush(s
)
766 netlink
.link_set_updown(s
, "down")
768 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
772 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
774 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
778 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
780 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
784 self
.ipcmd
.link_delete(ifaceobj
.name
)
786 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
790 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
792 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
796 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
798 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
799 self
.ipcmd
.link_set(ifacename
, 'nomaster')
800 netlink
.link_set_updown(ifacename
, "down")
802 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
804 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
806 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
808 self
._iproute
2_vrf
_map
_initialize
()
809 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
811 vrf
= ifaceobj
.get_attr_value_first('vrf')
813 self
._iproute
2_vrf
_map
_initialize
()
814 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
816 self
.log_warn(str(e
))
818 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
820 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
821 if not master
or master
!= vrf
:
822 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
824 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
826 self
.log_error(str(e
), ifaceobjcurr
)
828 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
830 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
831 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
833 if vrf_table
== 'auto':
834 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
836 config_table
= vrf_table
837 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
839 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
841 running_table
= vrfdev_attrs
.get('table')
842 if not running_table
:
843 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
845 if config_table
!= running_table
:
846 ifaceobjcurr
.update_config_with_status('vrf-table',
849 ifaceobjcurr
.update_config_with_status('vrf-table',
851 if not ifupdownflags
.flags
.WITHDEFAULTS
:
855 utils
.exec_command('%s verify %s %s'
857 ifaceobj
.name
, config_table
))
858 ifaceobjcurr
.update_config_with_status('vrf-helper',
864 ifaceobjcurr
.update_config_with_status('vrf-helper',
871 self
.log_warn(str(e
))
873 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
875 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
877 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
878 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
880 vrf
= ifaceobj
.get_attr_value_first('vrf')
882 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
883 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
885 self
.log_warn(str(e
))
887 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
889 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
891 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
893 running_table
= vrfdev_attrs
.get('table')
895 ifaceobjrunning
.update_config('vrf-table',
897 elif kind
== 'vrf_slave':
898 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
900 ifaceobjrunning
.update_config('vrf', vrf
)
902 self
.log_warn(str(e
))
904 def _query(self
, ifaceobj
, **kwargs
):
905 if not self
.vrf_helper
:
907 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
908 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
911 _run_ops
= {'pre-up' : _up
,
913 'query-running' : _query_running
,
914 'query-checkcurr' : _query_check
,
918 """ returns list of ops supported by this module """
919 return self
._run
_ops
.keys()
921 def _init_command_handlers(self
):
923 self
.ipcmd
= iproute2()
925 self
.bondcmd
= bondutil()
926 if not self
.dhclientcmd
:
927 self
.dhclientcmd
= dhclient()
929 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
930 ifaceobj_getfunc
=None, **extra_args
):
931 """ run bond configuration on the interface object passed as argument
934 **ifaceobj** (object): iface object
936 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
940 **query_ifaceobj** (object): query check ifaceobject. This is only
941 valid when op is 'query-checkcurr'. It is an object same as
942 ifaceobj, but contains running attribute values and its config
943 status. The modules can use it to return queried running state
944 of interfaces. status is success if the running state is same
945 as user required state in ifaceobj. error otherwise.
947 op_handler
= self
._run
_ops
.get(operation
)
950 self
._init
_command
_handlers
()
951 if operation
== 'query-checkcurr':
952 op_handler(self
, ifaceobj
, query_ifaceobj
)
954 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)