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