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