]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/vrf.py
addons: bridge: Deprecating attribute bridge-gcint
[mirror_ifupdown2.git] / addons / vrf.py
CommitLineData
8465de90
RP
1#!/usr/bin/python
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
7import os
5c5a7b93 8import signal
32f6e6ca 9import errno
5c5a7b93 10import subprocess
8465de90
RP
11import atexit
12from ifupdown.iface import *
54616d3f 13import ifupdown.policymanager as policymanager
8465de90 14import ifupdownaddons
768b4ec5 15import ifupdown.rtnetlink_api as rtnetlink_api
fc5e1735 16import ifupdown.ifupdownflags as ifupdownflags
8465de90
RP
17from ifupdownaddons.modulebase import moduleBase
18from ifupdownaddons.bondutil import bondutil
19from ifupdownaddons.iproute2 import iproute2
122ef35b 20from ifupdownaddons.dhclient import dhclient
8465de90 21
8ad5c767
RP
22class vrfPrivFlags:
23 PROCESSED = 0x1
24
8465de90
RP
25class vrf(moduleBase):
26 """ ifupdown2 addon module to configure vrfs """
27 _modinfo = { 'mhelp' : 'vrf configuration module',
28 'attrs' : {
29 'vrf-table':
30 {'help' : 'vrf device table id. key to ' +
31 'creating a vrf device',
32 'example': ['vrf-table-id 1']},
33 'vrf':
34 {'help' : 'vrf the interface is part of.',
35 'example': ['vrf blue']}}}
36
a1c23686 37 iproute2_vrf_filename = '/etc/iproute2/rt_tables.d/ifupdown2_vrf_map.conf'
8465de90
RP
38 iproute2_vrf_filehdr = '# This file is autogenerated by ifupdown2.\n' + \
39 '# It contains the vrf name to table mapping.\n' + \
6f2890fc
RP
40 '# Reserved table range %s %s\n'
41 VRF_TABLE_START = 1001
42 VRF_TABLE_END = 5000
8465de90 43
f6466fcb
RP
44 system_reserved_rt_tables = {'255' : 'local', '254' : 'main',
45 '253' : 'default', '0' : 'unspec'}
46
8465de90
RP
47 def __init__(self, *args, **kargs):
48 ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
49 self.ipcmd = None
50 self.bondcmd = None
122ef35b 51 self.dhclientcmd = None
8ad5c767 52 self.name = self.__class__.__name__
fc5e1735 53 if ifupdownflags.flags.PERFMODE:
122ef35b
RP
54 # if perf mode is set, remove vrf map file.
55 # start afresh. PERFMODE is set at boot
56 if os.path.exists(self.iproute2_vrf_filename):
57 try:
58 self.logger.info('vrf: removing file %s'
59 %self.iproute2_vrf_filename)
60 os.remove(self.iproute2_vrf_filename)
61 except Exception, e:
62 self.logger.debug('vrf: removing file failed (%s)'
63 %str(e))
8465de90
RP
64 try:
65 ip_rules = self.exec_command('/sbin/ip rule show').splitlines()
66 self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
67 except Exception, e:
68 self.ip_rule_cache = []
69 self.logger.warn('%s' %str(e))
70
71 try:
72 ip_rules = self.exec_command('/sbin/ip -6 rule show').splitlines()
73 self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
74 except Exception, e:
75 self.ip6_rule_cache = []
76 self.logger.warn('%s' %str(e))
77
78 #self.logger.debug("vrf: ip rule cache")
79 #self.logger.info(self.ip_rule_cache)
80
81 #self.logger.info("vrf: ip -6 rule cache")
82 #self.logger.info(self.ip6_rule_cache)
83
05ac52f0
RP
84 self._iproute2_vrf_map_initialized = False
85 self.iproute2_vrf_map = {}
86 self.iproute2_vrf_map_fd = None
87 self.iproute2_vrf_map_sync_to_disk = False
88
89 self.vrf_table_id_start = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-start')
90 if not self.vrf_table_id_start:
91 self.vrf_table_id_start = self.VRF_TABLE_START
92 self.vrf_table_id_end = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-end')
93 if not self.vrf_table_id_end:
94 self.vrf_table_id_end = self.VRF_TABLE_END
95 self.vrf_max_count = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-max-count')
96
97 self.vrf_fix_local_table = True
98 self.vrf_count = 0
05ac52f0 99 self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname')
25e2386e 100 self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper')
05ac52f0 101
eb3ce8c8 102 def _iproute2_vrf_map_initialize(self, writetodisk=True):
05ac52f0
RP
103 if self._iproute2_vrf_map_initialized:
104 return
105
8465de90
RP
106 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
107 self.iproute2_vrf_map = {}
05ac52f0 108 iproute2_vrf_map_force_rewrite = False
8465de90
RP
109 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
110 if os.path.exists(self.iproute2_vrf_filename):
05ac52f0
RP
111 vrf_map_fd = open(self.iproute2_vrf_filename, 'r+')
112 lines = vrf_map_fd.readlines()
8465de90
RP
113 for l in lines:
114 l = l.strip()
115 if l[0] == '#':
116 continue
117 try:
118 (table, vrf_name) = l.strip().split()
05ac52f0
RP
119 if self.iproute2_vrf_map.get(int(table)):
120 # looks like the existing file has
121 # duplicate entries, force rewrite of the
122 # file
123 iproute2_vrf_map_force_rewrite = True
124 continue
125 self.iproute2_vrf_map[int(table)] = vrf_name
8465de90
RP
126 except Exception, e:
127 self.logger.info('vrf: iproute2_vrf_map: unable to parse %s'
128 %l)
129 pass
8465de90 130
05ac52f0
RP
131 vrfs = self.ipcmd.link_get_vrfs()
132 running_vrf_map = {}
133 if vrfs:
134 for v, lattrs in vrfs.iteritems():
135 table = lattrs.get('table', None)
136 if table:
137 running_vrf_map[int(table)] = v
138
4934af35 139 if (not running_vrf_map or (running_vrf_map != self.iproute2_vrf_map)):
05ac52f0
RP
140 self.iproute2_vrf_map = running_vrf_map
141 iproute2_vrf_map_force_rewrite = True
142
143 self.iproute2_vrf_map_fd = None
eb3ce8c8
RP
144 if writetodisk:
145 if iproute2_vrf_map_force_rewrite:
146 # reopen the file and rewrite the map
147 self._iproute2_vrf_map_open(True, False)
148 else:
149 self._iproute2_vrf_map_open(False, True)
8465de90 150
05ac52f0
RP
151 self.iproute2_vrf_map_sync_to_disk = False
152 atexit.register(self._iproute2_vrf_map_sync_to_disk)
153
154 self.logger.info("vrf: dumping iproute2_vrf_map")
155 self.logger.info(self.iproute2_vrf_map)
6f2890fc
RP
156
157 last_used_vrf_table = None
158 for t in range(self.vrf_table_id_start,
159 self.vrf_table_id_end):
8465de90
RP
160 if not self.iproute2_vrf_map.get(t):
161 break
6f2890fc 162 last_used_vrf_table = t
8465de90 163 self.last_used_vrf_table = last_used_vrf_table
05ac52f0 164 self._iproute2_vrf_map_initialized = True
c8a3b44e 165 self.vrf_count = len(self.iproute2_vrf_map)
09753350 166
05ac52f0 167 def _iproute2_vrf_map_sync_to_disk(self):
eb3ce8c8
RP
168 if (ifupdownflags.flags.DRYRUN or
169 not self.iproute2_vrf_map_sync_to_disk):
8465de90 170 return
05ac52f0 171 self.logger.info('vrf: syncing table map to %s'
8465de90
RP
172 %self.iproute2_vrf_filename)
173 with open(self.iproute2_vrf_filename, 'w') as f:
6f2890fc
RP
174 f.write(self.iproute2_vrf_filehdr %(self.vrf_table_id_start,
175 self.vrf_table_id_end))
8465de90
RP
176 for t, v in self.iproute2_vrf_map.iteritems():
177 f.write('%s %s\n' %(t, v))
05ac52f0
RP
178 f.flush()
179
180 def _iproute2_vrf_map_open(self, sync_vrfs=False, append=False):
181 self.logger.info('vrf: syncing table map to %s'
182 %self.iproute2_vrf_filename)
eb3ce8c8
RP
183 if ifupdownflags.flags.DRYRUN:
184 return
05ac52f0
RP
185 fmode = 'a+' if append else 'w'
186 try:
187 self.iproute2_vrf_map_fd = open(self.iproute2_vrf_filename,
188 '%s' %fmode)
189 except Exception, e:
190 self.log_warn('vrf: error opening %s (%s)'
191 %(self.iproute2_vrf_filename, str(e)))
192 return
193
194 if not append:
195 # write file header
196 self.iproute2_vrf_map_fd.write(self.iproute2_vrf_filehdr
197 %(self.vrf_table_id_start,
198 self.vrf_table_id_end))
199 for t, v in self.iproute2_vrf_map.iteritems():
200 self.iproute2_vrf_map_fd.write('%s %s\n' %(t, v))
201 self.iproute2_vrf_map_fd.flush()
8465de90
RP
202
203 def _is_vrf(self, ifaceobj):
204 if ifaceobj.get_attr_value_first('vrf-table'):
205 return True
206 return False
207
768b4ec5 208 def get_upper_ifacenames(self, ifaceobj, ifacenames_all=None):
8465de90
RP
209 """ Returns list of interfaces dependent on ifaceobj """
210
768b4ec5
RP
211 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
212 if vrf_table:
213 ifaceobj.link_type = ifaceLinkType.LINK_MASTER
214 ifaceobj.link_kind |= ifaceLinkKind.VRF
f7551dcb 215 ifaceobj.role |= ifaceRole.MASTER
8465de90
RP
216 vrf_iface_name = ifaceobj.get_attr_value_first('vrf')
217 if not vrf_iface_name:
218 return None
768b4ec5 219 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
858a230f 220 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
8ad5c767 221
8465de90
RP
222 return [vrf_iface_name]
223
768b4ec5 224 def get_upper_ifacenames_running(self, ifaceobj):
8465de90
RP
225 return None
226
227 def _get_iproute2_vrf_table(self, vrf_dev_name):
228 for t, v in self.iproute2_vrf_map.iteritems():
229 if v == vrf_dev_name:
09753350 230 return str(t)
8465de90
RP
231 return None
232
233 def _get_avail_vrf_table_id(self):
6f2890fc
RP
234 if self.last_used_vrf_table == None:
235 table_id_start = self.vrf_table_id_start
236 else:
237 table_id_start = self.last_used_vrf_table + 1
238 for t in range(table_id_start,
239 self.vrf_table_id_end):
8465de90
RP
240 if not self.iproute2_vrf_map.get(t):
241 self.last_used_vrf_table = t
6f2890fc 242 return str(t)
8465de90
RP
243 return None
244
25e2386e
RP
245 def _iproute2_is_vrf_tableid_inuse(self, vrf_dev_name, table_id):
246 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
247 if old_vrf_name and old_vrf_name != vrf_dev_name:
248 self.log_error('table id %s already assigned to vrf dev %s'
249 %(table_id, old_vrf_name))
250
8465de90 251 def _iproute2_vrf_table_entry_add(self, vrf_dev_name, table_id):
05ac52f0 252 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
25e2386e 253 if not old_vrf_name:
05ac52f0
RP
254 self.iproute2_vrf_map[int(table_id)] = vrf_dev_name
255 if self.iproute2_vrf_map_fd:
256 self.iproute2_vrf_map_fd.write('%s %s\n'
257 %(table_id, vrf_dev_name))
258 self.iproute2_vrf_map_fd.flush()
c8a3b44e 259 self.vrf_count += 1
25e2386e
RP
260 return
261
262 if old_vrf_name != vrf_dev_name:
263 self.log_error('table id %d already assigned to vrf dev %s'
264 %(table_id, old_vrf_name))
8465de90
RP
265
266 def _iproute2_vrf_table_entry_del(self, table_id):
267 try:
05ac52f0
RP
268 # with any del of vrf map, we need to force sync to disk
269 self.iproute2_vrf_map_sync_to_disk = True
09753350 270 del self.iproute2_vrf_map[int(table_id)]
8465de90
RP
271 except Exception, e:
272 self.logger.info('vrf: iproute2 vrf map del failed for %d (%s)'
273 %(table_id, str(e)))
274 pass
275
aa36221f
RP
276 def _is_vrf_dev(self, ifacename):
277 # Look at iproute2 map for now.
278 # If it was a master we knew about,
279 # it is definately there
280 if ifacename in self.iproute2_vrf_map.values():
281 return True
282 return False
283
122ef35b
RP
284 def _is_dhcp_slave(self, ifaceobj):
285 if (not ifaceobj.addr_method or
286 (ifaceobj.addr_method != 'dhcp' and
287 ifaceobj.addr_method != 'dhcp6')):
288 return False
289 return True
290
0ba04b38
RP
291 def _up_vrf_slave_without_master(self, ifacename, vrfname, ifaceobj,
292 ifaceobj_getfunc):
8ad5c767
RP
293 """ If we have a vrf slave that has dhcp configured, bring up the
294 vrf master now. This is needed because vrf has special handling
295 in dhclient hook which requires the vrf master to be present """
0ba04b38 296
8ad5c767
RP
297 vrf_master = ifaceobj.upperifaces[0]
298 if not vrf_master:
299 self.logger.warn('%s: vrf master not found' %ifacename)
300 return
301 if os.path.exists('/sys/class/net/%s' %vrf_master):
302 self.logger.info('%s: vrf master %s exists returning'
303 %(ifacename, vrf_master))
304 return
305 vrf_master_objs = ifaceobj_getfunc(vrf_master)
306 if not vrf_master_objs:
307 self.logger.warn('%s: vrf master ifaceobj not found' %ifacename)
308 return
309 self.logger.info('%s: bringing up vrf master %s'
310 %(ifacename, vrf_master))
311 for mobj in vrf_master_objs:
312 vrf_table = mobj.get_attr_value_first('vrf-table')
313 if vrf_table:
df53966d
RP
314 if vrf_table == 'auto':
315 vrf_table = self._get_avail_vrf_table_id()
316 if not vrf_table:
317 self.log_error('%s: unable to get an auto table id'
318 %mobj.name)
319 self.logger.info('%s: table id auto: selected table id %s\n'
320 %(mobj.name, vrf_table))
25e2386e
RP
321 try:
322 self._up_vrf_dev(mobj, vrf_table, False)
323 except Exception:
324 raise
df53966d 325 break
0ba04b38 326 self._handle_existing_connections(ifaceobj, vrfname)
8ad5c767
RP
327 self.ipcmd.link_set(ifacename, 'master', vrfname)
328 return
329
717cee31 330 def _down_dhcp_slave(self, ifaceobj, vrfname):
122ef35b 331 try:
717cee31 332 dhclient_cmd_prefix = None
6369e774
RP
333 if (vrfname and self.vrf_exec_cmd_prefix and
334 self.ipcmd.link_exists(vrfname)):
717cee31
RP
335 dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix,
336 vrfname)
337 self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix)
122ef35b
RP
338 except:
339 # ignore any dhclient release errors
340 pass
341
0ba04b38 342 def _handle_existing_connections(self, ifaceobj, vrfname):
fc5e1735 343 if not ifaceobj or ifupdownflags.flags.PERFMODE:
0ba04b38
RP
344 return
345 if (self.vrf_mgmt_devname and
346 self.vrf_mgmt_devname == vrfname):
347 self._kill_ssh_connections(ifaceobj.name)
348 if self._is_dhcp_slave(ifaceobj):
717cee31 349 self._down_dhcp_slave(ifaceobj, vrfname)
0ba04b38 350
8ad5c767 351 def _up_vrf_slave(self, ifacename, vrfname, ifaceobj=None,
09753350 352 ifaceobj_getfunc=None, vrf_exists=False):
8465de90 353 try:
09753350
RP
354 if vrf_exists or self.ipcmd.link_exists(vrfname):
355 upper = self.ipcmd.link_get_upper(ifacename)
4d2c9798 356 if not upper or upper != vrfname:
0ba04b38 357 self._handle_existing_connections(ifaceobj, vrfname)
122ef35b 358 self.ipcmd.link_set(ifacename, 'master', vrfname)
8ad5c767 359 elif ifaceobj:
0ba04b38
RP
360 self._up_vrf_slave_without_master(ifacename, vrfname, ifaceobj,
361 ifaceobj_getfunc)
362 rtnetlink_api.rtnl_api.link_set(ifacename, "up")
8465de90 363 except Exception, e:
d54baa22 364 self.log_error('%s: %s' %(ifacename, str(e)))
8465de90
RP
365
366 def _del_vrf_rules(self, vrf_dev_name, vrf_table):
367 pref = 200
368 ip_rule_out_format = '%s: from all %s %s lookup %s'
369 ip_rule_cmd = 'ip %s rule del pref %s %s %s table %s'
370
4ce47ce4 371 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 372 if rule in self.ip_rule_cache:
25e2386e
RP
373 rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
374 vrf_dev_name)
8465de90
RP
375 self.exec_command(rule_cmd)
376
4ce47ce4 377 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
8465de90 378 if rule in self.ip_rule_cache:
25e2386e
RP
379 rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
380 vrf_dev_name)
8465de90
RP
381 self.exec_command(rule_cmd)
382
4ce47ce4 383 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 384 if rule in self.ip6_rule_cache:
8465de90 385 rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
25e2386e 386 vrf_dev_name)
8465de90
RP
387 self.exec_command(rule_cmd)
388
4ce47ce4 389 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 390 if rule in self.ip6_rule_cache:
8465de90 391 rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
25e2386e 392 vrf_dev_name)
8465de90
RP
393 self.exec_command(rule_cmd)
394
395 def _add_vrf_rules(self, vrf_dev_name, vrf_table):
396 pref = 200
397 ip_rule_out_format = '%s: from all %s %s lookup %s'
398 ip_rule_cmd = 'ip %s rule add pref %s %s %s table %s'
659097a0
N
399 if self.vrf_fix_local_table:
400 self.vrf_fix_local_table = False
401 rule = '0: from all lookup local'
402 if rule in self.ip_rule_cache:
403 try:
3fcb15fe
N
404 self.exec_command('ip rule del pref 0')
405 self.exec_command('ip rule add pref 32765 table local')
659097a0
N
406 except Exception, e:
407 self.logger.info('%s' %str(e))
408 pass
c61672da
N
409 if rule in self.ip6_rule_cache:
410 try:
411 self.exec_command('ip -6 rule del pref 0')
412 self.exec_command('ip -6 rule add pref 32765 table local')
413 except Exception, e:
414 self.logger.info('%s' %str(e))
415 pass
8465de90 416
3fcb15fe
N
417 #Example ip rule
418 #200: from all oif blue lookup blue
419 #200: from all iif blue lookup blue
420
421 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 422 if rule not in self.ip_rule_cache:
25e2386e
RP
423 rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
424 vrf_dev_name)
8465de90
RP
425 self.exec_command(rule_cmd)
426
3fcb15fe 427 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
8465de90 428 if rule not in self.ip_rule_cache:
25e2386e
RP
429 rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
430 vrf_dev_name)
8465de90
RP
431 self.exec_command(rule_cmd)
432
3fcb15fe 433 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 434 if rule not in self.ip6_rule_cache:
25e2386e
RP
435 rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
436 vrf_dev_name)
8465de90
RP
437 self.exec_command(rule_cmd)
438
3fcb15fe 439 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 440 if rule not in self.ip6_rule_cache:
8465de90 441 rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
25e2386e 442 vrf_dev_name)
8465de90
RP
443 self.exec_command(rule_cmd)
444
4d2c9798 445 def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None):
768b4ec5
RP
446 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
447 config_slaves = ifaceobj.lowerifaces
b94e4d24 448 if not config_slaves and not running_slaves:
867e11a2 449 return
4d2c9798
RP
450
451 if not config_slaves: config_slaves = []
452 if not running_slaves: running_slaves = []
768b4ec5
RP
453 add_slaves = set(config_slaves).difference(set(running_slaves))
454 del_slaves = set(running_slaves).difference(set(config_slaves))
455 if add_slaves:
456 for s in add_slaves:
457 try:
09753350
RP
458 sobj = None
459 if ifaceobj_getfunc:
460 sobj = ifaceobj_getfunc(s)
461 self._up_vrf_slave(s, ifaceobj.name,
462 sobj[0] if sobj else None,
463 ifaceobj_getfunc, True)
768b4ec5
RP
464 except Exception, e:
465 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
466
467 if del_slaves:
468 for s in del_slaves:
469 try:
aa36221f 470 sobj = None
4d2c9798
RP
471 if ifaceobj_getfunc:
472 sobj = ifaceobj_getfunc(s)
0ba04b38
RP
473 self._down_vrf_slave(s, sobj[0] if sobj else None,
474 ifaceobj.name)
768b4ec5
RP
475 except Exception, e:
476 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
477
478 if ifaceobj.link_type == ifaceLinkType.LINK_MASTER:
479 for s in config_slaves:
480 try:
481 rtnetlink_api.rtnl_api.link_set(s, "up")
482 except Exception, e:
483 self.logger.debug('%s: %s: link set up (%s)'
484 %(ifaceobj.name, s, str(e)))
485 pass
8465de90 486
8ad5c767
RP
487 def _set_vrf_dev_processed_flag(self, ifaceobj):
488 ifaceobj.module_flags[self.name] = \
489 ifaceobj.module_flags.setdefault(self.name, 0) | \
490 vrfPrivFlags.PROCESSED
491
492 def _check_vrf_dev_processed_flag(self, ifaceobj):
25e2386e 493 if (ifaceobj.module_flags.get(self.name, 0) & vrfPrivFlags.PROCESSED):
8ad5c767
RP
494 return True
495 return False
8465de90 496
8ad5c767 497 def _create_vrf_dev(self, ifaceobj, vrf_table):
2df6a60f 498 if not self.ipcmd.link_exists(ifaceobj.name):
f6466fcb
RP
499 if ifaceobj.name in self.system_reserved_rt_tables.values():
500 self.log_error('cannot use system reserved %s vrf names'
501 %( str(self.system_reserved_rt_tables.values())))
c8a3b44e
RP
502 if self.vrf_count == self.vrf_max_count:
503 self.log_error('%s: max vrf count %d hit...not '
504 'creating vrf' %(ifaceobj.name,
505 self.vrf_count))
6f2890fc
RP
506 if vrf_table == 'auto':
507 vrf_table = self._get_avail_vrf_table_id()
508 if not vrf_table:
509 self.log_error('%s: unable to get an auto table id'
510 %ifaceobj.name)
511 self.logger.info('%s: table id auto: selected table id %s\n'
512 %(ifaceobj.name, vrf_table))
25e2386e
RP
513 else:
514 self._iproute2_is_vrf_tableid_inuse(ifaceobj.name, vrf_table)
f6466fcb
RP
515 if ifaceobj.name in self.system_reserved_rt_tables.keys():
516 self.log_error('cannot use system reserved %s table ids'
517 %(str(self.system_reserved_rt_tables.keys())))
d54baa22
RP
518
519 if not vrf_table.isdigit():
520 self.log_error('%s: vrf-table must be an integer or \'auto\''
521 %(ifaceobj.name), ifaceobj)
522
6f2890fc
RP
523 # XXX: If we decide to not allow vrf id usages out of
524 # the reserved ifupdown range, then uncomment this code.
fd8c6caf
RP
525 else:
526 if (int(vrf_table) < self.vrf_table_id_start or
527 int(vrf_table) > self.vrf_table_id_end):
528 self.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
529 %(ifaceobj.name, vrf_table,
530 self.vrf_table_id_start,
531 self.vrf_table_id_end))
2df6a60f 532 try:
8465de90
RP
533 self.ipcmd.link_create(ifaceobj.name, 'vrf',
534 {'table' : '%s' %vrf_table})
2df6a60f
RP
535 except Exception, e:
536 self.log_error('%s: create failed (%s)\n'
537 %(ifaceobj.name, str(e)))
25e2386e
RP
538 if vrf_table != 'auto':
539 self._iproute2_vrf_table_entry_add(ifaceobj.name, vrf_table)
2df6a60f 540 else:
4d2c9798
RP
541 if vrf_table == 'auto':
542 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
543 if not vrf_table:
544 self.log_error('%s: unable to get vrf table id'
545 %ifaceobj.name)
6f2890fc 546
2df6a60f
RP
547 # if the device exists, check if table id is same
548 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
549 if vrfdev_attrs:
550 running_table = vrfdev_attrs.get('table', None)
551 if vrf_table != running_table:
6f2890fc
RP
552 self.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj.name,
553 running_table, vrf_table))
4d2c9798
RP
554 return vrf_table
555
25e2386e 556 def _up_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
557 mode = ""
558 if ifupdownflags.flags.PERFMODE:
559 mode = "boot"
25e2386e 560 if self.vrf_helper:
c4e05f9f
RP
561 self.exec_command('%s create %s %s %s' %(self.vrf_helper,
562 ifaceobj.name, vrf_table, mode))
25e2386e 563
4d2c9798
RP
564 def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True,
565 ifaceobj_getfunc=None):
8ad5c767
RP
566
567 # if vrf dev is already processed return. This can happen
0ba04b38
RP
568 # if we the slave was configured before.
569 # see self._up_vrf_slave_without_master
8ad5c767
RP
570 if self._check_vrf_dev_processed_flag(ifaceobj):
571 return True
572
25e2386e
RP
573 try:
574 vrf_table = self._create_vrf_dev(ifaceobj, vrf_table)
575 except Exception, e:
576 self.log_error('%s: %s' %(ifaceobj.name, str(e)))
577
8ad5c767 578 try:
8ad5c767 579 self._add_vrf_rules(ifaceobj.name, vrf_table)
6369e774 580 self._up_vrf_helper(ifaceobj, vrf_table)
8ad5c767 581 if add_slaves:
4d2c9798 582 self._add_vrf_slaves(ifaceobj, ifaceobj_getfunc)
8ad5c767 583 self._set_vrf_dev_processed_flag(ifaceobj)
0ba04b38 584 rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
8ad5c767
RP
585 except Exception, e:
586 self.log_error('%s: %s' %(ifaceobj.name, str(e)))
587
0ba04b38 588 def _kill_ssh_connections(self, ifacename):
5c5a7b93 589 try:
0ba04b38
RP
590 runningaddrsdict = self.ipcmd.addr_get(ifacename)
591 if not runningaddrsdict:
5c5a7b93 592 return
0ba04b38
RP
593 iplist = [i.split('/', 1)[0] for i in runningaddrsdict.keys()]
594 if not iplist:
595 return
596 proc=[]
5c5a7b93
N
597 #Example output:
598 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
599 #users:(("sshd",pid=2528,fd=3))
0ba04b38 600 cmdl = ['/bin/ss', '-t', '-p']
5c5a7b93
N
601 for line in subprocess.check_output(cmdl, stderr=subprocess.STDOUT,
602 shell=False).splitlines():
603 citems = line.split()
604 addr = None
605 if '%' in citems[3]:
606 addr = citems[3].split('%')[0]
607 elif ':ssh' in citems[3]:
608 addr = citems[3].split(':')[0]
609 if not addr:
610 continue
0ba04b38 611 if addr in iplist:
5c5a7b93
N
612 if len(citems) == 6:
613 proc.append(citems[5].split(',')[1].split('=')[1])
614
615 if not proc:
616 return
0ba04b38 617 pid = subprocess.check_output(['/bin/ps', '--no-headers',
5c5a7b93
N
618 '-fp', str(os.getppid())],
619 stderr=subprocess.STDOUT,
620 shell=False).split()[2]
aa36221f
RP
621 self.logger.info("%s: killing active ssh sessions: %s"
622 %(ifacename, str(proc)))
5c5a7b93
N
623 for id in proc:
624 if id != pid:
625 try:
aa36221f 626 os.kill(int(id), signal.SIGINT)
5c5a7b93
N
627 except OSError as e:
628 continue
0ba04b38
RP
629
630 # Kill current SSH client
5c5a7b93 631 if pid in proc:
32f6e6ca 632 try:
0ba04b38
RP
633 forkret = os.fork()
634 except OSError, e:
635 self.logger.info("fork error : %s [%d]" % (e.strerror, e.errno))
636 if (forkret == 0): # The first child.
637 try:
638 os.setsid()
639 self.logger.info("%s: ifreload continuing in the background" %ifacename)
640 except OSError, (err_no, err_message):
641 self.logger.info("os.setsid failed: errno=%d: %s" % (err_no, err_message))
642 self.logger.info("pid=%d pgid=%d" % (os.getpid(), os.getpgid(0)))
5c5a7b93 643 try:
aa36221f
RP
644 self.logger.info("%s: killing our session: %s"
645 %(ifacename, str(proc)))
646 os.kill(int(pid), signal.SIGINT)
5c5a7b93
N
647 return
648 except OSError as e:
649 return
650 except Exception, e:
651 self.logger.info('%s: %s' %(ifacename, str(e)))
652
8ad5c767 653 def _up(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
654 try:
655 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
656 if vrf_table:
05ac52f0 657 self._iproute2_vrf_map_initialize()
09753350 658 # This is a vrf device
4d2c9798 659 self._up_vrf_dev(ifaceobj, vrf_table, True, ifaceobj_getfunc)
8465de90
RP
660 else:
661 vrf = ifaceobj.get_attr_value_first('vrf')
662 if vrf:
05ac52f0 663 self._iproute2_vrf_map_initialize()
09753350 664 # This is a vrf slave
8ad5c767
RP
665 self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
666 ifaceobj_getfunc)
aa36221f
RP
667 else:
668 # check if we were a slave before
669 master = self.ipcmd.link_get_master(ifaceobj.name)
670 if master:
717cee31 671 self._iproute2_vrf_map_initialize()
aa36221f 672 if self._is_vrf_dev(master):
0ba04b38
RP
673 self._down_vrf_slave(ifaceobj.name, ifaceobj,
674 master)
8465de90
RP
675 except Exception, e:
676 self.log_error(str(e))
677
25e2386e 678 def _down_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
679 mode = ""
680 if ifupdownflags.flags.PERFMODE:
681 mode = "boot"
25e2386e 682 if self.vrf_helper:
c4e05f9f
RP
683 self.exec_command('%s delete %s %s %s' %(self.vrf_helper,
684 ifaceobj.name, vrf_table, mode))
25e2386e 685
c4be5481 686 def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
5c5a7b93 687
8465de90
RP
688 if vrf_table == 'auto':
689 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
aa36221f 690
2365b3c9
RP
691 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
692 if running_slaves:
693 for s in running_slaves:
694 if ifaceobj_getfunc:
695 sobj = ifaceobj_getfunc(s)
696 try:
697 self._handle_existing_connections(sobj[0]
698 if sobj else None,
0ba04b38 699 ifaceobj.name)
2365b3c9
RP
700 except Exception, e:
701 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
702 pass
703 try:
704 self.ipcmd.addr_flush(s)
705 rtnetlink_api.rtnl_api.link_set(s, "down")
706 except Exception, e:
707 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
708 pass
768b4ec5 709
6369e774 710 self._down_vrf_helper(ifaceobj, vrf_table)
25e2386e 711
768b4ec5 712 try:
f1c92482 713 self._del_vrf_rules(ifaceobj.name, vrf_table)
768b4ec5
RP
714 except Exception, e:
715 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
716 pass
717
718 try:
f1c92482
RP
719 self.ipcmd.link_delete(ifaceobj.name)
720 except Exception, e:
721 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
722 pass
723
724 try:
725 self._iproute2_vrf_table_entry_del(vrf_table)
8465de90 726 except Exception, e:
768b4ec5
RP
727 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
728 pass
8465de90 729
f1c92482 730
0ba04b38 731 def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
8465de90 732 try:
0ba04b38 733 self._handle_existing_connections(ifaceobj, vrfname)
768b4ec5 734 self.ipcmd.link_set(ifacename, 'nomaster')
f825610e 735 rtnetlink_api.rtnl_api.link_set(ifacename, "down")
8465de90 736 except Exception, e:
768b4ec5 737 self.logger.warn('%s: %s' %(ifacename, str(e)))
8465de90 738
8ad5c767 739 def _down(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
740 try:
741 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
742 if vrf_table:
05ac52f0 743 self._iproute2_vrf_map_initialize()
c4be5481 744 self._down_vrf_dev(ifaceobj, vrf_table, ifaceobj_getfunc)
8465de90
RP
745 else:
746 vrf = ifaceobj.get_attr_value_first('vrf')
747 if vrf:
05ac52f0 748 self._iproute2_vrf_map_initialize()
0ba04b38 749 self._down_vrf_slave(ifaceobj.name, ifaceobj, None)
8465de90
RP
750 except Exception, e:
751 self.log_warn(str(e))
752
753 def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
754 try:
54616d3f 755 master = self.ipcmd.link_get_master(ifaceobj.name)
8465de90 756 if not master or master != vrf:
586535e8 757 ifaceobjcurr.update_config_with_status('vrf', str(master), 1)
8465de90
RP
758 else:
759 ifaceobjcurr.update_config_with_status('vrf', master, 0)
760 except Exception, e:
761 self.log_warn(str(e))
762
6e16e5ae 763 def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
8465de90
RP
764 try:
765 if not self.ipcmd.link_exists(ifaceobj.name):
766 self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
767 return
768 if vrf_table == 'auto':
769 config_table = self._get_iproute2_vrf_table(ifaceobj.name)
770 else:
771 config_table = vrf_table
772 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
773 if not vrfdev_attrs:
774 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
775 return
776 running_table = vrfdev_attrs.get('table')
777 if not running_table:
778 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
779 return
780 if config_table != running_table:
781 ifaceobjcurr.update_config_with_status('vrf-table',
782 running_table, 1)
783 else:
784 ifaceobjcurr.update_config_with_status('vrf-table',
785 running_table, 0)
6e16e5ae 786 if not ifupdownflags.flags.WITHDEFAULTS:
669b422a
RP
787 return
788 if self.vrf_helper:
6e16e5ae
N
789 try:
790 self.exec_command('%s verify %s %s'
791 %(self.vrf_helper,
792 ifaceobj.name, config_table))
793 ifaceobjcurr.update_config_with_status('vrf-helper',
794 '%s create %s %s'
795 %(self.vrf_helper,
796 ifaceobj.name,
797 config_table), 0)
798 except Exception, e:
799 ifaceobjcurr.update_config_with_status('vrf-helper',
800 '%s create %s %s'
801 %(self.vrf_helper,
802 ifaceobj.name,
803 config_table), 1)
804 pass
8465de90
RP
805 except Exception, e:
806 self.log_warn(str(e))
807
6e16e5ae 808 def _query_check(self, ifaceobj, ifaceobjcurr):
8465de90
RP
809 try:
810 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
811 if vrf_table:
eb3ce8c8 812 self._iproute2_vrf_map_initialize(writetodisk=False)
6e16e5ae 813 self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table)
8465de90
RP
814 else:
815 vrf = ifaceobj.get_attr_value_first('vrf')
816 if vrf:
eb3ce8c8 817 self._iproute2_vrf_map_initialize(writetodisk=False)
8465de90
RP
818 self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf)
819 except Exception, e:
820 self.log_warn(str(e))
821
8ad5c767 822 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
8465de90
RP
823 try:
824 kind = self.ipcmd.link_get_kind(ifaceobjrunning.name)
825 if kind == 'vrf':
54616d3f 826 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobjrunning.name)
8465de90
RP
827 if vrfdev_attrs:
828 running_table = vrfdev_attrs.get('table')
829 if running_table:
830 ifaceobjrunning.update_config('vrf-table',
831 running_table)
832 elif kind == 'vrf_slave':
54616d3f 833 vrf = self.ipcmd.link_get_master(ifaceobjrunning.name)
8465de90
RP
834 if vrf:
835 ifaceobjrunning.update_config('vrf', vrf)
836 except Exception, e:
837 self.log_warn(str(e))
838
baa909c6
N
839 def _query(self, ifaceobj, **kwargs):
840 if not self.vrf_helper:
841 return
842 if (ifaceobj.link_kind & ifaceLinkKind.VRF):
843 ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper,
844 ifaceobj.name))
845
8465de90
RP
846 _run_ops = {'pre-up' : _up,
847 'post-down' : _down,
848 'query-running' : _query_running,
baa909c6
N
849 'query-checkcurr' : _query_check,
850 'query' : _query}
8465de90
RP
851
852 def get_ops(self):
853 """ returns list of ops supported by this module """
854 return self._run_ops.keys()
855
856 def _init_command_handlers(self):
8465de90 857 if not self.ipcmd:
fc5e1735 858 self.ipcmd = iproute2()
8465de90 859 if not self.bondcmd:
fc5e1735 860 self.bondcmd = bondutil()
122ef35b 861 if not self.dhclientcmd:
fc5e1735 862 self.dhclientcmd = dhclient()
8465de90 863
8ad5c767
RP
864 def run(self, ifaceobj, operation, query_ifaceobj=None,
865 ifaceobj_getfunc=None, **extra_args):
8465de90
RP
866 """ run bond configuration on the interface object passed as argument
867
868 Args:
869 **ifaceobj** (object): iface object
870
871 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
872 'query-running'
873
874 Kwargs:
875 **query_ifaceobj** (object): query check ifaceobject. This is only
876 valid when op is 'query-checkcurr'. It is an object same as
877 ifaceobj, but contains running attribute values and its config
878 status. The modules can use it to return queried running state
879 of interfaces. status is success if the running state is same
880 as user required state in ifaceobj. error otherwise.
881 """
882 op_handler = self._run_ops.get(operation)
883 if not op_handler:
884 return
885 self._init_command_handlers()
886 if operation == 'query-checkcurr':
6e16e5ae 887 op_handler(self, ifaceobj, query_ifaceobj)
8465de90 888 else:
8ad5c767 889 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)