]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/vrf.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
9 from ifupdown
.iface
import *
11 from ifupdownaddons
.modulebase
import moduleBase
12 from ifupdownaddons
.bondutil
import bondutil
13 from ifupdownaddons
.iproute2
import iproute2
15 class vrf(moduleBase
):
16 """ ifupdown2 addon module to configure vrfs """
17 _modinfo
= { 'mhelp' : 'vrf configuration module',
20 {'help' : 'vrf device table id. key to ' +
21 'creating a vrf device',
22 'example': ['vrf-table-id 1']},
24 {'help' : 'vrf the interface is part of.',
25 'example': ['vrf blue']}}}
27 iproute2_vrf_filename
= '/etc/iproute2/rt_tables.d/ifupdown2.vrf_map'
28 iproute2_vrf_filehdr
= '# This file is autogenerated by ifupdown2.\n' + \
29 '# It contains the vrf name to table mapping.\n' + \
30 '# Reserved table range 150-200\n'
31 vrf_table_reserved_start
= 150
32 vrf_table_reserved_end
= 200
34 def __init__(self
, *args
, **kargs
):
35 ifupdownaddons
.modulebase
.moduleBase
.__init
__(self
, *args
, **kargs
)
39 ip_rules
= self
.exec_command('/sbin/ip rule show').splitlines()
40 self
.ip_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
42 self
.ip_rule_cache
= []
43 self
.logger
.warn('%s' %str
(e
))
46 ip_rules
= self
.exec_command('/sbin/ip -6 rule show').splitlines()
47 self
.ip6_rule_cache
= [' '.join(r
.split()) for r
in ip_rules
]
49 self
.ip6_rule_cache
= []
50 self
.logger
.warn('%s' %str
(e
))
52 #self.logger.debug("vrf: ip rule cache")
53 #self.logger.info(self.ip_rule_cache)
55 #self.logger.info("vrf: ip -6 rule cache")
56 #self.logger.info(self.ip6_rule_cache)
58 # XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
59 self
.iproute2_vrf_map
= {}
60 # read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
61 if os
.path
.exists(self
.iproute2_vrf_filename
):
62 self
.vrf_map_fd
= open(self
.iproute2_vrf_filename
, 'a+')
63 lines
= self
.vrf_map_fd
.readlines()
69 (table
, vrf_name
) = l
.strip().split()
70 self
.iproute2_vrf_map
[table
] = vrf_name
72 self
.logger
.info('vrf: iproute2_vrf_map: unable to parse %s'
75 #self.logger.info("vrf: dumping iproute2_vrf_map")
76 #self.logger.info(self.iproute2_vrf_map)
78 # purge vrf table entries that are not around
79 iproute2_vrf_map_pruned
= {}
80 for t
, v
in self
.iproute2_vrf_map
.iteritems():
81 if os
.path
.exists('/sys/class/net/%s' %v
):
82 iproute2_vrf_map_pruned
[t
] = v
86 self
._del
_vrf
_rules
(v
, t
)
89 self
.iproute2_vrf_map
= iproute2_vrf_map_pruned
91 last_used_vrf_table
= self
.vrf_table_reserved_start
92 for t
in range(self
.vrf_table_reserved_start
,
93 self
.vrf_table_reserved_end
):
94 last_used_vrf_table
= t
95 if not self
.iproute2_vrf_map
.get(t
):
97 self
.last_used_vrf_table
= last_used_vrf_table
98 self
.iproute2_write_vrf_map
= False
99 atexit
.register(self
.iproute2_vrf_map_write
)
101 def iproute2_vrf_map_write(self
):
102 if not self
.iproute2_write_vrf_map
:
104 self
.logger
.info('vrf: writing table map to %s'
105 %self
.iproute2_vrf_filename
)
106 with
open(self
.iproute2_vrf_filename
, 'w') as f
:
107 f
.write(self
.iproute2_vrf_filehdr
)
108 for t
, v
in self
.iproute2_vrf_map
.iteritems():
109 f
.write('%s %s\n' %(t
, v
))
111 def _is_vrf(self
, ifaceobj
):
112 if ifaceobj
.get_attr_value_first('vrf-table'):
116 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
117 """ Returns list of interfaces dependent on ifaceobj """
119 vrf_iface_name
= ifaceobj
.get_attr_value_first('vrf')
120 if not vrf_iface_name
:
122 return [vrf_iface_name
]
124 def get_dependent_ifacenames_running(self
, ifaceobj
):
127 def _get_iproute2_vrf_table(self
, vrf_dev_name
):
128 for t
, v
in self
.iproute2_vrf_map
.iteritems():
129 if v
== vrf_dev_name
:
133 def _get_avail_vrf_table_id(self
):
134 for t
in range(self
.last_used_vrf_table
+ 1,
135 self
.vrf_table_reserved_end
):
136 if not self
.iproute2_vrf_map
.get(t
):
137 self
.last_used_vrf_table
= t
141 def _iproute2_vrf_table_entry_add(self
, vrf_dev_name
, table_id
):
142 self
.iproute2_vrf_map
[table_id
] = vrf_dev_name
143 self
.iproute2_write_vrf_map
= True
145 def _iproute2_vrf_table_entry_del(self
, table_id
):
147 del self
.iproute2_vrf_map
[table_id
]
148 self
.iproute2_write_vrf_map
= True
150 self
.logger
.info('vrf: iproute2 vrf map del failed for %d (%s)'
154 def _up_vrf_slave(self
, ifaceobj
, vrf
):
156 self
.ipcmd
.link_set(ifaceobj
.name
, 'master', vrf
)
158 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
160 def _del_vrf_rules(self
, vrf_dev_name
, vrf_table
):
162 ip_rule_out_format
= '%s: from all %s %s lookup %s'
163 ip_rule_cmd
= 'ip %s rule del pref %s %s %s table %s'
165 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_table
)
166 if rule
in self
.ip_rule_cache
:
167 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
, vrf_table
)
168 self
.exec_command(rule_cmd
)
170 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_table
)
171 if rule
in self
.ip_rule_cache
:
172 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
, vrf_table
)
173 self
.exec_command(rule_cmd
)
175 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_table
)
176 if rule
in self
.ip_rule_cache
:
177 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
179 self
.exec_command(rule_cmd
)
181 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_table
)
182 if rule
in self
.ip_rule_cache
:
183 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
185 self
.exec_command(rule_cmd
)
187 def _add_vrf_rules(self
, vrf_dev_name
, vrf_table
):
189 ip_rule_out_format
= '%s: from all %s %s lookup %s'
190 ip_rule_cmd
= 'ip %s rule add pref %s %s %s table %s'
192 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_table
)
193 if rule
not in self
.ip_rule_cache
:
194 rule_cmd
= ip_rule_cmd
%('', pref
, 'oif', vrf_dev_name
, vrf_table
)
195 self
.exec_command(rule_cmd
)
197 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_table
)
198 if rule
not in self
.ip_rule_cache
:
199 rule_cmd
= ip_rule_cmd
%('', pref
, 'iif', vrf_dev_name
, vrf_table
)
200 self
.exec_command(rule_cmd
)
202 rule
= ip_rule_out_format
%(pref
, 'oif', vrf_dev_name
, vrf_table
)
203 if rule
not in self
.ip_rule_cache
:
204 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'oif', vrf_dev_name
,
206 self
.exec_command(rule_cmd
)
208 rule
= ip_rule_out_format
%(pref
, 'iif', vrf_dev_name
, vrf_table
)
209 if rule
not in self
.ip_rule_cache
:
210 rule_cmd
= ip_rule_cmd
%('-6', pref
, 'iif', vrf_dev_name
,
212 self
.exec_command(rule_cmd
)
215 def _up_vrf_dev(self
, ifaceobj
, vrf_table
):
216 if vrf_table
== 'auto':
217 vrf_table
= _get_avail_vrf_table_id(ifaceobj
.name
)
220 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
221 self
.ipcmd
.link_create(ifaceobj
.name
, 'vrf',
222 {'table' : '%s' %vrf_table
})
223 self
._iproute
2_vrf
_table
_entry
_add
(ifaceobj
.name
, vrf_table
)
224 self
._add
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
226 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
228 def _up(self
, ifaceobj
):
230 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
232 self
._up
_vrf
_dev
(ifaceobj
, vrf_table
)
234 vrf
= ifaceobj
.get_attr_value_first('vrf')
236 self
._up
_vrf
_slave
(ifaceobj
, vrf
)
238 self
.log_error(str(e
))
240 def _down_vrf_dev(self
, ifaceobj
, vrf_table
):
241 if vrf_table
== 'auto':
242 vrf_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
244 self
.ipcmd
.link_delete(ifaceobj
.name
)
245 self
._iproute
2_vrf
_table
_entry
_del
(vrf_table
)
246 self
._del
_vrf
_rules
(ifaceobj
.name
, vrf_table
)
248 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
250 def _down_vrf_slave(self
, ifaceobj
, vrf
):
252 self
.ipcmd
.link_set(ifaceobj
.name
, 'nomaster')
254 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
256 def _down(self
, ifaceobj
):
258 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
260 self
._down
_vrf
_dev
(ifaceobj
, vrf_table
)
262 vrf
= ifaceobj
.get_attr_value_first('vrf')
264 self
._down
_vrf
_slave
(ifaceobj
, vrf
)
266 self
.log_warn(str(e
))
268 def _query_check_vrf_slave(self
, ifaceobj
, ifaceobjcurr
, vrf
):
270 master
= self
.ipcmd
.link_get_master(ifacename
)
271 if not master
or master
!= vrf
:
272 ifaceobjcurr
.update_config_with_status('vrf', master
, 1)
274 ifaceobjcurr
.update_config_with_status('vrf', master
, 0)
276 self
.log_warn(str(e
))
278 def _query_check_vrf_dev(self
, ifaceobj
, ifaceobjcurr
, vrf_table
):
280 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
281 self
.logger
.info('%s: vrf: does not exist' %(ifaceobj
.name
))
283 if vrf_table
== 'auto':
284 config_table
= self
._get
_iproute
2_vrf
_table
(ifaceobj
.name
)
286 config_table
= vrf_table
287 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
289 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
291 running_table
= vrfdev_attrs
.get('table')
292 if not running_table
:
293 ifaceobjcurr
.update_config_with_status('vrf-table', 'None', 1)
295 if config_table
!= running_table
:
296 ifaceobjcurr
.update_config_with_status('vrf-table',
299 ifaceobjcurr
.update_config_with_status('vrf-table',
302 self
.log_warn(str(e
))
304 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
306 vrf_table
= ifaceobj
.get_attr_value_first('vrf-table')
308 self
._query
_check
_vrf
_dev
(ifaceobj
, ifaceobjcurr
, vrf_table
)
310 vrf
= ifaceobj
.get_attr_value_first('vrf')
312 self
._query
_check
_vrf
_slave
(ifaceobj
, ifaceobjcurr
, vrf
)
314 self
.log_warn(str(e
))
316 def _query_running(self
, ifaceobjrunning
):
318 kind
= self
.ipcmd
.link_get_kind(ifaceobjrunning
.name
)
320 vrfdev_attrs
= self
.ipcmd
.link_get_linkinfo_attrs(ifaceobj
.name
)
322 running_table
= vrfdev_attrs
.get('table')
324 ifaceobjrunning
.update_config('vrf-table',
326 elif kind
== 'vrf_slave':
327 vrf
= self
.link_get_master(ifaceobjrunning
.name
)
329 ifaceobjrunning
.update_config('vrf', vrf
)
331 self
.log_warn(str(e
))
333 _run_ops
= {'pre-up' : _up
,
335 'query-running' : _query_running
,
336 'query-checkcurr' : _query_check
}
339 """ returns list of ops supported by this module """
340 return self
._run
_ops
.keys()
342 def _init_command_handlers(self
):
343 flags
= self
.get_flags()
345 self
.ipcmd
= iproute2(**flags
)
347 self
.bondcmd
= bondutil(**flags
)
349 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, **extra_args
):
350 """ run bond configuration on the interface object passed as argument
353 **ifaceobj** (object): iface object
355 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
359 **query_ifaceobj** (object): query check ifaceobject. This is only
360 valid when op is 'query-checkcurr'. It is an object same as
361 ifaceobj, but contains running attribute values and its config
362 status. The modules can use it to return queried running state
363 of interfaces. status is success if the running state is same
364 as user required state in ifaceobj. error otherwise.
366 op_handler
= self
._run
_ops
.get(operation
)
369 self
._init
_command
_handlers
()
370 if operation
== 'query-checkcurr':
371 op_handler(self
, ifaceobj
, query_ifaceobj
)
373 op_handler(self
, ifaceobj
)