]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/vrf.py
addons: address: fix merge-indentation issue
[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 19
421e9573 20 from ifupdown2.ifupdown.iface import ifaceRole, ifaceLinkKind, ifaceLinkPrivFlags, ifaceLinkType
d486dd0d 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 27 from ifupdown2.ifupdownaddons.modulebase import moduleBase
bd441a51 28except (ImportError, ModuleNotFoundError):
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 34
421e9573 35 from ifupdown.iface import ifaceRole, ifaceLinkKind, ifaceLinkPrivFlags, ifaceLinkType
d486dd0d 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()
e36ad206 118 self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
3b01ed76 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()
e36ad206 126 self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
3b01ed76 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 ' +
d0e56768 266 'map (%s)' %errstr)
6f5b74f7
RP
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 ' +
d0e56768 272 'map (%s)' %errstr)
6f5b74f7
RP
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
265bf3d3 351 for t in range(table_id_start, self.vrf_table_id_end + 1):
d486dd0d
JF
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)
d0e56768 436 self.logger.info('%s: table id auto: selected table id %s'
df53966d 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)
3218f49d 468 except Exception:
122ef35b
RP
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 516 if master_exists:
80f2b553
JF
517 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN and not self.check_link_down_on_vlan_lower_dev(
518 ifaceobj, ifaceobj_getfunc
519 ):
223ba5af 520 self.netlink.link_up(ifacename)
79cf5764 521 else:
d2b35716 522 self.log_error('vrf %s not around, skipping vrf config'
bf3eda91 523 %(vrfname), ifaceobj)
3b01ed76 524 except Exception as e:
bf3eda91 525 self.log_error('%s: %s' %(ifacename, str(e)), ifaceobj)
8465de90 526
80f2b553
JF
527 def check_link_down_on_vlan_lower_dev(self, ifaceobj, ifaceobj_getfunc):
528 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
529 for obj in ifaceobj_getfunc(ifaceobj.lowerifaces[0]):
530 if obj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
531 self.logger.info("%s: keeping vlan down (lower device %s has link-down flag set)" % (ifaceobj.name, obj.name))
532 return True
533 return False
534
8465de90
RP
535 def _del_vrf_rules(self, vrf_dev_name, vrf_table):
536 pref = 200
537 ip_rule_out_format = '%s: from all %s %s lookup %s'
d486dd0d 538 ip_rule_cmd = '%s %s rule del pref %s %s %s table %s'
8465de90 539
4ce47ce4 540 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 541 if rule in self.ip_rule_cache:
d486dd0d
JF
542 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
543 '', 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)
8465de90 548 if rule in self.ip_rule_cache:
d486dd0d
JF
549 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
550 '', pref, 'iif', vrf_dev_name,
25e2386e 551 vrf_dev_name)
a193d8d1 552 utils.exec_command(rule_cmd)
8465de90 553
4ce47ce4 554 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 555 if rule in self.ip6_rule_cache:
d486dd0d
JF
556 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
557 '-6', pref, 'oif', vrf_dev_name,
25e2386e 558 vrf_dev_name)
a193d8d1 559 utils.exec_command(rule_cmd)
8465de90 560
4ce47ce4 561 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 562 if rule in self.ip6_rule_cache:
d486dd0d
JF
563 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
564 '-6', pref, 'iif', vrf_dev_name,
25e2386e 565 vrf_dev_name)
a193d8d1 566 utils.exec_command(rule_cmd)
8465de90 567
0aa91758
N
568 def _l3mdev_rule(self, ip_rules):
569 for rule in ip_rules:
570 if not re.search(r"\d.*from\s+all\s+lookup\s+\W?l3mdev-table\W?",
e36ad206 571 rule):
0aa91758
N
572 continue
573 return True
574 return False
575
576 def _rule_cache_fill(self):
d486dd0d
JF
577 ip_rules = utils.exec_command('%s rule show'
578 %utils.ip_cmd).splitlines()
0aa91758
N
579 self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
580 self.l3mdev4_rule = self._l3mdev_rule(self.ip_rule_cache)
d486dd0d
JF
581 ip_rules = utils.exec_command('%s -6 rule show'
582 %utils.ip_cmd).splitlines()
0aa91758
N
583 self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
584 self.l3mdev6_rule = self._l3mdev_rule(self.ip6_rule_cache)
585
8465de90
RP
586 def _add_vrf_rules(self, vrf_dev_name, vrf_table):
587 pref = 200
588 ip_rule_out_format = '%s: from all %s %s lookup %s'
d486dd0d 589 ip_rule_cmd = '%s %s rule add pref %s %s %s table %s'
659097a0
N
590 if self.vrf_fix_local_table:
591 self.vrf_fix_local_table = False
592 rule = '0: from all lookup local'
593 if rule in self.ip_rule_cache:
594 try:
d486dd0d
JF
595 utils.exec_command('%s rule del pref 0'
596 %utils.ip_cmd)
597 utils.exec_command('%s rule add pref 32765 table local'
598 %utils.ip_cmd)
3b01ed76 599 except Exception as e:
a193d8d1 600 self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
659097a0 601 pass
c61672da
N
602 if rule in self.ip6_rule_cache:
603 try:
d486dd0d
JF
604 utils.exec_command('%s -6 rule del pref 0'
605 %utils.ip_cmd)
606 utils.exec_command('%s -6 rule add pref 32765 table local'
607 %utils.ip_cmd)
3b01ed76 608 except Exception as e:
a193d8d1 609 self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
c61672da 610 pass
8465de90 611
0aa91758
N
612 if not self.l3mdev_checked:
613 self._rule_cache_fill()
614 self.l3mdev_checked = True
3fcb15fe
N
615 #Example ip rule
616 #200: from all oif blue lookup blue
617 #200: from all iif blue lookup blue
618
619 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
0aa91758 620 if not self.l3mdev4_rule and rule not in self.ip_rule_cache:
d486dd0d
JF
621 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
622 '', 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.l3mdev4_rule and rule not in self.ip_rule_cache:
d486dd0d
JF
628 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
629 '', pref, 'iif', vrf_dev_name,
25e2386e 630 vrf_dev_name)
a193d8d1 631 utils.exec_command(rule_cmd)
8465de90 632
3fcb15fe 633 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
0aa91758 634 if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
d486dd0d
JF
635 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
636 '-6', pref, 'oif', vrf_dev_name,
25e2386e 637 vrf_dev_name)
a193d8d1 638 utils.exec_command(rule_cmd)
8465de90 639
3fcb15fe 640 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
0aa91758 641 if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
d486dd0d
JF
642 rule_cmd = ip_rule_cmd %(utils.ip_cmd,
643 '-6', pref, 'iif', vrf_dev_name,
25e2386e 644 vrf_dev_name)
a193d8d1 645 utils.exec_command(rule_cmd)
8465de90 646
1b284018
RP
647 def _is_address_virtual_slaves(self, vrfobj, config_vrfslaves,
648 vrfslave):
649 # Address virtual lines on a vrf slave will create
650 # macvlan devices on the vrf slave and enslave them
651 # to the vrf master. This function checks if the
652 # vrf slave is such a macvlan interface.
653 # XXX: additional possible checks that can be done here
654 # are:
655 # - check if it is also a macvlan device of the
d486dd0d 656 # format <vrf_slave>-v<int> created by the
1b284018 657 # address virtual module
223ba5af 658 vrfslave_lowers = self.sysfs.link_get_lowers(vrfslave)
1b284018
RP
659 if vrfslave_lowers:
660 if vrfslave_lowers[0] in config_vrfslaves:
661 return True
662 return False
663
4d2c9798 664 def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None):
223ba5af 665 running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
768b4ec5 666 config_slaves = ifaceobj.lowerifaces
b94e4d24 667 if not config_slaves and not running_slaves:
867e11a2 668 return
4d2c9798
RP
669
670 if not config_slaves: config_slaves = []
671 if not running_slaves: running_slaves = []
768b4ec5
RP
672 add_slaves = set(config_slaves).difference(set(running_slaves))
673 del_slaves = set(running_slaves).difference(set(config_slaves))
674 if add_slaves:
675 for s in add_slaves:
676 try:
223ba5af 677 if not self.cache.link_exists(s):
d2b35716 678 continue
09753350
RP
679 sobj = None
680 if ifaceobj_getfunc:
681 sobj = ifaceobj_getfunc(s)
682 self._up_vrf_slave(s, ifaceobj.name,
683 sobj[0] if sobj else None,
684 ifaceobj_getfunc, True)
3b01ed76 685 except Exception as e:
768b4ec5
RP
686 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
687
688 if del_slaves:
689 for s in del_slaves:
690 try:
1b284018
RP
691 if self._is_address_virtual_slaves(ifaceobj,
692 config_slaves, s):
693 continue
aa36221f 694 sobj = None
4d2c9798
RP
695 if ifaceobj_getfunc:
696 sobj = ifaceobj_getfunc(s)
0ba04b38
RP
697 self._down_vrf_slave(s, sobj[0] if sobj else None,
698 ifaceobj.name)
3b01ed76 699 except Exception as e:
768b4ec5
RP
700 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
701
702 if ifaceobj.link_type == ifaceLinkType.LINK_MASTER:
703 for s in config_slaves:
704 try:
7cdb931e 705 for slave_ifaceobj in ifaceobj_getfunc(s) or []:
80f2b553
JF
706 if slave_ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN or self.check_link_down_on_vlan_lower_dev(
707 slave_ifaceobj, ifaceobj_getfunc
708 ):
e7206159 709 raise Exception("link-down yes: keeping VRF slave down")
223ba5af 710 self.netlink.link_up(s)
3b01ed76 711 except Exception as e:
e7206159 712 self.logger.debug("%s: %s" % (s, str(e)))
768b4ec5 713 pass
8465de90 714
8ad5c767
RP
715 def _set_vrf_dev_processed_flag(self, ifaceobj):
716 ifaceobj.module_flags[self.name] = \
717 ifaceobj.module_flags.setdefault(self.name, 0) | \
718 vrfPrivFlags.PROCESSED
719
720 def _check_vrf_dev_processed_flag(self, ifaceobj):
25e2386e 721 if (ifaceobj.module_flags.get(self.name, 0) & vrfPrivFlags.PROCESSED):
8ad5c767
RP
722 return True
723 return False
8465de90 724
8ad5c767 725 def _create_vrf_dev(self, ifaceobj, vrf_table):
223ba5af 726 if not self.cache.link_exists(ifaceobj.name):
d486dd0d
JF
727 self._check_vrf_system_reserved_names(ifaceobj)
728
c8a3b44e 729 if self.vrf_count == self.vrf_max_count:
9b35cb3e
JF
730 self.log_error('max vrf count %d hit...not '
731 'creating vrf' % self.vrf_count, ifaceobj)
6f2890fc
RP
732 if vrf_table == 'auto':
733 vrf_table = self._get_avail_vrf_table_id()
734 if not vrf_table:
9b35cb3e 735 self.log_error('unable to get an auto table id', ifaceobj)
d0e56768 736 self.logger.info('%s: table id auto: selected table id %s'
6f2890fc 737 %(ifaceobj.name, vrf_table))
25e2386e 738 else:
bf3eda91 739 self._iproute2_is_vrf_tableid_inuse(ifaceobj, vrf_table)
3b01ed76 740 if ifaceobj.name in list(self.system_reserved_rt_tables.keys()):
f6466fcb 741 self.log_error('cannot use system reserved %s table ids'
3b01ed76 742 %(str(list(self.system_reserved_rt_tables.keys()))),
bf3eda91 743 ifaceobj)
d54baa22
RP
744
745 if not vrf_table.isdigit():
9b35cb3e 746 self.log_error('vrf-table must be an integer or \'auto\'', ifaceobj)
d54baa22 747
6f2890fc
RP
748 # XXX: If we decide to not allow vrf id usages out of
749 # the reserved ifupdown range, then uncomment this code.
fd8c6caf
RP
750 else:
751 if (int(vrf_table) < self.vrf_table_id_start or
752 int(vrf_table) > self.vrf_table_id_end):
9b35cb3e
JF
753 self.log_error('vrf table id %s out of reserved range [%d,%d]'
754 %(vrf_table,
fd8c6caf 755 self.vrf_table_id_start,
bf3eda91 756 self.vrf_table_id_end), ifaceobj)
2df6a60f 757 try:
223ba5af 758 self.netlink.link_add_vrf(ifaceobj.name, vrf_table)
3b01ed76 759 except Exception as e:
d0e56768 760 self.log_error('create failed (%s)' % str(e), ifaceobj)
25e2386e 761 if vrf_table != 'auto':
bf3eda91 762 self._iproute2_vrf_table_entry_add(ifaceobj, vrf_table)
2df6a60f 763 else:
4d2c9798
RP
764 if vrf_table == 'auto':
765 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
d486dd0d 766 if not vrf_table and not ifupdownflags.flags.DRYRUN:
9b35cb3e 767 self.log_error('unable to get vrf table id', ifaceobj)
6f2890fc 768
2df6a60f 769 # if the device exists, check if table id is same
223ba5af
JF
770 running_table = self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_VRF_TABLE)
771
772 if running_table is not None and vrf_table != str(running_table):
773 self.log_error('cannot change vrf table id,running table id'
774 ' %s is different from config id %s'
775 % (running_table, vrf_table), ifaceobj)
4d2c9798
RP
776 return vrf_table
777
25e2386e 778 def _up_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
779 mode = ""
780 if ifupdownflags.flags.PERFMODE:
781 mode = "boot"
25e2386e 782 if self.vrf_helper:
a193d8d1
JF
783 utils.exec_command('%s create %s %s %s' %
784 (self.vrf_helper,
785 ifaceobj.name,
786 vrf_table,
787 mode))
25e2386e 788
4d2c9798
RP
789 def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True,
790 ifaceobj_getfunc=None):
8ad5c767
RP
791
792 # if vrf dev is already processed return. This can happen
0ba04b38
RP
793 # if we the slave was configured before.
794 # see self._up_vrf_slave_without_master
8ad5c767
RP
795 if self._check_vrf_dev_processed_flag(ifaceobj):
796 return True
797
25e2386e
RP
798 try:
799 vrf_table = self._create_vrf_dev(ifaceobj, vrf_table)
3b01ed76 800 except Exception as e:
bf3eda91 801 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
d486dd0d 802
8ad5c767 803 try:
8ad5c767 804 self._add_vrf_rules(ifaceobj.name, vrf_table)
6369e774 805 self._up_vrf_helper(ifaceobj, vrf_table)
8ad5c767 806 if add_slaves:
4d2c9798 807 self._add_vrf_slaves(ifaceobj, ifaceobj_getfunc)
8ad5c767 808 self._set_vrf_dev_processed_flag(ifaceobj)
7cdb931e
JF
809
810 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
223ba5af 811 self.netlink.link_up(ifaceobj.name)
3b01ed76 812 except Exception as e:
bf3eda91 813 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
8ad5c767 814
223ba5af 815 def _kill_ssh_connections(self, ifacename, ifaceobj):
5c5a7b93 816 try:
0e936c3f 817 iplist = [str(ip.ip) for ip in self.cache.get_managed_ip_addresses(
223ba5af 818 ifname=ifacename,
0e936c3f 819 ifaceobj_list=[ifaceobj],
223ba5af
JF
820 )]
821
0ba04b38
RP
822 if not iplist:
823 return
824 proc=[]
5c5a7b93 825 #Example output:
d486dd0d 826 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
5c5a7b93 827 #users:(("sshd",pid=2528,fd=3))
d486dd0d 828 cmdl = [utils.ss_cmd, '-t', '-p']
a193d8d1 829 for line in utils.exec_commandl(cmdl).splitlines():
5c5a7b93
N
830 citems = line.split()
831 addr = None
832 if '%' in citems[3]:
833 addr = citems[3].split('%')[0]
834 elif ':ssh' in citems[3]:
835 addr = citems[3].split(':')[0]
836 if not addr:
837 continue
0ba04b38 838 if addr in iplist:
5c5a7b93
N
839 if len(citems) == 6:
840 proc.append(citems[5].split(',')[1].split('=')[1])
841
842 if not proc:
843 return
be276272
N
844 pid = None
845 # outpt of '/usr/bin/pstree -Aps <pid>':
846 # 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
847 # get the above output to following format
848 # ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
d486dd0d
JF
849 pstree = list(reversed(utils.exec_command('%s -Aps %s' %
850 (utils.pstree_cmd, os.getpid())).strip().split('---')))
be276272
N
851 for index, process in enumerate(pstree):
852 # check the parent of SSH process to make sure
853 # we don't kill SSH server or systemd process
854 if 'sshd' in process and 'sshd' in pstree[index + 1]:
3b01ed76 855 pid = [x for x in process if x.isdigit()]
be276272 856 break
aa36221f
RP
857 self.logger.info("%s: killing active ssh sessions: %s"
858 %(ifacename, str(proc)))
cbdde74e
RP
859
860 if ifupdownflags.flags.DRYRUN:
861 return
5c5a7b93
N
862 for id in proc:
863 if id != pid:
864 try:
aa36221f 865 os.kill(int(id), signal.SIGINT)
5c5a7b93
N
866 except OSError as e:
867 continue
0ba04b38
RP
868
869 # Kill current SSH client
5c5a7b93 870 if pid in proc:
32f6e6ca 871 try:
0ba04b38 872 forkret = os.fork()
3b01ed76 873 except OSError as e:
0ba04b38
RP
874 self.logger.info("fork error : %s [%d]" % (e.strerror, e.errno))
875 if (forkret == 0): # The first child.
876 try:
877 os.setsid()
878 self.logger.info("%s: ifreload continuing in the background" %ifacename)
3b01ed76
JF
879 except OSError as xxx_todo_changeme:
880 (err_no, err_message) = xxx_todo_changeme.args
0ba04b38
RP
881 self.logger.info("os.setsid failed: errno=%d: %s" % (err_no, err_message))
882 self.logger.info("pid=%d pgid=%d" % (os.getpid(), os.getpgid(0)))
5c5a7b93 883 try:
aa36221f
RP
884 self.logger.info("%s: killing our session: %s"
885 %(ifacename, str(proc)))
886 os.kill(int(pid), signal.SIGINT)
5c5a7b93
N
887 return
888 except OSError as e:
889 return
3b01ed76 890 except Exception as e:
5c5a7b93
N
891 self.logger.info('%s: %s' %(ifacename, str(e)))
892
8ad5c767 893 def _up(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
894 try:
895 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
896 if vrf_table:
05ac52f0 897 self._iproute2_vrf_map_initialize()
09753350 898 # This is a vrf device
4d2c9798 899 self._up_vrf_dev(ifaceobj, vrf_table, True, ifaceobj_getfunc)
8465de90
RP
900 else:
901 vrf = ifaceobj.get_attr_value_first('vrf')
902 if vrf:
223ba5af
JF
903 if not self.cache.link_exists(ifaceobj.name):
904 self.logger.warning("%s: device not found - please check your configuration" % ifaceobj.name)
905 return
906
05ac52f0 907 self._iproute2_vrf_map_initialize()
09753350 908 # This is a vrf slave
8ad5c767
RP
909 self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
910 ifaceobj_getfunc)
d486dd0d 911 elif not ifupdownflags.flags.PERFMODE:
aa36221f 912 # check if we were a slave before
223ba5af 913 master = self.cache.get_master(ifaceobj.name)
aa36221f 914 if master:
717cee31 915 self._iproute2_vrf_map_initialize()
aa36221f 916 if self._is_vrf_dev(master):
0ba04b38
RP
917 self._down_vrf_slave(ifaceobj.name, ifaceobj,
918 master)
3b01ed76 919 except Exception as e:
bf3eda91 920 self.log_error(str(e), ifaceobj)
8465de90 921
25e2386e 922 def _down_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
923 mode = ""
924 if ifupdownflags.flags.PERFMODE:
925 mode = "boot"
25e2386e 926 if self.vrf_helper:
a193d8d1
JF
927 utils.exec_command('%s delete %s %s %s' %
928 (self.vrf_helper,
929 ifaceobj.name,
930 vrf_table,
931 mode))
25e2386e 932
223ba5af 933 def _close_sockets(self, ifacename):
6fbd7444
RP
934 if not self.vrf_close_socks_on_down:
935 return
936
223ba5af
JF
937 try:
938 ifindex = self.cache.get_ifindex(ifacename)
939 except Exception as e:
5e3ea6fc 940 self.logger.debug("%s: vrf: close sockets error: %s" % (ifacename, str(e)))
223ba5af
JF
941 ifindex = 0
942
943 if not ifindex:
944 return
945
6fbd7444 946 try:
d486dd0d
JF
947 utils.exec_command('%s -aK \"dev == %s\"'
948 %(utils.ss_cmd, ifindex))
3b01ed76 949 except Exception as e:
6fbd7444 950 self.logger.info('%s: closing socks using ss'
d0e56768 951 ' failed (%s)' %(ifacename, str(e)))
6fbd7444
RP
952 pass
953
c4be5481 954 def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
5c5a7b93 955
223ba5af 956 if not self.cache.link_exists(ifaceobj.name):
6fbd7444
RP
957 return
958
8465de90
RP
959 if vrf_table == 'auto':
960 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
aa36221f 961
223ba5af 962 running_slaves = self.sysfs.link_get_lowers(ifaceobj.name)
2365b3c9
RP
963 if running_slaves:
964 for s in running_slaves:
965 if ifaceobj_getfunc:
966 sobj = ifaceobj_getfunc(s)
967 try:
968 self._handle_existing_connections(sobj[0]
969 if sobj else None,
0ba04b38 970 ifaceobj.name)
3b01ed76 971 except Exception as e:
2365b3c9
RP
972 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
973 pass
974 try:
223ba5af
JF
975 self.netlink.addr_flush(s)
976 self.netlink.link_down(s)
3b01ed76 977 except Exception as e:
223ba5af 978 self.logger.info('%s: %s' %(s, str(e)))
2365b3c9 979 pass
768b4ec5 980
40804f1a
RP
981 try:
982 self._down_vrf_helper(ifaceobj, vrf_table)
3b01ed76 983 except Exception as e:
c46af1c9 984 self.logger.warning('%s: %s' %(ifaceobj.name, str(e)))
40804f1a 985 pass
25e2386e 986
768b4ec5 987 try:
f1c92482 988 self._del_vrf_rules(ifaceobj.name, vrf_table)
3b01ed76 989 except Exception as e:
768b4ec5
RP
990 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
991 pass
992
223ba5af 993 self._close_sockets(ifaceobj.name)
6fbd7444 994
223ba5af
JF
995 try:
996 self.netlink.link_del(ifaceobj.name)
3b01ed76 997 except Exception as e:
223ba5af
JF
998 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
999 pass
6fbd7444 1000
f1c92482
RP
1001 try:
1002 self._iproute2_vrf_table_entry_del(vrf_table)
3b01ed76 1003 except Exception as e:
768b4ec5
RP
1004 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
1005 pass
8465de90 1006
f1c92482 1007
0ba04b38 1008 def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
8465de90 1009 try:
0ba04b38 1010 self._handle_existing_connections(ifaceobj, vrfname)
223ba5af 1011 self.netlink.link_set_nomaster(ifacename)
3b01ed76 1012 except Exception as e:
c46af1c9 1013 self.logger.warning('%s: %s' %(ifacename, str(e)))
8465de90 1014
8ad5c767 1015 def _down(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
1016 try:
1017 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
1018 if vrf_table:
05ac52f0 1019 self._iproute2_vrf_map_initialize()
c4be5481 1020 self._down_vrf_dev(ifaceobj, vrf_table, ifaceobj_getfunc)
8465de90
RP
1021 else:
1022 vrf = ifaceobj.get_attr_value_first('vrf')
1023 if vrf:
05ac52f0 1024 self._iproute2_vrf_map_initialize()
0ba04b38 1025 self._down_vrf_slave(ifaceobj.name, ifaceobj, None)
3b01ed76 1026 except Exception as e:
8465de90
RP
1027 self.log_warn(str(e))
1028
1029 def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
1030 try:
223ba5af 1031 master = self.cache.get_master(ifaceobj.name)
8465de90 1032 if not master or master != vrf:
586535e8 1033 ifaceobjcurr.update_config_with_status('vrf', str(master), 1)
8465de90
RP
1034 else:
1035 ifaceobjcurr.update_config_with_status('vrf', master, 0)
3b01ed76 1036 except Exception as e:
bf3eda91 1037 self.log_error(str(e), ifaceobjcurr)
8465de90 1038
6e16e5ae 1039 def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
8465de90 1040 try:
223ba5af 1041 if not self.cache.link_exists(ifaceobj.name):
8465de90
RP
1042 self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
1043 return
1044 if vrf_table == 'auto':
223ba5af 1045 config_table = str(self._get_iproute2_vrf_table(ifaceobj.name) or 0)
8465de90
RP
1046 else:
1047 config_table = vrf_table
223ba5af
JF
1048
1049 running_vrf_table = str(self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_VRF_TABLE))
1050
1051 ifaceobjcurr.update_config_with_status('vrf-table', running_vrf_table, config_table != running_vrf_table)
1052
6e16e5ae 1053 if not ifupdownflags.flags.WITHDEFAULTS:
669b422a
RP
1054 return
1055 if self.vrf_helper:
6e16e5ae 1056 try:
a193d8d1 1057 utils.exec_command('%s verify %s %s'
6e16e5ae
N
1058 %(self.vrf_helper,
1059 ifaceobj.name, config_table))
1060 ifaceobjcurr.update_config_with_status('vrf-helper',
1061 '%s create %s %s'
1062 %(self.vrf_helper,
1063 ifaceobj.name,
1064 config_table), 0)
3b01ed76 1065 except Exception as e:
6e16e5ae
N
1066 ifaceobjcurr.update_config_with_status('vrf-helper',
1067 '%s create %s %s'
1068 %(self.vrf_helper,
1069 ifaceobj.name,
1070 config_table), 1)
1071 pass
3b01ed76 1072 except Exception as e:
8465de90
RP
1073 self.log_warn(str(e))
1074
6e16e5ae 1075 def _query_check(self, ifaceobj, ifaceobjcurr):
8465de90
RP
1076 try:
1077 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
1078 if vrf_table:
eb3ce8c8 1079 self._iproute2_vrf_map_initialize(writetodisk=False)
6e16e5ae 1080 self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table)
8465de90
RP
1081 else:
1082 vrf = ifaceobj.get_attr_value_first('vrf')
1083 if vrf:
eb3ce8c8 1084 self._iproute2_vrf_map_initialize(writetodisk=False)
8465de90 1085 self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf)
3b01ed76 1086 except Exception as e:
8465de90
RP
1087 self.log_warn(str(e))
1088
8ad5c767 1089 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
8465de90 1090 try:
223ba5af 1091 kind = self.cache.get_link_kind(ifaceobjrunning.name)
8465de90 1092 if kind == 'vrf':
223ba5af
JF
1093 running_table = self.cache.get_link_info_data_attribute(ifaceobjrunning.name, Link.IFLA_VRF_TABLE)
1094
1095 if running_table is not None:
1096 ifaceobjrunning.update_config('vrf-table', str(running_table))
1097 return
1098
1099 slave_kind = self.cache.get_link_slave_kind(ifaceobjrunning.name)
5b563460 1100 if slave_kind == 'vrf_slave':
223ba5af 1101 vrf = self.cache.get_master(ifaceobjrunning.name)
8465de90
RP
1102 if vrf:
1103 ifaceobjrunning.update_config('vrf', vrf)
3b01ed76 1104 except Exception as e:
8465de90
RP
1105 self.log_warn(str(e))
1106
baa909c6
N
1107 def _query(self, ifaceobj, **kwargs):
1108 if not self.vrf_helper:
1109 return
1110 if (ifaceobj.link_kind & ifaceLinkKind.VRF):
1111 ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper,
1112 ifaceobj.name))
1113
223ba5af
JF
1114 _run_ops = {
1115 "pre-up": _up,
1116 "post-down": _down,
1117 "query-running": _query_running,
1118 "query-checkcurr": _query_check,
1119 "query": _query
1120 }
8465de90
RP
1121
1122 def get_ops(self):
1123 """ returns list of ops supported by this module """
3b01ed76 1124 return list(self._run_ops.keys())
8465de90
RP
1125
1126 def _init_command_handlers(self):
122ef35b 1127 if not self.dhclientcmd:
fc5e1735 1128 self.dhclientcmd = dhclient()
8465de90 1129
8ad5c767
RP
1130 def run(self, ifaceobj, operation, query_ifaceobj=None,
1131 ifaceobj_getfunc=None, **extra_args):
8465de90
RP
1132 """ run bond configuration on the interface object passed as argument
1133
1134 Args:
1135 **ifaceobj** (object): iface object
1136
1137 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1138 'query-running'
1139
1140 Kwargs:
1141 **query_ifaceobj** (object): query check ifaceobject. This is only
1142 valid when op is 'query-checkcurr'. It is an object same as
1143 ifaceobj, but contains running attribute values and its config
1144 status. The modules can use it to return queried running state
1145 of interfaces. status is success if the running state is same
1146 as user required state in ifaceobj. error otherwise.
1147 """
1148 op_handler = self._run_ops.get(operation)
1149 if not op_handler:
1150 return
1151 self._init_command_handlers()
1152 if operation == 'query-checkcurr':
6e16e5ae 1153 op_handler(self, ifaceobj, query_ifaceobj)
8465de90 1154 else:
8ad5c767 1155 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
223ba5af
JF
1156 if self.at_exit:
1157 self._iproute2_vrf_map_sync_to_disk()
1158 self.at_exit = False