]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdownaddons/bridgeutils.py
move ifupdown2/* .
[mirror_ifupdown2.git] / ifupdownaddons / bridgeutils.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 from ifupdown.iface import *
8 from utilsbase import *
9 import os
10 import re
11 import logging
12 from cache import *
13
14 class brctl(utilsBase):
15 """ This class contains helper functions to interact with the bridgeutils
16 commands """
17
18 _cache_fill_done = False
19
20 def __init__(self, *args, **kargs):
21 utilsBase.__init__(self, *args, **kargs)
22 if self.CACHE and not brctl._cache_fill_done:
23 self._bridge_fill()
24 brctl._cache_fill_done = True
25
26
27 def _bridge_get_mcattrs_from_sysfs(self, bridgename):
28 mcattrs = {}
29 mcattrmap = {'mclmc': 'multicast_last_member_count',
30 'mcrouter': 'multicast_router',
31 'mcsnoop' : 'multicast_snooping',
32 'mcsqc' : 'multicast_startup_query_count',
33 'mcqifaddr' : 'multicast_query_use_ifaddr',
34 'mcquerier' : 'multicast_querier',
35 'hashel' : 'hash_elasticity',
36 'hashmax' : 'hash_max',
37 'mclmi' : 'multicast_last_member_interval',
38 'mcmi' : 'multicast_membership_interval',
39 'mcqpi' : 'multicast_querier_interval',
40 'mcqi' : 'multicast_query_interval',
41 'mcqri' : 'multicast_query_response_interval',
42 'mcsqi' : 'multicast_startup_query_interval'}
43
44 mcattrsdivby100 = ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
45
46 for m, s in mcattrmap.items():
47 n = self.read_file_oneline('/sys/class/net/%s/bridge/%s'
48 %(bridgename, s))
49 if m in mcattrsdivby100:
50 try:
51 v = int(n) / 100
52 mcattrs[m] = str(v)
53 except Exception, e:
54 self.logger.warn('error getting mc attr %s (%s)'
55 %(m, str(e)))
56 pass
57 else:
58 mcattrs[m] = n
59 return mcattrs
60
61 def _bridge_attrs_fill(self, bridgename):
62 battrs = {}
63 bports = {}
64
65 brout = self.exec_command('/sbin/brctl showstp %s' %bridgename)
66 chunks = re.split(r'\n\n', brout, maxsplit=0, flags=re.MULTILINE)
67
68 try:
69 # Get all bridge attributes
70 broutlines = chunks[0].splitlines()
71 #battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
72 battrs['maxage'] = broutlines[4].split(
73 'bridge max age')[1].strip().replace('.00', '')
74 battrs['hello'] = broutlines[5].split(
75 'bridge hello time')[1].strip().replace('.00',
76 '')
77 battrs['fd'] = broutlines[6].split(
78 'bridge forward delay')[1].strip(
79 ).replace('.00', '')
80 battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename))
81
82 # XXX: comment this out until mc attributes become available
83 # with brctl again
84 #battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
85 #battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
86 #battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
87 #battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
88 #battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
89 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
90 #battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
91 except Exception, e:
92 self.logger.warn(str(e))
93 pass
94
95 linkCache.update_attrdict([bridgename, 'linkinfo'], battrs)
96
97 for cidx in range(1, len(chunks)):
98 bpout = chunks[cidx].lstrip('\n')
99 if not bpout or bpout[0] == ' ':
100 continue
101 bplines = bpout.splitlines()
102 pname = bplines[0].split()[0]
103 bportattrs = {}
104 try:
105 bportattrs['pathcost'] = bplines[2].split(
106 'path cost')[1].strip()
107 bportattrs['fdelay'] = bplines[4].split(
108 'forward delay timer')[1].strip()
109 bportattrs['mcrouter'] = self.read_file_oneline(
110 '/sys/class/net/%s/brport/multicast_router' %pname)
111 bportattrs['mcfl'] = self.read_file_oneline(
112 '/sys/class/net/%s/brport/multicast_fast_leave' %pname)
113
114 #bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
115 #bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
116 except Exception, e:
117 self.logger.warn(str(e))
118 pass
119 bports[pname] = bportattrs
120 linkCache.update_attrdict([bridgename, 'linkinfo', 'ports'], bports)
121
122 def _bridge_fill(self, bridgename=None, refresh=False):
123 try:
124 # if cache is already filled, return
125 linkCache.get_attr([bridgename, 'linkinfo', 'fd'])
126 return
127 except:
128 pass
129 if not bridgename:
130 brctlout = self.exec_command('/sbin/brctl show')
131 else:
132 brctlout = self.exec_command('/sbin/brctl show ' + bridgename)
133 if not brctlout:
134 return
135
136 for bline in brctlout.splitlines()[1:]:
137 bitems = bline.split()
138 if len(bitems) < 2:
139 continue
140 try:
141 linkCache.update_attrdict([bitems[0], 'linkinfo'],
142 {'stp' : bitems[2]})
143 except KeyError:
144 linkCache.update_attrdict([bitems[0]],
145 {'linkinfo' : {'stp' : bitems[2]}})
146 self._bridge_attrs_fill(bitems[0])
147
148 def _cache_get(self, attrlist, refresh=False):
149 try:
150 if self.DRYRUN:
151 return None
152 if self.CACHE:
153 if not self._cache_fill_done:
154 self._bridge_fill()
155 self._cache_fill_done = True
156 return linkCache.get_attr(attrlist)
157 if not refresh:
158 return linkCache.get_attr(attrlist)
159 self._bridge_fill(attrlist[0], refresh)
160 return linkCache.get_attr(attrlist)
161 except Exception, e:
162 self.logger.debug('_cache_get(%s) : [%s]'
163 %(str(attrlist), str(e)))
164 pass
165 return None
166
167 def _cache_check(self, attrlist, value, refresh=False):
168 try:
169 attrvalue = self._cache_get(attrlist, refresh)
170 if attrvalue and attrvalue == value:
171 return True
172 except Exception, e:
173 self.logger.debug('_cache_check(%s) : [%s]'
174 %(str(attrlist), str(e)))
175 pass
176 return False
177
178 def _cache_update(self, attrlist, value):
179 if self.DRYRUN: return
180 try:
181 linkCache.add_attr(attrlist, value)
182 except:
183 pass
184
185 def _cache_delete(self, attrlist):
186 if self.DRYRUN: return
187 try:
188 linkCache.del_attr(attrlist)
189 except:
190 pass
191
192 def _cache_invalidate(self):
193 if self.DRYRUN: return
194 linkCache.invalidate()
195
196 def create_bridge(self, bridgename):
197 if self.bridge_exists(bridgename):
198 return
199 self.exec_command('/sbin/brctl addbr %s' %bridgename)
200 self._cache_update([bridgename], {})
201
202 def delete_bridge(self, bridgename):
203 if not self.bridge_exists(bridgename):
204 return
205 self.exec_command('/sbin/brctl delbr %s' %bridgename)
206 self._cache_invalidate()
207
208 def add_bridge_port(self, bridgename, bridgeportname):
209 """ Add port to bridge """
210 ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
211 if ports and ports.get(bridgeportname):
212 return
213 self.exec_command('/sbin/brctl addif ' + bridgename + ' ' +
214 bridgeportname)
215 self._cache_update([bridgename, 'linkinfo', 'ports',
216 bridgeportname], {})
217
218 def delete_bridge_port(self, bridgename, bridgeportname):
219 """ Delete port from bridge """
220 ports = self._cache_get([bridgename, 'linkinfo', 'ports'])
221 if not ports or not ports.get(bridgeportname):
222 return
223 self.exec_command('/sbin/brctl delif ' + bridgename + ' ' +
224 bridgeportname)
225 self._cache_delete([bridgename, 'linkinfo', 'ports',
226 'bridgeportname'])
227
228 def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
229 portattrs = self._cache_get([bridgename, 'linkinfo',
230 'ports', bridgeportname])
231 if portattrs == None: portattrs = {}
232 for k, v in attrdict.iteritems():
233 if self.CACHE:
234 curval = portattrs.get(k)
235 if curval and curval == v:
236 continue
237 self.exec_command('/sbin/brctl set%s %s %s %s'
238 %(k, bridgename, bridgeportname, v))
239
240 def set_bridgeport_attr(self, bridgename, bridgeportname,
241 attrname, attrval):
242 if self._cache_check([bridgename, 'linkinfo', 'ports',
243 bridgeportname, attrname], attrval):
244 return
245 self.exec_command('/sbin/brctl set%s %s %s %s' %(attrname, bridgename,
246 bridgeportname, attrval))
247
248 def set_bridge_attrs(self, bridgename, attrdict):
249 for k, v in attrdict.iteritems():
250 if not v:
251 continue
252 if self._cache_check([bridgename, 'linkinfo', k], v):
253 continue
254 try:
255 self.exec_command('/sbin/brctl set%s %s %s'
256 %(k, bridgename, v))
257 except Exception, e:
258 self.logger.warn('%s: %s' %(bridgename, str(e)))
259 pass
260
261 def set_bridge_attr(self, bridgename, attrname, attrval):
262 if self._cache_check([bridgename, 'linkinfo', attrname], attrval):
263 return
264 self.exec_command('/sbin/brctl set%s %s %s'
265 %(attrname, bridgename, attrval))
266
267 def get_bridge_attrs(self, bridgename):
268 return self._cache_get([bridgename, 'linkinfo'])
269
270 def get_bridgeport_attrs(self, bridgename, bridgeportname):
271 return self._cache_get([bridgename, 'linkinfo', 'ports',
272 bridgeportname])
273
274 def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
275 return self._cache_get([bridgename, 'linkinfo', 'ports',
276 bridgeportname, attrname])
277
278 def set_stp(self, bridge, stp_state):
279 self.exec_command('/sbin/brctl stp ' + bridge + ' ' + stp_state)
280
281 def get_stp(self, bridge):
282 sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' %bridge
283 if not os.path.exists(sysfs_stpstate):
284 return 'error'
285 stpstate = self.read_file_oneline(sysfs_stpstate)
286 if not stpstate:
287 return 'error'
288 try:
289 if int(stpstate) > 0:
290 return 'yes'
291 elif int(stpstate) == 0:
292 return 'no'
293 except:
294 return 'unknown'
295
296 def conv_value_to_user(self, str):
297 try:
298 ret = int(str) / 100
299 except:
300 return None
301 finally:
302 return '%d' %ret
303
304 def read_value_from_sysfs(self, filename, preprocess_func):
305 value = self.read_file_oneline(filename)
306 if not value:
307 return None
308 return preprocess_func(value)
309
310 def set_ageing(self, bridge, ageing):
311 self.exec_command('/sbin/brctl setageing ' + bridge + ' ' + ageing)
312
313 def get_ageing(self, bridge):
314 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
315 %bridge, self.conv_value_to_user)
316
317 def set_bridgeprio(self, bridge, bridgeprio):
318 self.exec_command('/sbin/brctl setbridgeprio ' + bridge + ' ' +
319 bridgeprio)
320
321 def get_bridgeprio(self, bridge):
322 return self.read_file_oneline(
323 '/sys/class/net/%s/bridge/priority' %bridge)
324
325 def set_fd(self, bridge, fd):
326 self.exec_command('/sbin/brctl setfd ' + bridge + ' ' + fd)
327
328 def get_fd(self, bridge):
329 return self.read_value_from_sysfs(
330 '/sys/class/net/%s/bridge/forward_delay'
331 %bridge, self.conv_value_to_user)
332
333 def set_gcint(self, bridge, gcint):
334 #cmd = '/sbin/brctl setgcint ' + bridge + ' ' + gcint
335 raise Exception('set_gcint not implemented')
336
337 def set_hello(self, bridge, hello):
338 self.exec_command('/sbin/brctl sethello ' + bridge + ' ' + hello)
339
340 def get_hello(self, bridge):
341 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
342 %bridge, self.conv_value_to_user)
343
344 def set_maxage(self, bridge, maxage):
345 self.exec_command('/sbin/brctl setmaxage ' + bridge + ' ' + maxage)
346
347 def get_maxage(self, bridge):
348 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
349 %bridge, self.conv_value_to_user)
350
351 def set_pathcost(self, bridge, port, pathcost):
352 self.exec_command('/sbin/brctl setpathcost %s' %bridge + ' %s' %port +
353 ' %s' %pathcost)
354
355 def get_pathcost(self, bridge, port):
356 return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
357 %port)
358
359 def set_portprio(self, bridge, port, prio):
360 self.exec_command('/sbin/brctl setportprio %s' %bridge + ' %s' %port +
361 ' %s' %prio)
362
363 def get_portprio(self, bridge, port):
364 return self.read_file_oneline('/sys/class/net/%s/brport/priority'
365 %port)
366
367 def set_hashmax(self, bridge, hashmax):
368 self.exec_command('/sbin/brctl sethashmax %s' %bridge + ' %s' %hashmax)
369
370 def get_hashmax(self, bridge):
371 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
372 %bridge)
373
374 def set_hashel(self, bridge, hashel):
375 self.exec_command('/sbin/brctl sethashel %s' %bridge + ' %s' %hashel)
376
377 def get_hashel(self, bridge):
378 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
379 %bridge)
380
381 def set_mclmc(self, bridge, mclmc):
382 self.exec_command('/sbin/brctl setmclmc %s' %bridge + ' %s' %mclmc)
383
384 def get_mclmc(self, bridge):
385 return self.read_file_oneline(
386 '/sys/class/net/%s/bridge/multicast_last_member_count'
387 %bridge)
388
389 def set_mcrouter(self, bridge, mcrouter):
390 self.exec_command('/sbin/brctl setmcrouter %s' %bridge +
391 ' %s' %mcrouter)
392
393 def get_mcrouter(self, bridge):
394 return self.read_file_oneline(
395 '/sys/class/net/%s/bridge/multicast_router' %bridge)
396
397 def set_mcsnoop(self, bridge, mcsnoop):
398 self.exec_command('/sbin/brctl setmcsnoop %s' %bridge +
399 ' %s' %mcsnoop)
400
401 def get_mcsnoop(self, bridge):
402 return self.read_file_oneline(
403 '/sys/class/net/%s/bridge/multicast_snooping' %bridge)
404
405 def set_mcsqc(self, bridge, mcsqc):
406 self.exec_command('/sbin/brctl setmcsqc %s' %bridge +
407 ' %s' %mcsqc)
408
409 def get_mcsqc(self, bridge):
410 return self.read_file_oneline(
411 '/sys/class/net/%s/bridge/multicast_startup_query_count'
412 %bridge)
413
414 def set_mcqifaddr(self, bridge, mcqifaddr):
415 self.exec_command('/sbin/brctl setmcqifaddr %s' %bridge +
416 ' %s' %mcqifaddr)
417
418 def get_mcqifaddr(self, bridge):
419 return self.read_file_oneline(
420 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
421 %bridge)
422
423 def set_mcquerier(self, bridge, mcquerier):
424 self.exec_command('/sbin/brctl setmcquerier %s' %bridge +
425 ' %s' %mcquerier)
426
427 def get_mcquerier(self, bridge):
428 return self.read_file_oneline(
429 '/sys/class/net/%s/bridge/multicast_querier' %bridge)
430
431 def set_mcqv4src(self, bridge, vlan, mcquerier):
432 if vlan == 0 or vlan > 4095:
433 self.logger.warn('mcqv4src vlan \'%d\' invalid range' %vlan)
434 return
435
436 ip = mcquerier.split('.')
437 if len(ip) != 4:
438 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
439 return
440 for k in ip:
441 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
442 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' %mcquerier)
443 return
444
445 self.exec_command('/sbin/brctl setmcqv4src %s' %bridge +
446 ' %d %s' %(vlan, mcquerier))
447
448 def del_mcqv4src(self, bridge, vlan):
449 self.exec_command('/sbin/brctl delmcqv4src %s %d' %(bridge, vlan))
450
451 def get_mcqv4src(self, bridge, vlan=None):
452 mcqv4src = {}
453 mcqout = self.exec_command('/sbin/brctl showmcqv4src %s' %bridge)
454 if not mcqout: return None
455 mcqlines = mcqout.splitlines()
456 for l in mcqlines[1:]:
457 l=l.strip()
458 k, d, v = l.split('\t')
459 if not k or not v:
460 continue
461 mcqv4src[k] = v
462 if vlan:
463 return mcqv4src.get(vlan)
464 return mcqv4src
465
466 def set_mclmi(self, bridge, mclmi):
467 self.exec_command('/sbin/brctl setmclmi %s' %bridge +
468 ' %s' %mclmi)
469
470 def get_mclmi(self, bridge):
471 return self.read_file_oneline(
472 '/sys/class/net/%s/bridge/multicast_last_member_interval'
473 %bridge)
474
475 def set_mcmi(self, bridge, mcmi):
476 self.exec_command('/sbin/brctl setmcmi %s' %bridge +
477 ' %s' %mcmi)
478
479 def get_mcmi(self, bridge):
480 return self.read_file_oneline(
481 '/sys/class/net/%s/bridge/multicast_membership_interval'
482 %bridge)
483
484 def bridge_exists(self, bridge):
485 return os.path.exists('/sys/class/net/%s/bridge' %bridge)
486
487 def is_bridge_port(self, ifacename):
488 return os.path.exists('/sys/class/net/%s/brport' %ifacename)
489
490 def bridge_port_exists(self, bridge, bridgeportname):
491 try:
492 return os.path.exists('/sys/class/net/%s/brif/%s'
493 %(bridge, bridgeportname))
494 except Exception:
495 return False
496
497 def get_bridge_ports(self, bridgename):
498 try:
499 return os.listdir('/sys/class/net/%s/brif/' %bridgename)
500 except:
501 return []