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