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