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