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