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