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