]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/vrf.py
Merge pull request #121 from aderumier/arpaccept
[mirror_ifupdown2.git] / ifupdown2 / addons / vrf.py
CommitLineData
8465de90
RP
1#!/usr/bin/python
2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
8465de90
RP
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
d486dd0d 7import re
8465de90 8import os
a193d8d1 9import fcntl
8465de90 10import atexit
d486dd0d
JF
11import signal
12
79cf5764 13from sets import Set
d486dd0d
JF
14
15try:
16 import ifupdown2.ifupdown.policymanager as policymanager
17 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
d92f630c 18 from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager
d486dd0d
JF
19
20 from ifupdown2.ifupdown.iface import *
21 from ifupdown2.ifupdown.utils import utils
22 from ifupdown2.ifupdown.netlink import netlink
23
24 from ifupdown2.ifupdownaddons.dhclient import dhclient
25 from ifupdown2.ifupdownaddons.utilsbase import *
26 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
27 from ifupdown2.ifupdownaddons.modulebase import moduleBase
28except ImportError:
29 import ifupdown.policymanager as policymanager
30 import ifupdown.ifupdownflags as ifupdownflags
d92f630c 31 from ifupdown.statemanager import statemanager_api as statemanager
d486dd0d
JF
32
33 from ifupdown.iface import *
34 from ifupdown.utils import utils
35 from ifupdown.netlink import netlink
36
37 from ifupdownaddons.dhclient import dhclient
38 from ifupdownaddons.utilsbase import *
39 from ifupdownaddons.LinkUtils import LinkUtils
40 from ifupdownaddons.modulebase import moduleBase
41
8465de90 42
8ad5c767
RP
43class vrfPrivFlags:
44 PROCESSED = 0x1
45
8465de90
RP
46class vrf(moduleBase):
47 """ ifupdown2 addon module to configure vrfs """
48 _modinfo = { 'mhelp' : 'vrf configuration module',
49 'attrs' : {
50 'vrf-table':
fffec8bb
N
51 {'help' : 'vrf device routing table id. key to ' +
52 'creating a vrf device. ' +
53 'Table id is either \'auto\' or '+
54 '\'valid routing table id\'',
2c592263 55 'validvals': ['auto', '<number>'],
fffec8bb 56 'example': ['vrf-table auto', 'vrf-table 1001']},
8465de90
RP
57 'vrf':
58 {'help' : 'vrf the interface is part of.',
482b2fab 59 'validvals': ['<text>'],
8465de90
RP
60 'example': ['vrf blue']}}}
61
a1c23686 62 iproute2_vrf_filename = '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
8465de90
RP
63 iproute2_vrf_filehdr = '# This file is autogenerated by ifupdown2.\n' + \
64 '# It contains the vrf name to table mapping.\n' + \
6f2890fc
RP
65 '# Reserved table range %s %s\n'
66 VRF_TABLE_START = 1001
67 VRF_TABLE_END = 5000
8465de90 68
d486dd0d 69 system_reserved_rt_tables = {'255' : 'local', '254' : 'main',
f6466fcb
RP
70 '253' : 'default', '0' : 'unspec'}
71
8465de90 72 def __init__(self, *args, **kargs):
d486dd0d 73 moduleBase.__init__(self, *args, **kargs)
8465de90
RP
74 self.ipcmd = None
75 self.bondcmd = None
122ef35b 76 self.dhclientcmd = None
8ad5c767 77 self.name = self.__class__.__name__
d9e75535
RP
78 self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname')
79
d486dd0d
JF
80 self.user_reserved_vrf_table = []
81
d9e75535
RP
82 if (ifupdownflags.flags.PERFMODE and
83 not (self.vrf_mgmt_devname and os.path.exists('/sys/class/net/%s'
84 %self.vrf_mgmt_devname))):
85 # if perf mode is set (PERFMODE is set at boot), and this is the first
86 # time we are calling ifup at boot (check for mgmt vrf existance at
87 # boot, make sure this is really the first invocation at boot.
88 # ifup is called with PERFMODE at boot multiple times (once for mgmt vrf
89 # and the second time with all auto interfaces). We want to delete
90 # the map file only the first time. This is to avoid accidently
91 # deleting map file with a valid mgmt vrf entry
122ef35b
RP
92 if os.path.exists(self.iproute2_vrf_filename):
93 try:
94 self.logger.info('vrf: removing file %s'
95 %self.iproute2_vrf_filename)
96 os.remove(self.iproute2_vrf_filename)
97 except Exception, e:
98 self.logger.debug('vrf: removing file failed (%s)'
99 %str(e))
8465de90 100 try:
d486dd0d
JF
101 ip_rules = utils.exec_command('%s rule show'
102 %utils.ip_cmd).splitlines()
8465de90
RP
103 self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
104 except Exception, e:
105 self.ip_rule_cache = []
a193d8d1 106 self.logger.warn('vrf: cache v4: %s' % str(e))
8465de90
RP
107
108 try:
d486dd0d
JF
109 ip_rules = utils.exec_command('%s -6 rule show'
110 %utils.ip_cmd).splitlines()
8465de90
RP
111 self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
112 except Exception, e:
113 self.ip6_rule_cache = []
a193d8d1 114 self.logger.warn('vrf: cache v6: %s' % str(e))
8465de90
RP
115
116 #self.logger.debug("vrf: ip rule cache")
117 #self.logger.info(self.ip_rule_cache)
118
119 #self.logger.info("vrf: ip -6 rule cache")
120 #self.logger.info(self.ip6_rule_cache)
121
0aa91758
N
122 self.l3mdev_checked = False
123 self.l3mdev4_rule = False
124 if self._l3mdev_rule(self.ip_rule_cache):
125 self.l3mdev4_rule = True
126 self.l3mdev_checked = True
127 self.l3mdev6_rule = False
128 if self._l3mdev_rule(self.ip6_rule_cache):
129 self.l3mdev6_rule = True
130 self.l3mdev_checked = True
05ac52f0
RP
131 self._iproute2_vrf_map_initialized = False
132 self.iproute2_vrf_map = {}
133 self.iproute2_vrf_map_fd = None
134 self.iproute2_vrf_map_sync_to_disk = False
135
136 self.vrf_table_id_start = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-start')
137 if not self.vrf_table_id_start:
138 self.vrf_table_id_start = self.VRF_TABLE_START
139 self.vrf_table_id_end = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-end')
140 if not self.vrf_table_id_end:
141 self.vrf_table_id_end = self.VRF_TABLE_END
d486dd0d
JF
142
143 self._modinfo['attrs']['vrf-table']['validrange'] = [
144 str(self.vrf_table_id_start),
145 str(self.vrf_table_id_end)
146 ]
147
05ac52f0
RP
148 self.vrf_max_count = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-max-count')
149
150 self.vrf_fix_local_table = True
151 self.vrf_count = 0
25e2386e 152 self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper')
6fbd7444 153 self.vrf_close_socks_on_down = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-close-socks-on-down')
6f5b74f7
RP
154 self.warn_on_vrf_map_write_err = True
155
d486dd0d
JF
156 def _check_vrf_table_id(self, ifaceobj):
157 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
158 if not vrf_table:
159 return False
160 if (vrf_table != 'auto' and
161 (int(vrf_table) < self.vrf_table_id_start or
162 int(vrf_table) > self.vrf_table_id_end)):
163 self.logger.error('%s: vrf table id %s out of reserved range [%d,%d]'
164 %(ifaceobj.name,
165 vrf_table,
166 self.vrf_table_id_start,
167 self.vrf_table_id_end))
168 return False
169 return True
170
171 def syntax_check(self, ifaceobj, ifaceobj_getfunc):
172 if ifaceobj.link_kind & ifaceLinkKind.VRF:
173 try:
174 check_vrf_table_id = self._check_vrf_table_id(ifaceobj)
175 check_vrf_sys_names = self._check_vrf_system_reserved_names(ifaceobj)
176 return check_vrf_table_id and check_vrf_sys_names
177 except Exception as e:
178 self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
179 return False
180 return True
181
182 def _check_vrf_system_reserved_names(self, ifaceobj):
183 system_reserved_names = self.system_reserved_rt_tables.values()
184 if ifaceobj.name in system_reserved_names:
185 self.log_error('cannot use system reserved %s vrf names'
186 % (str(system_reserved_names)), ifaceobj)
187 return False
188 return True
189
eb3ce8c8 190 def _iproute2_vrf_map_initialize(self, writetodisk=True):
05ac52f0
RP
191 if self._iproute2_vrf_map_initialized:
192 return
193
8465de90
RP
194 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
195 self.iproute2_vrf_map = {}
05ac52f0 196 iproute2_vrf_map_force_rewrite = False
8465de90
RP
197 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
198 if os.path.exists(self.iproute2_vrf_filename):
a193d8d1
JF
199 with open(self.iproute2_vrf_filename, 'r+') as vrf_map_fd:
200 lines = vrf_map_fd.readlines()
201 for l in lines:
202 l = l.strip()
203 if l[0] == '#':
05ac52f0 204 continue
a193d8d1
JF
205 try:
206 (table, vrf_name) = l.strip().split()
207 if self.iproute2_vrf_map.get(int(table)):
208 # looks like the existing file has
209 # duplicate entries, force rewrite of the
210 # file
211 iproute2_vrf_map_force_rewrite = True
212 continue
213 self.iproute2_vrf_map[int(table)] = vrf_name
214 except Exception, e:
42e85fc8 215 self.logger.info('vrf: iproute2_vrf_map: unable to parse %s (%s)' %(l, str(e)))
a193d8d1 216 pass
8465de90 217
05ac52f0
RP
218 vrfs = self.ipcmd.link_get_vrfs()
219 running_vrf_map = {}
220 if vrfs:
221 for v, lattrs in vrfs.iteritems():
222 table = lattrs.get('table', None)
223 if table:
224 running_vrf_map[int(table)] = v
225
4934af35 226 if (not running_vrf_map or (running_vrf_map != self.iproute2_vrf_map)):
05ac52f0
RP
227 self.iproute2_vrf_map = running_vrf_map
228 iproute2_vrf_map_force_rewrite = True
229
230 self.iproute2_vrf_map_fd = None
eb3ce8c8
RP
231 if writetodisk:
232 if iproute2_vrf_map_force_rewrite:
233 # reopen the file and rewrite the map
234 self._iproute2_vrf_map_open(True, False)
235 else:
236 self._iproute2_vrf_map_open(False, True)
8465de90 237
05ac52f0
RP
238 self.iproute2_vrf_map_sync_to_disk = False
239 atexit.register(self._iproute2_vrf_map_sync_to_disk)
240
241 self.logger.info("vrf: dumping iproute2_vrf_map")
242 self.logger.info(self.iproute2_vrf_map)
6f2890fc
RP
243
244 last_used_vrf_table = None
245 for t in range(self.vrf_table_id_start,
246 self.vrf_table_id_end):
8465de90
RP
247 if not self.iproute2_vrf_map.get(t):
248 break
6f2890fc 249 last_used_vrf_table = t
8465de90 250 self.last_used_vrf_table = last_used_vrf_table
05ac52f0 251 self._iproute2_vrf_map_initialized = True
c8a3b44e 252 self.vrf_count = len(self.iproute2_vrf_map)
09753350 253
6f5b74f7
RP
254 def _iproute2_map_warn(self, errstr):
255 if self.warn_on_vrf_map_write_err:
256 if not os.path.exists('/etc/iproute2/rt_tables.d/'):
257 self.logger.info('unable to save iproute2 vrf to table ' +
258 'map (%s)\n' %errstr)
259 self.logger.info('cannot find /etc/iproute2/rt_tables.d.' +
260 ' pls check if your iproute2 version' +
261 ' supports rt_tables.d')
262 else:
263 self.logger.warn('unable to open iproute2 vrf to table ' +
264 'map (%s)\n' %errstr)
265 self.warn_on_vrf_map_write_err = False
266
05ac52f0 267 def _iproute2_vrf_map_sync_to_disk(self):
eb3ce8c8
RP
268 if (ifupdownflags.flags.DRYRUN or
269 not self.iproute2_vrf_map_sync_to_disk):
8465de90 270 return
05ac52f0 271 self.logger.info('vrf: syncing table map to %s'
8465de90 272 %self.iproute2_vrf_filename)
6f5b74f7
RP
273 try:
274 with open(self.iproute2_vrf_filename, 'w') as f:
275 f.write(self.iproute2_vrf_filehdr %(self.vrf_table_id_start,
276 self.vrf_table_id_end))
277 for t, v in self.iproute2_vrf_map.iteritems():
278 f.write('%s %s\n' %(t, v))
279 f.flush()
280 except Exception, e:
281 self._iproute2_map_warn(str(e))
282 pass
05ac52f0
RP
283
284 def _iproute2_vrf_map_open(self, sync_vrfs=False, append=False):
285 self.logger.info('vrf: syncing table map to %s'
286 %self.iproute2_vrf_filename)
eb3ce8c8
RP
287 if ifupdownflags.flags.DRYRUN:
288 return
05ac52f0
RP
289 fmode = 'a+' if append else 'w'
290 try:
291 self.iproute2_vrf_map_fd = open(self.iproute2_vrf_filename,
292 '%s' %fmode)
a193d8d1 293 fcntl.fcntl(self.iproute2_vrf_map_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
05ac52f0 294 except Exception, e:
6f5b74f7 295 self._iproute2_map_warn(str(e))
05ac52f0
RP
296 return
297
298 if not append:
299 # write file header
300 self.iproute2_vrf_map_fd.write(self.iproute2_vrf_filehdr
301 %(self.vrf_table_id_start,
302 self.vrf_table_id_end))
303 for t, v in self.iproute2_vrf_map.iteritems():
304 self.iproute2_vrf_map_fd.write('%s %s\n' %(t, v))
305 self.iproute2_vrf_map_fd.flush()
8465de90
RP
306
307 def _is_vrf(self, ifaceobj):
308 if ifaceobj.get_attr_value_first('vrf-table'):
309 return True
310 return False
311
768b4ec5 312 def get_upper_ifacenames(self, ifaceobj, ifacenames_all=None):
8465de90
RP
313 """ Returns list of interfaces dependent on ifaceobj """
314
768b4ec5
RP
315 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
316 if vrf_table:
317 ifaceobj.link_type = ifaceLinkType.LINK_MASTER
318 ifaceobj.link_kind |= ifaceLinkKind.VRF
f7551dcb 319 ifaceobj.role |= ifaceRole.MASTER
d486dd0d
JF
320
321 if vrf_table != 'auto':
322 # if the user didn't specify auto we need to store the desired
323 # vrf tables ids, in case the configuration has both auto and
324 # hardcoded vrf-table ids. We need to create them all without
325 # collisions.
326 self.user_reserved_vrf_table.append(int(vrf_table))
327
8465de90
RP
328 vrf_iface_name = ifaceobj.get_attr_value_first('vrf')
329 if not vrf_iface_name:
330 return None
768b4ec5 331 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
858a230f 332 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
8ad5c767 333
8465de90
RP
334 return [vrf_iface_name]
335
768b4ec5 336 def get_upper_ifacenames_running(self, ifaceobj):
8465de90
RP
337 return None
338
339 def _get_iproute2_vrf_table(self, vrf_dev_name):
340 for t, v in self.iproute2_vrf_map.iteritems():
341 if v == vrf_dev_name:
09753350 342 return str(t)
8465de90
RP
343 return None
344
345 def _get_avail_vrf_table_id(self):
6f2890fc
RP
346 if self.last_used_vrf_table == None:
347 table_id_start = self.vrf_table_id_start
348 else:
349 table_id_start = self.last_used_vrf_table + 1
d486dd0d
JF
350 for t in range(table_id_start, self.vrf_table_id_end):
351 if (not self.iproute2_vrf_map.get(t)
352 and t not in self.user_reserved_vrf_table):
8465de90 353 self.last_used_vrf_table = t
6f2890fc 354 return str(t)
8465de90
RP
355 return None
356
bf3eda91 357 def _iproute2_is_vrf_tableid_inuse(self, vrfifaceobj, table_id):
25e2386e 358 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
bf3eda91 359 if old_vrf_name and old_vrf_name != vrfifaceobj.name:
25e2386e 360 self.log_error('table id %s already assigned to vrf dev %s'
bf3eda91 361 %(table_id, old_vrf_name), vrfifaceobj)
25e2386e 362
bf3eda91 363 def _iproute2_vrf_table_entry_add(self, vrfifaceobj, table_id):
05ac52f0 364 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
25e2386e 365 if not old_vrf_name:
bf3eda91 366 self.iproute2_vrf_map[int(table_id)] = vrfifaceobj.name
05ac52f0
RP
367 if self.iproute2_vrf_map_fd:
368 self.iproute2_vrf_map_fd.write('%s %s\n'
bf3eda91 369 %(table_id, vrfifaceobj.name))
05ac52f0 370 self.iproute2_vrf_map_fd.flush()
c8a3b44e 371 self.vrf_count += 1
25e2386e 372 return
bf3eda91 373 if old_vrf_name != vrfifaceobj.name:
25e2386e
RP
374 self.log_error('table id %d already assigned to vrf dev %s'
375 %(table_id, old_vrf_name))
8465de90
RP
376
377 def _iproute2_vrf_table_entry_del(self, table_id):
378 try:
05ac52f0
RP
379 # with any del of vrf map, we need to force sync to disk
380 self.iproute2_vrf_map_sync_to_disk = True
09753350 381 del self.iproute2_vrf_map[int(table_id)]
8465de90 382 except Exception, e:
04e4f352 383 self.logger.info('vrf: iproute2 vrf map del failed for %s (%s)'
8465de90
RP
384 %(table_id, str(e)))
385 pass
386
aa36221f
RP
387 def _is_vrf_dev(self, ifacename):
388 # Look at iproute2 map for now.
389 # If it was a master we knew about,
390 # it is definately there
391 if ifacename in self.iproute2_vrf_map.values():
392 return True
393 return False
394
122ef35b
RP
395 def _is_dhcp_slave(self, ifaceobj):
396 if (not ifaceobj.addr_method or
397 (ifaceobj.addr_method != 'dhcp' and
398 ifaceobj.addr_method != 'dhcp6')):
399 return False
400 return True
401
d486dd0d 402 def _up_vrf_slave_without_master(self, ifacename, vrfname, ifaceobj, vrf_master_objs, ifaceobj_getfunc=None):
8ad5c767
RP
403 """ If we have a vrf slave that has dhcp configured, bring up the
404 vrf master now. This is needed because vrf has special handling
405 in dhclient hook which requires the vrf master to be present """
d486dd0d
JF
406 vrf_master = None
407 if len(ifaceobj.upperifaces) > 1 and ifaceobj_getfunc:
408 for upper_iface in ifaceobj.upperifaces:
409 upper_ifaceobjs = ifaceobj_getfunc(upper_iface)
410
411 if upper_ifaceobjs:
412 for upper_obj in upper_ifaceobjs:
413 if upper_obj.link_kind & ifaceLinkKind.VRF:
414 vrf_master = upper_obj.name
415 break
416 elif ifaceobj.upperifaces:
417 vrf_master = ifaceobj.upperifaces[0]
8ad5c767
RP
418 if not vrf_master:
419 self.logger.warn('%s: vrf master not found' %ifacename)
420 return
421 if os.path.exists('/sys/class/net/%s' %vrf_master):
422 self.logger.info('%s: vrf master %s exists returning'
423 %(ifacename, vrf_master))
424 return
8ad5c767
RP
425 self.logger.info('%s: bringing up vrf master %s'
426 %(ifacename, vrf_master))
427 for mobj in vrf_master_objs:
428 vrf_table = mobj.get_attr_value_first('vrf-table')
429 if vrf_table:
df53966d
RP
430 if vrf_table == 'auto':
431 vrf_table = self._get_avail_vrf_table_id()
432 if not vrf_table:
433 self.log_error('%s: unable to get an auto table id'
bf3eda91 434 %mobj.name, ifaceobj)
df53966d
RP
435 self.logger.info('%s: table id auto: selected table id %s\n'
436 %(mobj.name, vrf_table))
25e2386e
RP
437 try:
438 self._up_vrf_dev(mobj, vrf_table, False)
439 except Exception:
440 raise
df53966d 441 break
0ba04b38 442 self._handle_existing_connections(ifaceobj, vrfname)
97fc046b 443 self.enable_ipv6_if_prev_brport(ifacename)
d486dd0d 444 self.ipcmd.link_set(ifacename, 'master', vrfname)
8ad5c767
RP
445 return
446
97fc046b 447 def enable_ipv6_if_prev_brport(self, ifname):
d92f630c 448 """
97fc046b 449 If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
d92f630c
JF
450 """
451 try:
97fc046b
JF
452 if os.path.exists("/sys/class/net/%s/brport" % ifname):
453 self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
d92f630c
JF
454 except Exception, e:
455 self.logger.info(str(e))
456
717cee31 457 def _down_dhcp_slave(self, ifaceobj, vrfname):
122ef35b 458 try:
717cee31 459 dhclient_cmd_prefix = None
6369e774
RP
460 if (vrfname and self.vrf_exec_cmd_prefix and
461 self.ipcmd.link_exists(vrfname)):
717cee31
RP
462 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix,
463 vrfname)
464 self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
122ef35b
RP
465 except:
466 # ignore any dhclient release errors
467 pass
468
0ba04b38 469 def _handle_existing_connections(self, ifaceobj, vrfname):
fc5e1735 470 if not ifaceobj or ifupdownflags.flags.PERFMODE:
0ba04b38
RP
471 return
472 if (self.vrf_mgmt_devname and
473 self.vrf_mgmt_devname == vrfname):
474 self._kill_ssh_connections(ifaceobj.name)
475 if self._is_dhcp_slave(ifaceobj):
717cee31 476 self._down_dhcp_slave(ifaceobj, vrfname)
0ba04b38 477
8ad5c767 478 def _up_vrf_slave(self, ifacename, vrfname, ifaceobj=None,
09753350 479 ifaceobj_getfunc=None, vrf_exists=False):
8465de90 480 try:
d2b35716 481 master_exists = True
09753350 482 if vrf_exists or self.ipcmd.link_exists(vrfname):
42e85fc8
RP
483 uppers = self.ipcmd.link_get_uppers(ifacename)
484 if not uppers or vrfname not in uppers:
0ba04b38 485 self._handle_existing_connections(ifaceobj, vrfname)
97fc046b 486 self.enable_ipv6_if_prev_brport(ifacename)
d486dd0d 487 self.ipcmd.link_set(ifacename, 'master', vrfname)
79cf5764
RP
488 elif ifaceobj:
489 vrf_master_objs = ifaceobj_getfunc(vrfname)
490 if not vrf_master_objs:
80be09ba
RP
491 # this is the case where vrf is assigned to an interface
492 # but user has not provided a vrf interface.
493 # people expect you to warn them but go ahead with the
494 # rest of the config on that interface
495 netlink.link_set_updown(ifacename, "up")
496 self.log_error('vrf master ifaceobj %s not found'
497 %vrfname)
79cf5764
RP
498 return
499 if (ifupdownflags.flags.ALL or
1ce8b5bb 500 ifupdownflags.flags.WITH_DEPENDS or
79cf5764
RP
501 (ifupdownflags.flags.CLASS and
502 ifaceobj.classes and vrf_master_objs[0].classes and
503 Set(ifaceobj.classes).intersection(vrf_master_objs[0].classes))):
504 self._up_vrf_slave_without_master(ifacename, vrfname,
505 ifaceobj,
d486dd0d
JF
506 vrf_master_objs,
507 ifaceobj_getfunc)
79cf5764
RP
508 else:
509 master_exists = False
d2b35716
RP
510 else:
511 master_exists = False
f944abda
JF
512 if master_exists:
513 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
514 netlink.link_set_updown(ifacename, "up")
79cf5764 515 else:
d2b35716 516 self.log_error('vrf %s not around, skipping vrf config'
bf3eda91 517 %(vrfname), ifaceobj)
8465de90 518 except Exception, e:
bf3eda91 519 self.log_error('%s: %s' %(ifacename, str(e)), ifaceobj)
8465de90
RP
520
521 def _del_vrf_rules(self, vrf_dev_name, vrf_table):
522 pref = 200
523 ip_rule_out_format = '%s: from all %s %s lookup %s'
d486dd0d 524 ip_rule_cmd = '%s %s rule del pref %s %s %s table %s'
8465de90 525
4ce47ce4 526 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 527 if rule in self.ip_rule_cache:
d486dd0d
JF
528 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
529 '', pref, 'oif', vrf_dev_name,
25e2386e 530 vrf_dev_name)
a193d8d1 531 utils.exec_command(rule_cmd)
8465de90 532
4ce47ce4 533 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
8465de90 534 if rule in self.ip_rule_cache:
d486dd0d
JF
535 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
536 '', pref, 'iif', vrf_dev_name,
25e2386e 537 vrf_dev_name)
a193d8d1 538 utils.exec_command(rule_cmd)
8465de90 539
4ce47ce4 540 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 541 if rule in self.ip6_rule_cache:
d486dd0d
JF
542 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
543 '-6', pref, 'oif', vrf_dev_name,
25e2386e 544 vrf_dev_name)
a193d8d1 545 utils.exec_command(rule_cmd)
8465de90 546
4ce47ce4 547 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 548 if rule in self.ip6_rule_cache:
d486dd0d
JF
549 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
550 '-6', pref, 'iif', vrf_dev_name,
25e2386e 551 vrf_dev_name)
a193d8d1 552 utils.exec_command(rule_cmd)
8465de90 553
0aa91758
N
554 def _l3mdev_rule(self, ip_rules):
555 for rule in ip_rules:
556 if not re.search(r"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
557 rule):
558 continue
559 return True
560 return False
561
562 def _rule_cache_fill(self):
d486dd0d
JF
563 ip_rules = utils.exec_command('%s rule show'
564 %utils.ip_cmd).splitlines()
0aa91758
N
565 self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
566 self.l3mdev4_rule = self._l3mdev_rule(self.ip_rule_cache)
d486dd0d
JF
567 ip_rules = utils.exec_command('%s -6 rule show'
568 %utils.ip_cmd).splitlines()
0aa91758
N
569 self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
570 self.l3mdev6_rule = self._l3mdev_rule(self.ip6_rule_cache)
571
8465de90
RP
572 def _add_vrf_rules(self, vrf_dev_name, vrf_table):
573 pref = 200
574 ip_rule_out_format = '%s: from all %s %s lookup %s'
d486dd0d 575 ip_rule_cmd = '%s %s rule add pref %s %s %s table %s'
659097a0
N
576 if self.vrf_fix_local_table:
577 self.vrf_fix_local_table = False
578 rule = '0: from all lookup local'
579 if rule in self.ip_rule_cache:
580 try:
d486dd0d
JF
581 utils.exec_command('%s rule del pref 0'
582 %utils.ip_cmd)
583 utils.exec_command('%s rule add pref 32765 table local'
584 %utils.ip_cmd)
659097a0 585 except Exception, e:
a193d8d1 586 self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
659097a0 587 pass
c61672da
N
588 if rule in self.ip6_rule_cache:
589 try:
d486dd0d
JF
590 utils.exec_command('%s -6 rule del pref 0'
591 %utils.ip_cmd)
592 utils.exec_command('%s -6 rule add pref 32765 table local'
593 %utils.ip_cmd)
c61672da 594 except Exception, e:
a193d8d1 595 self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
c61672da 596 pass
8465de90 597
0aa91758
N
598 if not self.l3mdev_checked:
599 self._rule_cache_fill()
600 self.l3mdev_checked = True
3fcb15fe
N
601 #Example ip rule
602 #200: from all oif blue lookup blue
603 #200: from all iif blue lookup blue
604
605 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
0aa91758 606 if not self.l3mdev4_rule and rule not in self.ip_rule_cache:
d486dd0d
JF
607 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
608 '', pref, 'oif', vrf_dev_name,
25e2386e 609 vrf_dev_name)
a193d8d1 610 utils.exec_command(rule_cmd)
8465de90 611
3fcb15fe 612 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
0aa91758 613 if not self.l3mdev4_rule and rule not in self.ip_rule_cache:
d486dd0d
JF
614 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
615 '', pref, 'iif', vrf_dev_name,
25e2386e 616 vrf_dev_name)
a193d8d1 617 utils.exec_command(rule_cmd)
8465de90 618
3fcb15fe 619 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
0aa91758 620 if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
d486dd0d
JF
621 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
622 '-6', pref, 'oif', vrf_dev_name,
25e2386e 623 vrf_dev_name)
a193d8d1 624 utils.exec_command(rule_cmd)
8465de90 625
3fcb15fe 626 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
0aa91758 627 if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
d486dd0d
JF
628 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
629 '-6', pref, 'iif', vrf_dev_name,
25e2386e 630 vrf_dev_name)
a193d8d1 631 utils.exec_command(rule_cmd)
8465de90 632
1b284018
RP
633 def _is_address_virtual_slaves(self, vrfobj, config_vrfslaves,
634 vrfslave):
635 # Address virtual lines on a vrf slave will create
636 # macvlan devices on the vrf slave and enslave them
637 # to the vrf master. This function checks if the
638 # vrf slave is such a macvlan interface.
639 # XXX: additional possible checks that can be done here
640 # are:
641 # - check if it is also a macvlan device of the
d486dd0d 642 # format <vrf_slave>-v<int> created by the
1b284018
RP
643 # address virtual module
644 vrfslave_lowers = self.ipcmd.link_get_lowers(vrfslave)
645 if vrfslave_lowers:
646 if vrfslave_lowers[0] in config_vrfslaves:
647 return True
648 return False
649
4d2c9798 650 def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None):
768b4ec5
RP
651 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
652 config_slaves = ifaceobj.lowerifaces
b94e4d24 653 if not config_slaves and not running_slaves:
867e11a2 654 return
4d2c9798
RP
655
656 if not config_slaves: config_slaves = []
657 if not running_slaves: running_slaves = []
768b4ec5
RP
658 add_slaves = set(config_slaves).difference(set(running_slaves))
659 del_slaves = set(running_slaves).difference(set(config_slaves))
660 if add_slaves:
661 for s in add_slaves:
662 try:
d2b35716
RP
663 if not self.ipcmd.link_exists(s):
664 continue
09753350
RP
665 sobj = None
666 if ifaceobj_getfunc:
667 sobj = ifaceobj_getfunc(s)
668 self._up_vrf_slave(s, ifaceobj.name,
669 sobj[0] if sobj else None,
670 ifaceobj_getfunc, True)
768b4ec5
RP
671 except Exception, e:
672 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
673
674 if del_slaves:
675 for s in del_slaves:
676 try:
1b284018
RP
677 if self._is_address_virtual_slaves(ifaceobj,
678 config_slaves, s):
679 continue
aa36221f 680 sobj = None
4d2c9798
RP
681 if ifaceobj_getfunc:
682 sobj = ifaceobj_getfunc(s)
0ba04b38
RP
683 self._down_vrf_slave(s, sobj[0] if sobj else None,
684 ifaceobj.name)
768b4ec5
RP
685 except Exception, e:
686 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
687
688 if ifaceobj.link_type == ifaceLinkType.LINK_MASTER:
689 for s in config_slaves:
690 try:
7cdb931e 691 for slave_ifaceobj in ifaceobj_getfunc(s) or []:
e7206159
JF
692 if slave_ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
693 raise Exception("link-down yes: keeping VRF slave down")
2864d6f3 694 netlink.link_set_updown(s, "up")
768b4ec5 695 except Exception, e:
e7206159 696 self.logger.debug("%s: %s" % (s, str(e)))
768b4ec5 697 pass
8465de90 698
8ad5c767
RP
699 def _set_vrf_dev_processed_flag(self, ifaceobj):
700 ifaceobj.module_flags[self.name] = \
701 ifaceobj.module_flags.setdefault(self.name, 0) | \
702 vrfPrivFlags.PROCESSED
703
704 def _check_vrf_dev_processed_flag(self, ifaceobj):
25e2386e 705 if (ifaceobj.module_flags.get(self.name, 0) & vrfPrivFlags.PROCESSED):
8ad5c767
RP
706 return True
707 return False
8465de90 708
8ad5c767 709 def _create_vrf_dev(self, ifaceobj, vrf_table):
2df6a60f 710 if not self.ipcmd.link_exists(ifaceobj.name):
d486dd0d
JF
711 self._check_vrf_system_reserved_names(ifaceobj)
712
c8a3b44e 713 if self.vrf_count == self.vrf_max_count:
9b35cb3e
JF
714 self.log_error('max vrf count %d hit...not '
715 'creating vrf' % self.vrf_count, ifaceobj)
6f2890fc
RP
716 if vrf_table == 'auto':
717 vrf_table = self._get_avail_vrf_table_id()
718 if not vrf_table:
9b35cb3e 719 self.log_error('unable to get an auto table id', ifaceobj)
6f2890fc
RP
720 self.logger.info('%s: table id auto: selected table id %s\n'
721 %(ifaceobj.name, vrf_table))
25e2386e 722 else:
bf3eda91 723 self._iproute2_is_vrf_tableid_inuse(ifaceobj, vrf_table)
f6466fcb
RP
724 if ifaceobj.name in self.system_reserved_rt_tables.keys():
725 self.log_error('cannot use system reserved %s table ids'
bf3eda91
RP
726 %(str(self.system_reserved_rt_tables.keys())),
727 ifaceobj)
d54baa22
RP
728
729 if not vrf_table.isdigit():
9b35cb3e 730 self.log_error('vrf-table must be an integer or \'auto\'', ifaceobj)
d54baa22 731
6f2890fc
RP
732 # XXX: If we decide to not allow vrf id usages out of
733 # the reserved ifupdown range, then uncomment this code.
fd8c6caf
RP
734 else:
735 if (int(vrf_table) < self.vrf_table_id_start or
736 int(vrf_table) > self.vrf_table_id_end):
9b35cb3e
JF
737 self.log_error('vrf table id %s out of reserved range [%d,%d]'
738 %(vrf_table,
fd8c6caf 739 self.vrf_table_id_start,
bf3eda91 740 self.vrf_table_id_end), ifaceobj)
2df6a60f 741 try:
8465de90
RP
742 self.ipcmd.link_create(ifaceobj.name, 'vrf',
743 {'table' : '%s' %vrf_table})
2df6a60f 744 except Exception, e:
9b35cb3e 745 self.log_error('create failed (%s)\n' % str(e), ifaceobj)
25e2386e 746 if vrf_table != 'auto':
bf3eda91 747 self._iproute2_vrf_table_entry_add(ifaceobj, vrf_table)
2df6a60f 748 else:
4d2c9798
RP
749 if vrf_table == 'auto':
750 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
d486dd0d 751 if not vrf_table and not ifupdownflags.flags.DRYRUN:
9b35cb3e 752 self.log_error('unable to get vrf table id', ifaceobj)
6f2890fc 753
2df6a60f
RP
754 # if the device exists, check if table id is same
755 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
756 if vrfdev_attrs:
757 running_table = vrfdev_attrs.get('table', None)
758 if vrf_table != running_table:
9b35cb3e
JF
759 self.log_error('cannot change vrf table id,running table id'
760 ' %s is different from config id %s'
761 % (running_table, vrf_table), ifaceobj)
4d2c9798
RP
762 return vrf_table
763
25e2386e 764 def _up_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
765 mode = ""
766 if ifupdownflags.flags.PERFMODE:
767 mode = "boot"
25e2386e 768 if self.vrf_helper:
a193d8d1
JF
769 utils.exec_command('%s create %s %s %s' %
770 (self.vrf_helper,
771 ifaceobj.name,
772 vrf_table,
773 mode))
25e2386e 774
4d2c9798
RP
775 def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True,
776 ifaceobj_getfunc=None):
8ad5c767
RP
777
778 # if vrf dev is already processed return. This can happen
0ba04b38
RP
779 # if we the slave was configured before.
780 # see self._up_vrf_slave_without_master
8ad5c767
RP
781 if self._check_vrf_dev_processed_flag(ifaceobj):
782 return True
783
25e2386e
RP
784 try:
785 vrf_table = self._create_vrf_dev(ifaceobj, vrf_table)
786 except Exception, e:
bf3eda91 787 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
d486dd0d 788
8ad5c767 789 try:
8ad5c767 790 self._add_vrf_rules(ifaceobj.name, vrf_table)
6369e774 791 self._up_vrf_helper(ifaceobj, vrf_table)
8ad5c767 792 if add_slaves:
4d2c9798 793 self._add_vrf_slaves(ifaceobj, ifaceobj_getfunc)
8ad5c767 794 self._set_vrf_dev_processed_flag(ifaceobj)
7cdb931e
JF
795
796 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
797 netlink.link_set_updown(ifaceobj.name, "up")
8ad5c767 798 except Exception, e:
bf3eda91 799 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
8ad5c767 800
0ba04b38 801 def _kill_ssh_connections(self, ifacename):
5c5a7b93 802 try:
d486dd0d 803 runningaddrsdict = self.ipcmd.get_running_addrs(None, ifacename)
0ba04b38 804 if not runningaddrsdict:
5c5a7b93 805 return
0ba04b38
RP
806 iplist = [i.split('/', 1)[0] for i in runningaddrsdict.keys()]
807 if not iplist:
808 return
809 proc=[]
5c5a7b93 810 #Example output:
d486dd0d 811 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
5c5a7b93 812 #users:(("sshd",pid=2528,fd=3))
d486dd0d 813 cmdl = [utils.ss_cmd, '-t', '-p']
a193d8d1 814 for line in utils.exec_commandl(cmdl).splitlines():
5c5a7b93
N
815 citems = line.split()
816 addr = None
817 if '%' in citems[3]:
818 addr = citems[3].split('%')[0]
819 elif ':ssh' in citems[3]:
820 addr = citems[3].split(':')[0]
821 if not addr:
822 continue
0ba04b38 823 if addr in iplist:
5c5a7b93
N
824 if len(citems) == 6:
825 proc.append(citems[5].split(',')[1].split('=')[1])
826
827 if not proc:
828 return
be276272
N
829 pid = None
830 # outpt of '/usr/bin/pstree -Aps <pid>':
831 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
832 # get the above output to following format
833 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
d486dd0d
JF
834 pstree = list(reversed(utils.exec_command('%s -Aps %s' %
835 (utils.pstree_cmd, os.getpid())).strip().split('---')))
be276272
N
836 for index, process in enumerate(pstree):
837 # check the parent of SSH process to make sure
838 # we don't kill SSH server or systemd process
839 if 'sshd' in process and 'sshd' in pstree[index + 1]:
840 pid = filter(lambda x: x.isdigit(), process)
841 break
aa36221f
RP
842 self.logger.info("%s: killing active ssh sessions: %s"
843 %(ifacename, str(proc)))
cbdde74e
RP
844
845 if ifupdownflags.flags.DRYRUN:
846 return
5c5a7b93
N
847 for id in proc:
848 if id != pid:
849 try:
aa36221f 850 os.kill(int(id), signal.SIGINT)
5c5a7b93
N
851 except OSError as e:
852 continue
0ba04b38
RP
853
854 # Kill current SSH client
5c5a7b93 855 if pid in proc:
32f6e6ca 856 try:
0ba04b38
RP
857 forkret = os.fork()
858 except OSError, e:
859 self.logger.info("fork error : %s [%d]" % (e.strerror, e.errno))
860 if (forkret == 0): # The first child.
861 try:
862 os.setsid()
863 self.logger.info("%s: ifreload continuing in the background" %ifacename)
864 except OSError, (err_no, err_message):
865 self.logger.info("os.setsid failed: errno=%d: %s" % (err_no, err_message))
866 self.logger.info("pid=%d pgid=%d" % (os.getpid(), os.getpgid(0)))
5c5a7b93 867 try:
aa36221f
RP
868 self.logger.info("%s: killing our session: %s"
869 %(ifacename, str(proc)))
870 os.kill(int(pid), signal.SIGINT)
5c5a7b93
N
871 return
872 except OSError as e:
873 return
874 except Exception, e:
875 self.logger.info('%s: %s' %(ifacename, str(e)))
876
8ad5c767 877 def _up(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
878 try:
879 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
880 if vrf_table:
05ac52f0 881 self._iproute2_vrf_map_initialize()
09753350 882 # This is a vrf device
4d2c9798 883 self._up_vrf_dev(ifaceobj, vrf_table, True, ifaceobj_getfunc)
8465de90
RP
884 else:
885 vrf = ifaceobj.get_attr_value_first('vrf')
886 if vrf:
05ac52f0 887 self._iproute2_vrf_map_initialize()
09753350 888 # This is a vrf slave
8ad5c767
RP
889 self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
890 ifaceobj_getfunc)
d486dd0d 891 elif not ifupdownflags.flags.PERFMODE:
aa36221f
RP
892 # check if we were a slave before
893 master = self.ipcmd.link_get_master(ifaceobj.name)
894 if master:
717cee31 895 self._iproute2_vrf_map_initialize()
aa36221f 896 if self._is_vrf_dev(master):
0ba04b38
RP
897 self._down_vrf_slave(ifaceobj.name, ifaceobj,
898 master)
8465de90 899 except Exception, e:
bf3eda91 900 self.log_error(str(e), ifaceobj)
8465de90 901
25e2386e 902 def _down_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
903 mode = ""
904 if ifupdownflags.flags.PERFMODE:
905 mode = "boot"
25e2386e 906 if self.vrf_helper:
a193d8d1
JF
907 utils.exec_command('%s delete %s %s %s' %
908 (self.vrf_helper,
909 ifaceobj.name,
910 vrf_table,
911 mode))
25e2386e 912
6fbd7444
RP
913 def _close_sockets(self, ifaceobj, ifindex):
914 if not self.vrf_close_socks_on_down:
915 return
916
917 try:
d486dd0d
JF
918 utils.exec_command('%s -aK \"dev == %s\"'
919 %(utils.ss_cmd, ifindex))
6fbd7444
RP
920 except Exception, e:
921 self.logger.info('%s: closing socks using ss'
922 ' failed (%s)\n' %(ifaceobj.name, str(e)))
923 pass
924
c4be5481 925 def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
5c5a7b93 926
6fbd7444
RP
927 if not self.ipcmd.link_exists(ifaceobj.name):
928 return
929
8465de90
RP
930 if vrf_table == 'auto':
931 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
aa36221f 932
2365b3c9
RP
933 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
934 if running_slaves:
935 for s in running_slaves:
936 if ifaceobj_getfunc:
937 sobj = ifaceobj_getfunc(s)
938 try:
939 self._handle_existing_connections(sobj[0]
940 if sobj else None,
0ba04b38 941 ifaceobj.name)
2365b3c9
RP
942 except Exception, e:
943 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
944 pass
945 try:
946 self.ipcmd.addr_flush(s)
2864d6f3 947 netlink.link_set_updown(s, "down")
2365b3c9
RP
948 except Exception, e:
949 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
950 pass
768b4ec5 951
40804f1a
RP
952 try:
953 self._down_vrf_helper(ifaceobj, vrf_table)
954 except Exception, e:
955 self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
956 pass
25e2386e 957
768b4ec5 958 try:
f1c92482 959 self._del_vrf_rules(ifaceobj.name, vrf_table)
768b4ec5
RP
960 except Exception, e:
961 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
962 pass
963
6fbd7444
RP
964 ifindex = self.ipcmd.link_get_ifindex(ifaceobj.name)
965
d486dd0d
JF
966 if ifindex:
967 try:
968 self.ipcmd.link_delete(ifaceobj.name)
969 except Exception, e:
970 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
971 pass
f1c92482 972
6fbd7444
RP
973 self._close_sockets(ifaceobj, ifindex)
974
f1c92482
RP
975 try:
976 self._iproute2_vrf_table_entry_del(vrf_table)
8465de90 977 except Exception, e:
768b4ec5
RP
978 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
979 pass
8465de90 980
f1c92482 981
0ba04b38 982 def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
8465de90 983 try:
0ba04b38 984 self._handle_existing_connections(ifaceobj, vrfname)
d486dd0d 985 self.ipcmd.link_set(ifacename, 'nomaster')
dc3f4c45
RP
986 # Down this slave only if it is a slave ifupdown2 manages.
987 # we dont want to down slaves that maybe up'ed by
988 # somebody else. One such example is a macvlan device
989 # which ifupdown2 addressvirtual addon module auto creates
990 if ifaceobj:
991 netlink.link_set_updown(ifacename, "down")
8465de90 992 except Exception, e:
768b4ec5 993 self.logger.warn('%s: %s' %(ifacename, str(e)))
8465de90 994
8ad5c767 995 def _down(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
996 try:
997 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
998 if vrf_table:
05ac52f0 999 self._iproute2_vrf_map_initialize()
c4be5481 1000 self._down_vrf_dev(ifaceobj, vrf_table, ifaceobj_getfunc)
8465de90
RP
1001 else:
1002 vrf = ifaceobj.get_attr_value_first('vrf')
1003 if vrf:
05ac52f0 1004 self._iproute2_vrf_map_initialize()
0ba04b38 1005 self._down_vrf_slave(ifaceobj.name, ifaceobj, None)
8465de90
RP
1006 except Exception, e:
1007 self.log_warn(str(e))
1008
1009 def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
1010 try:
54616d3f 1011 master = self.ipcmd.link_get_master(ifaceobj.name)
8465de90 1012 if not master or master != vrf:
586535e8 1013 ifaceobjcurr.update_config_with_status('vrf', str(master), 1)
8465de90
RP
1014 else:
1015 ifaceobjcurr.update_config_with_status('vrf', master, 0)
1016 except Exception, e:
bf3eda91 1017 self.log_error(str(e), ifaceobjcurr)
8465de90 1018
6e16e5ae 1019 def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
8465de90
RP
1020 try:
1021 if not self.ipcmd.link_exists(ifaceobj.name):
1022 self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
1023 return
1024 if vrf_table == 'auto':
1025 config_table = self._get_iproute2_vrf_table(ifaceobj.name)
1026 else:
1027 config_table = vrf_table
1028 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
1029 if not vrfdev_attrs:
1030 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
1031 return
1032 running_table = vrfdev_attrs.get('table')
1033 if not running_table:
1034 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
1035 return
1036 if config_table != running_table:
1037 ifaceobjcurr.update_config_with_status('vrf-table',
1038 running_table, 1)
1039 else:
1040 ifaceobjcurr.update_config_with_status('vrf-table',
1041 running_table, 0)
6e16e5ae 1042 if not ifupdownflags.flags.WITHDEFAULTS:
669b422a
RP
1043 return
1044 if self.vrf_helper:
6e16e5ae 1045 try:
a193d8d1 1046 utils.exec_command('%s verify %s %s'
6e16e5ae
N
1047 %(self.vrf_helper,
1048 ifaceobj.name, config_table))
1049 ifaceobjcurr.update_config_with_status('vrf-helper',
1050 '%s create %s %s'
1051 %(self.vrf_helper,
1052 ifaceobj.name,
1053 config_table), 0)
1054 except Exception, e:
1055 ifaceobjcurr.update_config_with_status('vrf-helper',
1056 '%s create %s %s'
1057 %(self.vrf_helper,
1058 ifaceobj.name,
1059 config_table), 1)
1060 pass
8465de90
RP
1061 except Exception, e:
1062 self.log_warn(str(e))
1063
6e16e5ae 1064 def _query_check(self, ifaceobj, ifaceobjcurr):
8465de90
RP
1065 try:
1066 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
1067 if vrf_table:
eb3ce8c8 1068 self._iproute2_vrf_map_initialize(writetodisk=False)
6e16e5ae 1069 self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table)
8465de90
RP
1070 else:
1071 vrf = ifaceobj.get_attr_value_first('vrf')
1072 if vrf:
eb3ce8c8 1073 self._iproute2_vrf_map_initialize(writetodisk=False)
8465de90
RP
1074 self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf)
1075 except Exception, e:
1076 self.log_warn(str(e))
1077
8ad5c767 1078 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
8465de90
RP
1079 try:
1080 kind = self.ipcmd.link_get_kind(ifaceobjrunning.name)
1081 if kind == 'vrf':
54616d3f 1082 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobjrunning.name)
8465de90
RP
1083 if vrfdev_attrs:
1084 running_table = vrfdev_attrs.get('table')
1085 if running_table:
1086 ifaceobjrunning.update_config('vrf-table',
1087 running_table)
5b563460
JF
1088 return
1089 slave_kind = self.ipcmd.link_get_slave_kind(ifaceobjrunning.name)
1090 if slave_kind == 'vrf_slave':
54616d3f 1091 vrf = self.ipcmd.link_get_master(ifaceobjrunning.name)
8465de90
RP
1092 if vrf:
1093 ifaceobjrunning.update_config('vrf', vrf)
1094 except Exception, e:
1095 self.log_warn(str(e))
1096
baa909c6
N
1097 def _query(self, ifaceobj, **kwargs):
1098 if not self.vrf_helper:
1099 return
1100 if (ifaceobj.link_kind & ifaceLinkKind.VRF):
1101 ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper,
1102 ifaceobj.name))
1103
8465de90
RP
1104 _run_ops = {'pre-up' : _up,
1105 'post-down' : _down,
1106 'query-running' : _query_running,
baa909c6
N
1107 'query-checkcurr' : _query_check,
1108 'query' : _query}
8465de90
RP
1109
1110 def get_ops(self):
1111 """ returns list of ops supported by this module """
1112 return self._run_ops.keys()
1113
1114 def _init_command_handlers(self):
8465de90 1115 if not self.ipcmd:
d486dd0d 1116 self.ipcmd = self.bondcmd = LinkUtils()
122ef35b 1117 if not self.dhclientcmd:
fc5e1735 1118 self.dhclientcmd = dhclient()
8465de90 1119
8ad5c767
RP
1120 def run(self, ifaceobj, operation, query_ifaceobj=None,
1121 ifaceobj_getfunc=None, **extra_args):
8465de90
RP
1122 """ run bond configuration on the interface object passed as argument
1123
1124 Args:
1125 **ifaceobj** (object): iface object
1126
1127 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1128 'query-running'
1129
1130 Kwargs:
1131 **query_ifaceobj** (object): query check ifaceobject. This is only
1132 valid when op is 'query-checkcurr'. It is an object same as
1133 ifaceobj, but contains running attribute values and its config
1134 status. The modules can use it to return queried running state
1135 of interfaces. status is success if the running state is same
1136 as user required state in ifaceobj. error otherwise.
1137 """
1138 op_handler = self._run_ops.get(operation)
1139 if not op_handler:
1140 return
1141 self._init_command_handlers()
1142 if operation == 'query-checkcurr':
6e16e5ae 1143 op_handler(self, ifaceobj, query_ifaceobj)
8465de90 1144 else:
8ad5c767 1145 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)