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')
126 self
.vrf_close_socks_on_down
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='vrf-close-socks-on-down')
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 (%s)' %(l
, str(e
)))
157 vrfs
= self
.ipcmd
.link_get_vrfs()
160 for v
, lattrs
in vrfs
.iteritems():
161 table
= lattrs
.get('table', None)
163 running_vrf_map
[int(table
)] = v
165 if (not running_vrf_map
or (running_vrf_map
!= self
.iproute2_vrf_map
)):
166 self
.iproute2_vrf_map
= running_vrf_map
167 iproute2_vrf_map_force_rewrite
= True
169 self
.iproute2_vrf_map_fd
= None
171 if iproute2_vrf_map_force_rewrite
:
172 # reopen the file and rewrite the map
173 self
._iproute
2_vrf
_map
_open
(True, False)
175 self
._iproute
2_vrf
_map
_open
(False, True)
177 self
.iproute2_vrf_map_sync_to_disk
= False
178 atexit
.register(self
._iproute
2_vrf
_map
_sync
_to
_disk
)
180 self
.logger
.info("vrf: dumping iproute2_vrf_map")
181 self
.logger
.info(self
.iproute2_vrf_map
)
183 last_used_vrf_table
= None
184 for t
in range(self
.vrf_table_id_start
,
185 self
.vrf_table_id_end
):
186 if not self
.iproute2_vrf_map
.get(t
):
188 last_used_vrf_table
= t
189 self
.last_used_vrf_table
= last_used_vrf_table
190 self
._iproute
2_vrf
_map
_initialized
= True
191 self
.vrf_count
= len(self
.iproute2_vrf_map
)
193 def _iproute2_map_warn(self
, errstr
):
194 if self
.warn_on_vrf_map_write_err
:
195 if not os
.path
.exists('/etc/iproute2/rt_tables.d/'):
196 self
.logger
.info('unable to save iproute2 vrf to table ' +
197 'map (%s)\n' %errstr
)
198 self
.logger
.info('cannot find /etc/iproute2/rt_tables.d.' +
199 ' pls check if your iproute2 version' +
200 ' supports rt_tables.d')
202 self
.logger
.warn('unable to open iproute2 vrf to table ' +
203 'map (%s)\n' %errstr
)
204 self
.warn_on_vrf_map_write_err
= False
206 def _iproute2_vrf_map_sync_to_disk(self
):
207 if (ifupdownflags
.flags
.DRYRUN
or
208 not self
.iproute2_vrf_map_sync_to_disk
):
210 self
.logger
.info('vrf: syncing table map to %s'
211 %self
.iproute2_vrf_filename
)
213 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
214 f
.write(self
.iproute2_vrf_filehdr
%(self
.vrf_table_id_start
,
215 self
.vrf_table_id_end
))
216 for t
, v
in self
.iproute2_vrf_map
.iteritems():
217 f
.write('%s %s\n' %(t
, v
))
220 self
._iproute
2_map
_warn
(str(e
))
223 def _iproute2_vrf_map_open(self
, sync_vrfs
=False, append
=False):
224 self
.logger
.info('vrf: syncing table map to %s'
225 %self
.iproute2_vrf_filename
)
226 if ifupdownflags
.flags
.DRYRUN
:
228 fmode
= 'a+' if append
else 'w'
230 self
.iproute2_vrf_map_fd
= open(self
.iproute2_vrf_filename
,
232 fcntl
.fcntl(self
.iproute2_vrf_map_fd
, fcntl
.F_SETFD
, fcntl
.FD_CLOEXEC
)
234 self
._iproute
2_map
_warn
(str(e
))
239 self
.iproute2_vrf_map_fd
.write(self
.iproute2_vrf_filehdr
240 %(self
.vrf_table_id_start
,
241 self
.vrf_table_id_end
))
242 for t
, v
in self
.iproute2_vrf_map
.iteritems():
243 self
.iproute2_vrf_map_fd
.write('%s %s\n' %(t
, v
))
244 self
.iproute2_vrf_map_fd
.flush()
246 def _is_vrf(self
, ifaceobj
):
247 if ifaceobj
.get_attr_value_first('vrf-table'):
251 def get_upper_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
252 """ Returns list of interfaces dependent on ifaceobj """
254 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
256 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
257 ifaceobj
.link_kind |
= ifaceLinkKind
.VRF
258 ifaceobj
.role |
= ifaceRole
.MASTER
259 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
260 if not vrf_iface_name
:
262 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
263 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
265 return [vrf_iface_name
]
267 def get_upper_ifacenames_running(self
, ifaceobj
):
270 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
271 for t
, v
in self
.iproute2_vrf_map
.iteritems():
272 if v
== vrf_dev_name
:
276 def _get_avail_vrf_table_id(self
):
277 if self
.last_used_vrf_table
== None:
278 table_id_start
= self
.vrf_table_id_start
280 table_id_start
= self
.last_used_vrf_table
+ 1
281 for t
in range(table_id_start
,
282 self
.vrf_table_id_end
):
283 if not self
.iproute2_vrf_map
.get(t
):
284 self
.last_used_vrf_table
= t
288 def _iproute2_is_vrf_tableid_inuse(self
, vrfifaceobj
, table_id
):
289 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
290 if old_vrf_name
and old_vrf_name
!= vrfifaceobj
.name
:
291 self
.log_error('table id %s already assigned to vrf dev %s'
292 %(table_id
, old_vrf_name
), vrfifaceobj
)
294 def _iproute2_vrf_table_entry_add(self
, vrfifaceobj
, table_id
):
295 old_vrf_name
= self
.iproute2_vrf_map
.get(int(table_id
))
297 self
.iproute2_vrf_map
[int(table_id
)] = vrfifaceobj
.name
298 if self
.iproute2_vrf_map_fd
:
299 self
.iproute2_vrf_map_fd
.write('%s %s\n'
300 %(table_id
, vrfifaceobj
.name
))
301 self
.iproute2_vrf_map_fd
.flush()
304 if old_vrf_name
!= vrfifaceobj
.name
:
305 self
.log_error('table id %d already assigned to vrf dev %s'
306 %(table_id
, old_vrf_name
))
308 def _iproute2_vrf_table_entry_del(self
, table_id
):
310 # with any del of vrf map, we need to force sync to disk
311 self
.iproute2_vrf_map_sync_to_disk
= True
312 del self
.iproute2_vrf_map
[int(table_id
)]
314 self
.logger
.info('vrf: iproute2 vrf map del failed for %s (%s)'
318 def _is_vrf_dev(self
, ifacename
):
319 # Look at iproute2 map for now.
320 # If it was a master we knew about,
321 # it is definately there
322 if ifacename
in self
.iproute2_vrf_map
.values():
326 def _is_dhcp_slave(self
, ifaceobj
):
327 if (not ifaceobj
.addr_method
or
328 (ifaceobj
.addr_method
!= 'dhcp' and
329 ifaceobj
.addr_method
!= 'dhcp6')):
333 def _up_vrf_slave_without_master(self
, ifacename
, vrfname
, ifaceobj
,
335 """ If we have a vrf slave that has dhcp configured, bring up the
336 vrf master now. This is needed because vrf has special handling
337 in dhclient hook which requires the vrf master to be present """
339 vrf_master
= ifaceobj
.upperifaces
[0]
341 self
.logger
.warn('%s: vrf master not found' %ifacename
)
343 if os
.path
.exists('/sys/class/net/%s' %vrf_master
):
344 self
.logger
.info('%s: vrf master %s exists returning'
345 %(ifacename
, vrf_master
))
347 self
.logger
.info('%s: bringing up vrf master %s'
348 %(ifacename
, vrf_master
))
349 for mobj
in vrf_master_objs
:
350 vrf_table
= mobj
.get_attr_value_first('vrf-table')
352 if vrf_table
== 'auto':
353 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
355 self
.log_error('%s: unable to get an auto table id'
356 %mobj
.name
, ifaceobj
)
357 self
.logger
.info('%s: table id auto: selected table id %s\n'
358 %(mobj
.name
, vrf_table
))
360 self
._up
_vrf
_dev
(mobj
, vrf_table
, False)
364 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
365 netlink
.link_set_master(ifacename
, vrfname
)
368 def _down_dhcp_slave(self
, ifaceobj
, vrfname
):
370 dhclient_cmd_prefix
= None
371 if (vrfname
and self
.vrf_exec_cmd_prefix
and
372 self
.ipcmd
.link_exists(vrfname
)):
373 dhclient_cmd_prefix
= '%s %s' %(self
.vrf_exec_cmd_prefix
,
375 self
.dhclientcmd
.release(ifaceobj
.name
, dhclient_cmd_prefix
)
377 # ignore any dhclient release errors
380 def _handle_existing_connections(self
, ifaceobj
, vrfname
):
381 if not ifaceobj
or ifupdownflags
.flags
.PERFMODE
:
383 if (self
.vrf_mgmt_devname
and
384 self
.vrf_mgmt_devname
== vrfname
):
385 self
._kill
_ssh
_connections
(ifaceobj
.name
)
386 if self
._is
_dhcp
_slave
(ifaceobj
):
387 self
._down
_dhcp
_slave
(ifaceobj
, vrfname
)
389 def _up_vrf_slave(self
, ifacename
, vrfname
, ifaceobj
=None,
390 ifaceobj_getfunc
=None, vrf_exists
=False):
393 if vrf_exists
or self
.ipcmd
.link_exists(vrfname
):
394 uppers
= self
.ipcmd
.link_get_uppers(ifacename
)
395 if not uppers
or vrfname
not in uppers
:
396 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
397 netlink
.link_set_master(ifacename
, vrfname
)
399 vrf_master_objs
= ifaceobj_getfunc(vrfname
)
400 if not vrf_master_objs
:
401 # this is the case where vrf is assigned to an interface
402 # but user has not provided a vrf interface.
403 # people expect you to warn them but go ahead with the
404 # rest of the config on that interface
405 netlink
.link_set_updown(ifacename
, "up")
406 self
.log_error('vrf master ifaceobj %s not found'
409 if (ifupdownflags
.flags
.ALL
or
410 (ifupdownflags
.flags
.CLASS
and
411 ifaceobj
.classes
and vrf_master_objs
[0].classes
and
412 Set(ifaceobj
.classes
).intersection(vrf_master_objs
[0].classes
))):
413 self
._up
_vrf
_slave
_without
_master
(ifacename
, vrfname
,
417 master_exists
= False
419 master_exists
= False
421 netlink
.link_set_updown(ifacename
, "up")
423 self
.log_error('vrf %s not around, skipping vrf config'
424 %(vrfname), ifaceobj
)
426 self
.log_error('%s: %s' %(ifacename
, str(e
)), ifaceobj
)
428 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
430 ip_rule_out_format
= '%s: from all %s %s lookup %s'
431 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
433 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
434 if rule
in self
.ip_rule_cache
:
435 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
437 utils
.exec_command(rule_cmd
)
439 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
440 if rule
in self
.ip_rule_cache
:
441 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
443 utils
.exec_command(rule_cmd
)
445 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
446 if rule
in self
.ip6_rule_cache
:
447 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
449 utils
.exec_command(rule_cmd
)
451 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
452 if rule
in self
.ip6_rule_cache
:
453 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
455 utils
.exec_command(rule_cmd
)
457 def _l3mdev_rule(self
, ip_rules
):
458 for rule
in ip_rules
:
459 if not re
.search(r
"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
465 def _rule_cache_fill(self
):
466 ip_rules
= utils
.exec_command('/sbin/ip rule show').splitlines()
467 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
468 self
.l3mdev4_rule
= self
._l3mdev
_rule
(self
.ip_rule_cache
)
469 ip_rules
= utils
.exec_command('/sbin/ip -6 rule show').splitlines()
470 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
471 self
.l3mdev6_rule
= self
._l3mdev
_rule
(self
.ip6_rule_cache
)
473 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
475 ip_rule_out_format
= '%s: from all %s %s lookup %s'
476 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
477 if self
.vrf_fix_local_table
:
478 self
.vrf_fix_local_table
= False
479 rule
= '0: from all lookup local'
480 if rule
in self
.ip_rule_cache
:
482 utils
.exec_command('ip rule del pref 0')
483 utils
.exec_command('ip rule add pref 32765 table local')
485 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
487 if rule
in self
.ip6_rule_cache
:
489 utils
.exec_command('ip -6 rule del pref 0')
490 utils
.exec_command('ip -6 rule add pref 32765 table local')
492 self
.logger
.info('%s: %s' % (vrf_dev_name
, str(e
)))
495 if not self
.l3mdev_checked
:
496 self
._rule
_cache
_fill
()
497 self
.l3mdev_checked
= True
499 #200: from all oif blue lookup blue
500 #200: from all iif blue lookup blue
502 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
503 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
504 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
,
506 utils
.exec_command(rule_cmd
)
508 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
509 if not self
.l3mdev4_rule
and rule
not in self
.ip_rule_cache
:
510 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
,
512 utils
.exec_command(rule_cmd
)
514 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_dev_name
)
515 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
516 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
518 utils
.exec_command(rule_cmd
)
520 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_dev_name
)
521 if not self
.l3mdev6_rule
and rule
not in self
.ip6_rule_cache
:
522 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
524 utils
.exec_command(rule_cmd
)
526 def _is_address_virtual_slaves(self
, vrfobj
, config_vrfslaves
,
528 # Address virtual lines on a vrf slave will create
529 # macvlan devices on the vrf slave and enslave them
530 # to the vrf master. This function checks if the
531 # vrf slave is such a macvlan interface.
532 # XXX: additional possible checks that can be done here
534 # - check if it is also a macvlan device of the
535 # format <vrf_slave>-v<int> created by the
536 # address virtual module
537 vrfslave_lowers
= self
.ipcmd
.link_get_lowers(vrfslave
)
539 if vrfslave_lowers
[0] in config_vrfslaves
:
543 def _add_vrf_slaves(self
, ifaceobj
, ifaceobj_getfunc
=None):
544 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
545 config_slaves
= ifaceobj
.lowerifaces
546 if not config_slaves
and not running_slaves
:
549 if not config_slaves
: config_slaves
= []
550 if not running_slaves
: running_slaves
= []
551 add_slaves
= set(config_slaves
).difference(set(running_slaves
))
552 del_slaves
= set(running_slaves
).difference(set(config_slaves
))
556 if not self
.ipcmd
.link_exists(s
):
560 sobj
= ifaceobj_getfunc(s
)
561 self
._up
_vrf
_slave
(s
, ifaceobj
.name
,
562 sobj
[0] if sobj
else None,
563 ifaceobj_getfunc
, True)
565 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
570 if self
._is
_address
_virtual
_slaves
(ifaceobj
,
575 sobj
= ifaceobj_getfunc(s
)
576 self
._down
_vrf
_slave
(s
, sobj
[0] if sobj
else None,
579 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
581 if ifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
582 for s
in config_slaves
:
584 netlink
.link_set_updown(s
, "up")
586 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
589 def _set_vrf_dev_processed_flag(self
, ifaceobj
):
590 ifaceobj
.module_flags
[self
.name
] = \
591 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
592 vrfPrivFlags
.PROCESSED
594 def _check_vrf_dev_processed_flag(self
, ifaceobj
):
595 if (ifaceobj
.module_flags
.get(self
.name
, 0) & vrfPrivFlags
.PROCESSED
):
599 def _create_vrf_dev(self
, ifaceobj
, vrf_table
):
600 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
601 if ifaceobj
.name
in self
.system_reserved_rt_tables
.values():
602 self
.log_error('cannot use system reserved %s vrf names'
603 %(str(self
.system_reserved_rt_tables
.values())),
605 if self
.vrf_count
== self
.vrf_max_count
:
606 self
.log_error('max vrf count %d hit...not '
607 'creating vrf' % self
.vrf_count
, ifaceobj
)
608 if vrf_table
== 'auto':
609 vrf_table
= self
._get
_avail
_vrf
_table
_id
()
611 self
.log_error('unable to get an auto table id', ifaceobj
)
612 self
.logger
.info('%s: table id auto: selected table id %s\n'
613 %(ifaceobj
.name
, vrf_table
))
615 self
._iproute
2_is
_vrf
_tableid
_inuse
(ifaceobj
, vrf_table
)
616 if ifaceobj
.name
in self
.system_reserved_rt_tables
.keys():
617 self
.log_error('cannot use system reserved %s table ids'
618 %(str(self
.system_reserved_rt_tables
.keys())),
621 if not vrf_table
.isdigit():
622 self
.log_error('vrf-table must be an integer or \'auto\'', ifaceobj
)
624 # XXX: If we decide to not allow vrf id usages out of
625 # the reserved ifupdown range, then uncomment this code.
627 if (int(vrf_table
) < self
.vrf_table_id_start
or
628 int(vrf_table
) > self
.vrf_table_id_end
):
629 self
.log_error('vrf table id %s out of reserved range [%d,%d]'
631 self
.vrf_table_id_start
,
632 self
.vrf_table_id_end
), ifaceobj
)
634 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
635 {'table' : '%s' %vrf_table
})
637 self
.log_error('create failed (%s)\n' % str(e
), ifaceobj
)
638 if vrf_table
!= 'auto':
639 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
, vrf_table
)
641 if vrf_table
== 'auto':
642 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
644 self
.log_error('unable to get vrf table id', ifaceobj
)
646 # if the device exists, check if table id is same
647 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
649 running_table
= vrfdev_attrs
.get('table', None)
650 if vrf_table
!= running_table
:
651 self
.log_error('cannot change vrf table id,running table id'
652 ' %s is different from config id %s'
653 % (running_table
, vrf_table
), ifaceobj
)
656 def _up_vrf_helper(self
, ifaceobj
, vrf_table
):
658 if ifupdownflags
.flags
.PERFMODE
:
661 utils
.exec_command('%s create %s %s %s' %
667 def _up_vrf_dev(self
, ifaceobj
, vrf_table
, add_slaves
=True,
668 ifaceobj_getfunc
=None):
670 # if vrf dev is already processed return. This can happen
671 # if we the slave was configured before.
672 # see self._up_vrf_slave_without_master
673 if self
._check
_vrf
_dev
_processed
_flag
(ifaceobj
):
677 vrf_table
= self
._create
_vrf
_dev
(ifaceobj
, vrf_table
)
679 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
682 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
683 self
._up
_vrf
_helper
(ifaceobj
, vrf_table
)
685 self
._add
_vrf
_slaves
(ifaceobj
, ifaceobj_getfunc
)
686 self
._set
_vrf
_dev
_processed
_flag
(ifaceobj
)
687 netlink
.link_set_updown(ifaceobj
.name
, "up")
689 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
691 def _kill_ssh_connections(self
, ifacename
):
693 runningaddrsdict
= self
.ipcmd
.addr_get(ifacename
)
694 if not runningaddrsdict
:
696 iplist
= [i
.split('/', 1)[0] for i
in runningaddrsdict
.keys()]
701 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
702 #users:(("sshd",pid=2528,fd=3))
703 cmdl
= ['/bin/ss', '-t', '-p']
704 for line
in utils
.exec_commandl(cmdl
).splitlines():
705 citems
= line
.split()
708 addr
= citems
[3].split('%')[0]
709 elif ':ssh' in citems
[3]:
710 addr
= citems
[3].split(':')[0]
715 proc
.append(citems
[5].split(',')[1].split('=')[1])
720 # outpt of '/usr/bin/pstree -Aps <pid>':
721 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
722 # get the above output to following format
723 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
724 pstree
= list(reversed(utils
.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
725 for index
, process
in enumerate(pstree
):
726 # check the parent of SSH process to make sure
727 # we don't kill SSH server or systemd process
728 if 'sshd' in process
and 'sshd' in pstree
[index
+ 1]:
729 pid
= filter(lambda x
: x
.isdigit(), process
)
731 self
.logger
.info("%s: killing active ssh sessions: %s"
732 %(ifacename
, str(proc
)))
734 if ifupdownflags
.flags
.DRYRUN
:
739 os
.kill(int(id), signal
.SIGINT
)
743 # Kill current SSH client
748 self
.logger
.info("fork error : %s [%d]" % (e
.strerror
, e
.errno
))
749 if (forkret
== 0): # The first child.
752 self
.logger
.info("%s: ifreload continuing in the background" %ifacename
)
753 except OSError, (err_no
, err_message
):
754 self
.logger
.info("os.setsid failed: errno=%d: %s" % (err_no
, err_message
))
755 self
.logger
.info("pid=%d pgid=%d" % (os
.getpid(), os
.getpgid(0)))
757 self
.logger
.info("%s: killing our session: %s"
758 %(ifacename
, str(proc
)))
759 os
.kill(int(pid
), signal
.SIGINT
)
764 self
.logger
.info('%s: %s' %(ifacename
, str(e
)))
766 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
768 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
770 self
._iproute
2_vrf
_map
_initialize
()
771 # This is a vrf device
772 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
, True, ifaceobj_getfunc
)
774 vrf
= ifaceobj
.get_attr_value_first('vrf')
776 self
._iproute
2_vrf
_map
_initialize
()
777 # This is a vrf slave
778 self
._up
_vrf
_slave
(ifaceobj
.name
, vrf
, ifaceobj
,
781 # check if we were a slave before
782 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
784 self
._iproute
2_vrf
_map
_initialize
()
785 if self
._is
_vrf
_dev
(master
):
786 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
,
789 self
.log_error(str(e
), ifaceobj
)
791 def _down_vrf_helper(self
, ifaceobj
, vrf_table
):
793 if ifupdownflags
.flags
.PERFMODE
:
796 utils
.exec_command('%s delete %s %s %s' %
802 def _close_sockets(self
, ifaceobj
, ifindex
):
803 if not self
.vrf_close_socks_on_down
:
807 utils
.exec_command('/bin/ss -aK \"dev == %s\"'
810 self
.logger
.info('%s: closing socks using ss'
811 ' failed (%s)\n' %(ifaceobj
.name
, str(e
)))
814 def _down_vrf_dev(self
, ifaceobj
, vrf_table
, ifaceobj_getfunc
=None):
816 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
819 if vrf_table
== 'auto':
820 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
822 running_slaves
= self
.ipcmd
.link_get_lowers(ifaceobj
.name
)
824 for s
in running_slaves
:
826 sobj
= ifaceobj_getfunc(s
)
828 self
._handle
_existing
_connections
(sobj
[0]
832 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
835 self
.ipcmd
.addr_flush(s
)
836 netlink
.link_set_updown(s
, "down")
838 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
842 self
._down
_vrf
_helper
(ifaceobj
, vrf_table
)
844 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
848 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
850 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
853 ifindex
= self
.ipcmd
.link_get_ifindex(ifaceobj
.name
)
856 self
.ipcmd
.link_delete(ifaceobj
.name
)
858 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
861 self
._close
_sockets
(ifaceobj
, ifindex
)
864 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
866 self
.logger
.info('%s: %s' %(ifaceobj
.name
, str(e
)))
870 def _down_vrf_slave(self
, ifacename
, ifaceobj
=None, vrfname
=None):
872 self
._handle
_existing
_connections
(ifaceobj
, vrfname
)
873 netlink
.link_set_nomaster(ifacename
)
874 # Down this slave only if it is a slave ifupdown2 manages.
875 # we dont want to down slaves that maybe up'ed by
876 # somebody else. One such example is a macvlan device
877 # which ifupdown2 addressvirtual addon module auto creates
879 netlink
.link_set_updown(ifacename
, "down")
881 self
.logger
.warn('%s: %s' %(ifacename
, str(e
)))
883 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
885 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
887 self
._iproute
2_vrf
_map
_initialize
()
888 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
, ifaceobj_getfunc
)
890 vrf
= ifaceobj
.get_attr_value_first('vrf')
892 self
._iproute
2_vrf
_map
_initialize
()
893 self
._down
_vrf
_slave
(ifaceobj
.name
, ifaceobj
, None)
895 self
.log_warn(str(e
))
897 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
899 master
= self
.ipcmd
.link_get_master(ifaceobj
.name
)
900 if not master
or master
!= vrf
:
901 ifaceobjcurr
.update_config_with_status('vrf', str(master
), 1)
903 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
905 self
.log_error(str(e
), ifaceobjcurr
)
907 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
909 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
910 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
912 if vrf_table
== 'auto':
913 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
915 config_table
= vrf_table
916 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
918 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
920 running_table
= vrfdev_attrs
.get('table')
921 if not running_table
:
922 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
924 if config_table
!= running_table
:
925 ifaceobjcurr
.update_config_with_status('vrf-table',
928 ifaceobjcurr
.update_config_with_status('vrf-table',
930 if not ifupdownflags
.flags
.WITHDEFAULTS
:
934 utils
.exec_command('%s verify %s %s'
936 ifaceobj
.name
, config_table
))
937 ifaceobjcurr
.update_config_with_status('vrf-helper',
943 ifaceobjcurr
.update_config_with_status('vrf-helper',
950 self
.log_warn(str(e
))
952 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
954 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
956 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
957 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
959 vrf
= ifaceobj
.get_attr_value_first('vrf')
961 self
._iproute
2_vrf
_map
_initialize
(writetodisk
=False)
962 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
964 self
.log_warn(str(e
))
966 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
968 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
970 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobjrunning
.name
)
972 running_table
= vrfdev_attrs
.get('table')
974 ifaceobjrunning
.update_config('vrf-table',
976 elif kind
== 'vrf_slave':
977 vrf
= self
.ipcmd
.link_get_master(ifaceobjrunning
.name
)
979 ifaceobjrunning
.update_config('vrf', vrf
)
981 self
.log_warn(str(e
))
983 def _query(self
, ifaceobj
, **kwargs
):
984 if not self
.vrf_helper
:
986 if (ifaceobj
.link_kind
& ifaceLinkKind
.VRF
):
987 ifaceobj
.update_config('vrf-helper', '%s %s' %(self
.vrf_helper
,
990 _run_ops
= {'pre-up' : _up
,
992 'query-running' : _query_running
,
993 'query-checkcurr' : _query_check
,
997 """ returns list of ops supported by this module """
998 return self
._run
_ops
.keys()
1000 def _init_command_handlers(self
):
1002 self
.ipcmd
= iproute2()
1003 if not self
.bondcmd
:
1004 self
.bondcmd
= bondutil()
1005 if not self
.dhclientcmd
:
1006 self
.dhclientcmd
= dhclient()
1008 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
1009 ifaceobj_getfunc
=None, **extra_args
):
1010 """ run bond configuration on the interface object passed as argument
1013 **ifaceobj** (object): iface object
1015 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1019 **query_ifaceobj** (object): query check ifaceobject. This is only
1020 valid when op is 'query-checkcurr'. It is an object same as
1021 ifaceobj, but contains running attribute values and its config
1022 status. The modules can use it to return queried running state
1023 of interfaces. status is success if the running state is same
1024 as user required state in ifaceobj. error otherwise.
1026 op_handler
= self
._run
_ops
.get(operation
)
1029 self
._init
_command
_handlers
()
1030 if operation
== 'query-checkcurr':
1031 op_handler(self
, ifaceobj
, query_ifaceobj
)
1033 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)