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