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