]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/vrf.py
ifreload: --currently-up fixes
[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
bf3eda91 245 def _iproute2_is_vrf_tableid_inuse(self, vrfifaceobj, table_id):
25e2386e 246 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
bf3eda91 247 if old_vrf_name and old_vrf_name != vrfifaceobj.name:
25e2386e 248 self.log_error('table id %s already assigned to vrf dev %s'
bf3eda91 249 %(table_id, old_vrf_name), vrfifaceobj)
25e2386e 250
bf3eda91 251 def _iproute2_vrf_table_entry_add(self, vrfifaceobj, table_id):
05ac52f0 252 old_vrf_name = self.iproute2_vrf_map.get(int(table_id))
25e2386e 253 if not old_vrf_name:
bf3eda91 254 self.iproute2_vrf_map[int(table_id)] = vrfifaceobj.name
05ac52f0
RP
255 if self.iproute2_vrf_map_fd:
256 self.iproute2_vrf_map_fd.write('%s %s\n'
bf3eda91 257 %(table_id, vrfifaceobj.name))
05ac52f0 258 self.iproute2_vrf_map_fd.flush()
c8a3b44e 259 self.vrf_count += 1
25e2386e
RP
260 return
261
bf3eda91 262 if old_vrf_name != vrfifaceobj.name:
25e2386e
RP
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'
bf3eda91 318 %mobj.name, ifaceobj)
df53966d
RP
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:
d2b35716 354 master_exists = True
09753350
RP
355 if vrf_exists or self.ipcmd.link_exists(vrfname):
356 upper = self.ipcmd.link_get_upper(ifacename)
4d2c9798 357 if not upper or upper != vrfname:
0ba04b38 358 self._handle_existing_connections(ifaceobj, vrfname)
122ef35b 359 self.ipcmd.link_set(ifacename, 'master', vrfname)
d2b35716 360 elif ifupdownflags.flags.ALL and ifaceobj:
0ba04b38
RP
361 self._up_vrf_slave_without_master(ifacename, vrfname, ifaceobj,
362 ifaceobj_getfunc)
d2b35716
RP
363 else:
364 master_exists = False
365 if master_exists:
366 rtnetlink_api.rtnl_api.link_set(ifacename, "up")
367 else:
368 self.log_error('vrf %s not around, skipping vrf config'
bf3eda91 369 %(vrfname), ifaceobj)
8465de90 370 except Exception, e:
bf3eda91 371 self.log_error('%s: %s' %(ifacename, str(e)), ifaceobj)
8465de90
RP
372
373 def _del_vrf_rules(self, vrf_dev_name, vrf_table):
374 pref = 200
375 ip_rule_out_format = '%s: from all %s %s lookup %s'
376 ip_rule_cmd = 'ip %s rule del pref %s %s %s table %s'
377
4ce47ce4 378 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 379 if rule in self.ip_rule_cache:
25e2386e
RP
380 rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
381 vrf_dev_name)
8465de90
RP
382 self.exec_command(rule_cmd)
383
4ce47ce4 384 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
8465de90 385 if rule in self.ip_rule_cache:
25e2386e
RP
386 rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
387 vrf_dev_name)
8465de90
RP
388 self.exec_command(rule_cmd)
389
4ce47ce4 390 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 391 if rule in self.ip6_rule_cache:
8465de90 392 rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
25e2386e 393 vrf_dev_name)
8465de90
RP
394 self.exec_command(rule_cmd)
395
4ce47ce4 396 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 397 if rule in self.ip6_rule_cache:
8465de90 398 rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
25e2386e 399 vrf_dev_name)
8465de90
RP
400 self.exec_command(rule_cmd)
401
402 def _add_vrf_rules(self, vrf_dev_name, vrf_table):
403 pref = 200
404 ip_rule_out_format = '%s: from all %s %s lookup %s'
405 ip_rule_cmd = 'ip %s rule add pref %s %s %s table %s'
659097a0
N
406 if self.vrf_fix_local_table:
407 self.vrf_fix_local_table = False
408 rule = '0: from all lookup local'
409 if rule in self.ip_rule_cache:
410 try:
3fcb15fe
N
411 self.exec_command('ip rule del pref 0')
412 self.exec_command('ip rule add pref 32765 table local')
659097a0
N
413 except Exception, e:
414 self.logger.info('%s' %str(e))
415 pass
c61672da
N
416 if rule in self.ip6_rule_cache:
417 try:
418 self.exec_command('ip -6 rule del pref 0')
419 self.exec_command('ip -6 rule add pref 32765 table local')
420 except Exception, e:
421 self.logger.info('%s' %str(e))
422 pass
8465de90 423
3fcb15fe
N
424 #Example ip rule
425 #200: from all oif blue lookup blue
426 #200: from all iif blue lookup blue
427
428 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
8465de90 429 if rule not in self.ip_rule_cache:
25e2386e
RP
430 rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
431 vrf_dev_name)
8465de90
RP
432 self.exec_command(rule_cmd)
433
3fcb15fe 434 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
8465de90 435 if rule not in self.ip_rule_cache:
25e2386e
RP
436 rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
437 vrf_dev_name)
8465de90
RP
438 self.exec_command(rule_cmd)
439
3fcb15fe 440 rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
e6072769 441 if rule not in self.ip6_rule_cache:
25e2386e
RP
442 rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
443 vrf_dev_name)
8465de90
RP
444 self.exec_command(rule_cmd)
445
3fcb15fe 446 rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
e6072769 447 if rule not in self.ip6_rule_cache:
8465de90 448 rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
25e2386e 449 vrf_dev_name)
8465de90
RP
450 self.exec_command(rule_cmd)
451
4d2c9798 452 def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None):
768b4ec5
RP
453 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
454 config_slaves = ifaceobj.lowerifaces
b94e4d24 455 if not config_slaves and not running_slaves:
867e11a2 456 return
4d2c9798
RP
457
458 if not config_slaves: config_slaves = []
459 if not running_slaves: running_slaves = []
768b4ec5
RP
460 add_slaves = set(config_slaves).difference(set(running_slaves))
461 del_slaves = set(running_slaves).difference(set(config_slaves))
462 if add_slaves:
463 for s in add_slaves:
464 try:
d2b35716
RP
465 if not self.ipcmd.link_exists(s):
466 continue
09753350
RP
467 sobj = None
468 if ifaceobj_getfunc:
469 sobj = ifaceobj_getfunc(s)
470 self._up_vrf_slave(s, ifaceobj.name,
471 sobj[0] if sobj else None,
472 ifaceobj_getfunc, True)
768b4ec5
RP
473 except Exception, e:
474 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
475
476 if del_slaves:
477 for s in del_slaves:
478 try:
aa36221f 479 sobj = None
4d2c9798
RP
480 if ifaceobj_getfunc:
481 sobj = ifaceobj_getfunc(s)
0ba04b38
RP
482 self._down_vrf_slave(s, sobj[0] if sobj else None,
483 ifaceobj.name)
768b4ec5
RP
484 except Exception, e:
485 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
486
487 if ifaceobj.link_type == ifaceLinkType.LINK_MASTER:
488 for s in config_slaves:
489 try:
490 rtnetlink_api.rtnl_api.link_set(s, "up")
491 except Exception, e:
492 self.logger.debug('%s: %s: link set up (%s)'
493 %(ifaceobj.name, s, str(e)))
494 pass
8465de90 495
8ad5c767
RP
496 def _set_vrf_dev_processed_flag(self, ifaceobj):
497 ifaceobj.module_flags[self.name] = \
498 ifaceobj.module_flags.setdefault(self.name, 0) | \
499 vrfPrivFlags.PROCESSED
500
501 def _check_vrf_dev_processed_flag(self, ifaceobj):
25e2386e 502 if (ifaceobj.module_flags.get(self.name, 0) & vrfPrivFlags.PROCESSED):
8ad5c767
RP
503 return True
504 return False
8465de90 505
8ad5c767 506 def _create_vrf_dev(self, ifaceobj, vrf_table):
2df6a60f 507 if not self.ipcmd.link_exists(ifaceobj.name):
f6466fcb
RP
508 if ifaceobj.name in self.system_reserved_rt_tables.values():
509 self.log_error('cannot use system reserved %s vrf names'
bf3eda91
RP
510 %(str(self.system_reserved_rt_tables.values())),
511 ifaceobj)
c8a3b44e
RP
512 if self.vrf_count == self.vrf_max_count:
513 self.log_error('%s: max vrf count %d hit...not '
514 'creating vrf' %(ifaceobj.name,
bf3eda91 515 self.vrf_count), ifaceobj)
6f2890fc
RP
516 if vrf_table == 'auto':
517 vrf_table = self._get_avail_vrf_table_id()
518 if not vrf_table:
519 self.log_error('%s: unable to get an auto table id'
bf3eda91 520 %ifaceobj.name, ifaceobj)
6f2890fc
RP
521 self.logger.info('%s: table id auto: selected table id %s\n'
522 %(ifaceobj.name, vrf_table))
25e2386e 523 else:
bf3eda91 524 self._iproute2_is_vrf_tableid_inuse(ifaceobj, vrf_table)
f6466fcb
RP
525 if ifaceobj.name in self.system_reserved_rt_tables.keys():
526 self.log_error('cannot use system reserved %s table ids'
bf3eda91
RP
527 %(str(self.system_reserved_rt_tables.keys())),
528 ifaceobj)
d54baa22
RP
529
530 if not vrf_table.isdigit():
531 self.log_error('%s: vrf-table must be an integer or \'auto\''
532 %(ifaceobj.name), ifaceobj)
533
6f2890fc
RP
534 # XXX: If we decide to not allow vrf id usages out of
535 # the reserved ifupdown range, then uncomment this code.
fd8c6caf
RP
536 else:
537 if (int(vrf_table) < self.vrf_table_id_start or
538 int(vrf_table) > self.vrf_table_id_end):
539 self.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
540 %(ifaceobj.name, vrf_table,
541 self.vrf_table_id_start,
bf3eda91 542 self.vrf_table_id_end), ifaceobj)
2df6a60f 543 try:
8465de90
RP
544 self.ipcmd.link_create(ifaceobj.name, 'vrf',
545 {'table' : '%s' %vrf_table})
2df6a60f
RP
546 except Exception, e:
547 self.log_error('%s: create failed (%s)\n'
bf3eda91 548 %(ifaceobj.name, str(e)), ifaceobj)
25e2386e 549 if vrf_table != 'auto':
bf3eda91 550 self._iproute2_vrf_table_entry_add(ifaceobj, vrf_table)
2df6a60f 551 else:
4d2c9798
RP
552 if vrf_table == 'auto':
553 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
554 if not vrf_table:
555 self.log_error('%s: unable to get vrf table id'
bf3eda91 556 %ifaceobj.name, ifaceobj)
6f2890fc 557
2df6a60f
RP
558 # if the device exists, check if table id is same
559 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
560 if vrfdev_attrs:
561 running_table = vrfdev_attrs.get('table', None)
562 if vrf_table != running_table:
6f2890fc 563 self.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj.name,
bf3eda91
RP
564 running_table, vrf_table),
565 ifaceobj)
4d2c9798
RP
566 return vrf_table
567
25e2386e 568 def _up_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
569 mode = ""
570 if ifupdownflags.flags.PERFMODE:
571 mode = "boot"
25e2386e 572 if self.vrf_helper:
c4e05f9f
RP
573 self.exec_command('%s create %s %s %s' %(self.vrf_helper,
574 ifaceobj.name, vrf_table, mode))
25e2386e 575
4d2c9798
RP
576 def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True,
577 ifaceobj_getfunc=None):
8ad5c767
RP
578
579 # if vrf dev is already processed return. This can happen
0ba04b38
RP
580 # if we the slave was configured before.
581 # see self._up_vrf_slave_without_master
8ad5c767
RP
582 if self._check_vrf_dev_processed_flag(ifaceobj):
583 return True
584
25e2386e
RP
585 try:
586 vrf_table = self._create_vrf_dev(ifaceobj, vrf_table)
587 except Exception, e:
bf3eda91 588 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
25e2386e 589
8ad5c767 590 try:
8ad5c767 591 self._add_vrf_rules(ifaceobj.name, vrf_table)
6369e774 592 self._up_vrf_helper(ifaceobj, vrf_table)
8ad5c767 593 if add_slaves:
4d2c9798 594 self._add_vrf_slaves(ifaceobj, ifaceobj_getfunc)
8ad5c767 595 self._set_vrf_dev_processed_flag(ifaceobj)
0ba04b38 596 rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
8ad5c767 597 except Exception, e:
bf3eda91 598 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
8ad5c767 599
0ba04b38 600 def _kill_ssh_connections(self, ifacename):
5c5a7b93 601 try:
0ba04b38
RP
602 runningaddrsdict = self.ipcmd.addr_get(ifacename)
603 if not runningaddrsdict:
5c5a7b93 604 return
0ba04b38
RP
605 iplist = [i.split('/', 1)[0] for i in runningaddrsdict.keys()]
606 if not iplist:
607 return
608 proc=[]
5c5a7b93
N
609 #Example output:
610 #ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
611 #users:(("sshd",pid=2528,fd=3))
0ba04b38 612 cmdl = ['/bin/ss', '-t', '-p']
5c5a7b93
N
613 for line in subprocess.check_output(cmdl, stderr=subprocess.STDOUT,
614 shell=False).splitlines():
615 citems = line.split()
616 addr = None
617 if '%' in citems[3]:
618 addr = citems[3].split('%')[0]
619 elif ':ssh' in citems[3]:
620 addr = citems[3].split(':')[0]
621 if not addr:
622 continue
0ba04b38 623 if addr in iplist:
5c5a7b93
N
624 if len(citems) == 6:
625 proc.append(citems[5].split(',')[1].split('=')[1])
626
627 if not proc:
628 return
0ba04b38 629 pid = subprocess.check_output(['/bin/ps', '--no-headers',
5c5a7b93
N
630 '-fp', str(os.getppid())],
631 stderr=subprocess.STDOUT,
632 shell=False).split()[2]
aa36221f
RP
633 self.logger.info("%s: killing active ssh sessions: %s"
634 %(ifacename, str(proc)))
cbdde74e
RP
635
636 if ifupdownflags.flags.DRYRUN:
637 return
5c5a7b93
N
638 for id in proc:
639 if id != pid:
640 try:
aa36221f 641 os.kill(int(id), signal.SIGINT)
5c5a7b93
N
642 except OSError as e:
643 continue
0ba04b38
RP
644
645 # Kill current SSH client
5c5a7b93 646 if pid in proc:
32f6e6ca 647 try:
0ba04b38
RP
648 forkret = os.fork()
649 except OSError, e:
650 self.logger.info("fork error : %s [%d]" % (e.strerror, e.errno))
651 if (forkret == 0): # The first child.
652 try:
653 os.setsid()
654 self.logger.info("%s: ifreload continuing in the background" %ifacename)
655 except OSError, (err_no, err_message):
656 self.logger.info("os.setsid failed: errno=%d: %s" % (err_no, err_message))
657 self.logger.info("pid=%d pgid=%d" % (os.getpid(), os.getpgid(0)))
5c5a7b93 658 try:
aa36221f
RP
659 self.logger.info("%s: killing our session: %s"
660 %(ifacename, str(proc)))
661 os.kill(int(pid), signal.SIGINT)
5c5a7b93
N
662 return
663 except OSError as e:
664 return
665 except Exception, e:
666 self.logger.info('%s: %s' %(ifacename, str(e)))
667
8ad5c767 668 def _up(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
669 try:
670 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
671 if vrf_table:
05ac52f0 672 self._iproute2_vrf_map_initialize()
09753350 673 # This is a vrf device
4d2c9798 674 self._up_vrf_dev(ifaceobj, vrf_table, True, ifaceobj_getfunc)
8465de90
RP
675 else:
676 vrf = ifaceobj.get_attr_value_first('vrf')
677 if vrf:
05ac52f0 678 self._iproute2_vrf_map_initialize()
09753350 679 # This is a vrf slave
8ad5c767
RP
680 self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
681 ifaceobj_getfunc)
aa36221f
RP
682 else:
683 # check if we were a slave before
684 master = self.ipcmd.link_get_master(ifaceobj.name)
685 if master:
717cee31 686 self._iproute2_vrf_map_initialize()
aa36221f 687 if self._is_vrf_dev(master):
0ba04b38
RP
688 self._down_vrf_slave(ifaceobj.name, ifaceobj,
689 master)
8465de90 690 except Exception, e:
bf3eda91 691 self.log_error(str(e), ifaceobj)
8465de90 692
25e2386e 693 def _down_vrf_helper(self, ifaceobj, vrf_table):
c4e05f9f
RP
694 mode = ""
695 if ifupdownflags.flags.PERFMODE:
696 mode = "boot"
25e2386e 697 if self.vrf_helper:
c4e05f9f
RP
698 self.exec_command('%s delete %s %s %s' %(self.vrf_helper,
699 ifaceobj.name, vrf_table, mode))
25e2386e 700
c4be5481 701 def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
5c5a7b93 702
8465de90
RP
703 if vrf_table == 'auto':
704 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
aa36221f 705
2365b3c9
RP
706 running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name)
707 if running_slaves:
708 for s in running_slaves:
709 if ifaceobj_getfunc:
710 sobj = ifaceobj_getfunc(s)
711 try:
712 self._handle_existing_connections(sobj[0]
713 if sobj else None,
0ba04b38 714 ifaceobj.name)
2365b3c9
RP
715 except Exception, e:
716 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
717 pass
718 try:
719 self.ipcmd.addr_flush(s)
720 rtnetlink_api.rtnl_api.link_set(s, "down")
721 except Exception, e:
722 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
723 pass
768b4ec5 724
6369e774 725 self._down_vrf_helper(ifaceobj, vrf_table)
25e2386e 726
768b4ec5 727 try:
f1c92482 728 self._del_vrf_rules(ifaceobj.name, vrf_table)
768b4ec5
RP
729 except Exception, e:
730 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
731 pass
732
733 try:
f1c92482
RP
734 self.ipcmd.link_delete(ifaceobj.name)
735 except Exception, e:
736 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
737 pass
738
739 try:
740 self._iproute2_vrf_table_entry_del(vrf_table)
8465de90 741 except Exception, e:
768b4ec5
RP
742 self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
743 pass
8465de90 744
f1c92482 745
0ba04b38 746 def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
8465de90 747 try:
0ba04b38 748 self._handle_existing_connections(ifaceobj, vrfname)
768b4ec5 749 self.ipcmd.link_set(ifacename, 'nomaster')
f825610e 750 rtnetlink_api.rtnl_api.link_set(ifacename, "down")
8465de90 751 except Exception, e:
768b4ec5 752 self.logger.warn('%s: %s' %(ifacename, str(e)))
8465de90 753
8ad5c767 754 def _down(self, ifaceobj, ifaceobj_getfunc=None):
8465de90
RP
755 try:
756 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
757 if vrf_table:
05ac52f0 758 self._iproute2_vrf_map_initialize()
c4be5481 759 self._down_vrf_dev(ifaceobj, vrf_table, ifaceobj_getfunc)
8465de90
RP
760 else:
761 vrf = ifaceobj.get_attr_value_first('vrf')
762 if vrf:
05ac52f0 763 self._iproute2_vrf_map_initialize()
0ba04b38 764 self._down_vrf_slave(ifaceobj.name, ifaceobj, None)
8465de90
RP
765 except Exception, e:
766 self.log_warn(str(e))
767
768 def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
769 try:
54616d3f 770 master = self.ipcmd.link_get_master(ifaceobj.name)
8465de90 771 if not master or master != vrf:
586535e8 772 ifaceobjcurr.update_config_with_status('vrf', str(master), 1)
8465de90
RP
773 else:
774 ifaceobjcurr.update_config_with_status('vrf', master, 0)
775 except Exception, e:
bf3eda91 776 self.log_error(str(e), ifaceobjcurr)
8465de90 777
6e16e5ae 778 def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
8465de90
RP
779 try:
780 if not self.ipcmd.link_exists(ifaceobj.name):
781 self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
782 return
783 if vrf_table == 'auto':
784 config_table = self._get_iproute2_vrf_table(ifaceobj.name)
785 else:
786 config_table = vrf_table
787 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
788 if not vrfdev_attrs:
789 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
790 return
791 running_table = vrfdev_attrs.get('table')
792 if not running_table:
793 ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
794 return
795 if config_table != running_table:
796 ifaceobjcurr.update_config_with_status('vrf-table',
797 running_table, 1)
798 else:
799 ifaceobjcurr.update_config_with_status('vrf-table',
800 running_table, 0)
6e16e5ae 801 if not ifupdownflags.flags.WITHDEFAULTS:
669b422a
RP
802 return
803 if self.vrf_helper:
6e16e5ae
N
804 try:
805 self.exec_command('%s verify %s %s'
806 %(self.vrf_helper,
807 ifaceobj.name, config_table))
808 ifaceobjcurr.update_config_with_status('vrf-helper',
809 '%s create %s %s'
810 %(self.vrf_helper,
811 ifaceobj.name,
812 config_table), 0)
813 except Exception, e:
814 ifaceobjcurr.update_config_with_status('vrf-helper',
815 '%s create %s %s'
816 %(self.vrf_helper,
817 ifaceobj.name,
818 config_table), 1)
819 pass
8465de90
RP
820 except Exception, e:
821 self.log_warn(str(e))
822
6e16e5ae 823 def _query_check(self, ifaceobj, ifaceobjcurr):
8465de90
RP
824 try:
825 vrf_table = ifaceobj.get_attr_value_first('vrf-table')
826 if vrf_table:
eb3ce8c8 827 self._iproute2_vrf_map_initialize(writetodisk=False)
6e16e5ae 828 self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table)
8465de90
RP
829 else:
830 vrf = ifaceobj.get_attr_value_first('vrf')
831 if vrf:
eb3ce8c8 832 self._iproute2_vrf_map_initialize(writetodisk=False)
8465de90
RP
833 self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf)
834 except Exception, e:
835 self.log_warn(str(e))
836
8ad5c767 837 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
8465de90
RP
838 try:
839 kind = self.ipcmd.link_get_kind(ifaceobjrunning.name)
840 if kind == 'vrf':
54616d3f 841 vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobjrunning.name)
8465de90
RP
842 if vrfdev_attrs:
843 running_table = vrfdev_attrs.get('table')
844 if running_table:
845 ifaceobjrunning.update_config('vrf-table',
846 running_table)
847 elif kind == 'vrf_slave':
54616d3f 848 vrf = self.ipcmd.link_get_master(ifaceobjrunning.name)
8465de90
RP
849 if vrf:
850 ifaceobjrunning.update_config('vrf', vrf)
851 except Exception, e:
852 self.log_warn(str(e))
853
baa909c6
N
854 def _query(self, ifaceobj, **kwargs):
855 if not self.vrf_helper:
856 return
857 if (ifaceobj.link_kind & ifaceLinkKind.VRF):
858 ifaceobj.update_config('vrf-helper', '%s %s' %(self.vrf_helper,
859 ifaceobj.name))
860
8465de90
RP
861 _run_ops = {'pre-up' : _up,
862 'post-down' : _down,
863 'query-running' : _query_running,
baa909c6
N
864 'query-checkcurr' : _query_check,
865 'query' : _query}
8465de90
RP
866
867 def get_ops(self):
868 """ returns list of ops supported by this module """
869 return self._run_ops.keys()
870
871 def _init_command_handlers(self):
8465de90 872 if not self.ipcmd:
fc5e1735 873 self.ipcmd = iproute2()
8465de90 874 if not self.bondcmd:
fc5e1735 875 self.bondcmd = bondutil()
122ef35b 876 if not self.dhclientcmd:
fc5e1735 877 self.dhclientcmd = dhclient()
8465de90 878
8ad5c767
RP
879 def run(self, ifaceobj, operation, query_ifaceobj=None,
880 ifaceobj_getfunc=None, **extra_args):
8465de90
RP
881 """ run bond configuration on the interface object passed as argument
882
883 Args:
884 **ifaceobj** (object): iface object
885
886 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
887 'query-running'
888
889 Kwargs:
890 **query_ifaceobj** (object): query check ifaceobject. This is only
891 valid when op is 'query-checkcurr'. It is an object same as
892 ifaceobj, but contains running attribute values and its config
893 status. The modules can use it to return queried running state
894 of interfaces. status is success if the running state is same
895 as user required state in ifaceobj. error otherwise.
896 """
897 op_handler = self._run_ops.get(operation)
898 if not op_handler:
899 return
900 self._init_command_handlers()
901 if operation == 'query-checkcurr':
6e16e5ae 902 op_handler(self, ifaceobj, query_ifaceobj)
8465de90 903 else:
8ad5c767 904 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)