]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/bridge.py
Merge branch 'release-2.5' into CumulusLinux-2.5_br
[mirror_ifupdown2.git] / addons / bridge.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 sets import Set
8 from ifupdown.iface import *
9 from ifupdownaddons.modulebase import moduleBase
10 from ifupdownaddons.bridgeutils import brctl
11 from ifupdownaddons.iproute2 import iproute2
12 from collections import Counter
13 import ifupdown.rtnetlink_api as rtnetlink_api
14 import itertools
15 import re
16 import time
17
18 class bridge(moduleBase):
19 """ ifupdown2 addon module to configure linux bridges """
20
21 _modinfo = { 'mhelp' : 'Bridge configuration module. Supports both ' +
22 'vlan aware and non vlan aware bridges. For the vlan ' +
23 'aware bridge, the port specific attributes must be ' +
24 'specified under the port. And for vlan unaware bridge ' +
25 'port specific attributes must be specified under the ' +
26 'bridge.',
27 'attrs' : {
28 'bridge-vlan-aware' :
29 {'help' : 'vlan aware bridge. Setting this ' +
30 'attribute to yes enables vlan filtering' +
31 ' on the bridge',
32 'example' : ['bridge-vlan-aware yes/no']},
33 'bridge-ports' :
34 {'help' : 'bridge ports',
35 'required' : True,
36 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
37 'bridge-ports glob swp1-3.100',
38 'bridge-ports regex (swp[1|2|3].100)']},
39 'bridge-stp' :
40 {'help': 'bridge-stp yes/no',
41 'example' : ['bridge-stp no'],
42 'validvals' : ['yes', 'on', 'off', 'no'],
43 'default' : 'no'},
44 'bridge-bridgeprio' :
45 {'help': 'bridge priority',
46 'example' : ['bridge-bridgeprio 32768'],
47 'default' : '32768'},
48 'bridge-ageing' :
49 {'help': 'bridge ageing',
50 'example' : ['bridge-ageing 300'],
51 'default' : '300'},
52 'bridge-fd' :
53 { 'help' : 'bridge forward delay',
54 'example' : ['bridge-fd 15'],
55 'default' : '15'},
56 'bridge-gcint' :
57 # XXX: recheck values
58 { 'help' : 'bridge garbage collection interval in secs',
59 'example' : ['bridge-gcint 4'],
60 'default' : '4'},
61 'bridge-hello' :
62 { 'help' : 'bridge set hello time',
63 'example' : ['bridge-hello 2'],
64 'default' : '2'},
65 'bridge-maxage' :
66 { 'help' : 'bridge set maxage',
67 'example' : ['bridge-maxage 20'],
68 'default' : '20'},
69 'bridge-pathcosts' :
70 { 'help' : 'bridge set port path costs',
71 'example' : ['bridge-pathcosts swp1=100 swp2=100'],
72 'default' : '100'},
73 'bridge-portprios' :
74 { 'help' : 'bridge port prios',
75 'example' : ['bridge-portprios swp1=32 swp2=32'],
76 'default' : '32'},
77 'bridge-mclmc' :
78 { 'help' : 'set multicast last member count',
79 'example' : ['bridge-mclmc 2'],
80 'default' : '2'},
81 'bridge-mcrouter' :
82 { 'help' : 'set multicast router',
83 'default' : '1',
84 'example' : ['bridge-mcrouter 1']},
85 'bridge-mcsnoop' :
86 { 'help' : 'set multicast snooping',
87 'default' : '1',
88 'example' : ['bridge-mcsnoop 1']},
89 'bridge-mcsqc' :
90 { 'help' : 'set multicast startup query count',
91 'default' : '2',
92 'example' : ['bridge-mcsqc 2']},
93 'bridge-mcqifaddr' :
94 { 'help' : 'set multicast query to use ifaddr',
95 'default' : '0',
96 'example' : ['bridge-mcqifaddr 0']},
97 'bridge-mcquerier' :
98 { 'help' : 'set multicast querier',
99 'default' : '0',
100 'example' : ['bridge-mcquerier 0']},
101 'bridge-hashel' :
102 { 'help' : 'set hash elasticity',
103 'default' : '4096',
104 'example' : ['bridge-hashel 4096']},
105 'bridge-hashmax' :
106 { 'help' : 'set hash max',
107 'default' : '4096',
108 'example' : ['bridge-hashmax 4096']},
109 'bridge-mclmi' :
110 { 'help' : 'set multicast last member interval (in secs)',
111 'default' : '1',
112 'example' : ['bridge-mclmi 1']},
113 'bridge-mcmi' :
114 { 'help' : 'set multicast membership interval (in secs)',
115 'default' : '260',
116 'example' : ['bridge-mcmi 260']},
117 'bridge-mcqpi' :
118 { 'help' : 'set multicast querier interval (in secs)',
119 'default' : '255',
120 'example' : ['bridge-mcqpi 255']},
121 'bridge-mcqi' :
122 { 'help' : 'set multicast query interval (in secs)',
123 'default' : '125',
124 'example' : ['bridge-mcqi 125']},
125 'bridge-mcqri' :
126 { 'help' : 'set multicast query response interval (in secs)',
127 'default' : '10',
128 'example' : ['bridge-mcqri 10']},
129 'bridge-mcsqi' :
130 { 'help' : 'set multicast startup query interval (in secs)',
131 'default' : '31',
132 'example' : ['bridge-mcsqi 31']},
133 'bridge-mcqv4src' :
134 { 'help' : 'set per VLAN v4 multicast querier source address',
135 'compat' : True,
136 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
137 'bridge-portmcrouter' :
138 { 'help' : 'set port multicast routers',
139 'default' : '1',
140 'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
141 'under the port: bridge-portmcrouter 1']},
142 'bridge-portmcfl' :
143 { 'help' : 'port multicast fast leave.',
144 'default' : '0',
145 'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
146 'under the port: bridge-portmcfl 0']},
147 'bridge-waitport' :
148 { 'help' : 'wait for a max of time secs for the' +
149 ' specified ports to become available,' +
150 'if no ports are specified then those' +
151 ' specified on bridge-ports will be' +
152 ' used here. Specifying no ports here ' +
153 'should not be used if we are using ' +
154 'regex or \"all\" on bridge_ports,' +
155 'as it wouldnt work.',
156 'default' : '0',
157 'example' : ['bridge-waitport 4 swp1 swp2']},
158 'bridge-maxwait' :
159 { 'help' : 'forces to time seconds the maximum time ' +
160 'that the Debian bridge setup scripts will ' +
161 'wait for the bridge ports to get to the ' +
162 'forwarding status, doesn\'t allow factional ' +
163 'part. If it is equal to 0 then no waiting' +
164 ' is done',
165 'default' : '0',
166 'example' : ['bridge-maxwait 3']},
167 'bridge-vids' :
168 { 'help' : 'bridge port vids. Can be specified ' +
169 'under the bridge or under the port. ' +
170 'If specified under the bridge the ports ' +
171 'inherit it unless overridden by a ' +
172 'bridge-vids attribuet under the port',
173 'example' : ['bridge-vids 4000',
174 'bridge-vids 2000 2200-3000']},
175 'bridge-pvid' :
176 { 'help' : 'bridge port pvid. Must be specified under' +
177 ' the bridge port',
178 'example' : ['bridge-pvid 1']},
179 'bridge-access' :
180 { 'help' : 'bridge port access vlan. Must be ' +
181 'specified under the bridge port',
182 'example' : ['bridge-access 300']},
183 'bridge-port-vids' :
184 { 'help' : 'bridge vlans',
185 'compat': True,
186 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
187 'bridge-port-pvids' :
188 { 'help' : 'bridge port vlans',
189 'compat': True,
190 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
191 }}
192
193 # declare some ifaceobj priv_flags.
194 # XXX: This assumes that the priv_flags is owned by this module
195 # which it is not.
196 _BRIDGE_PORT_PROCESSED = 0x1
197
198 def __init__(self, *args, **kargs):
199 moduleBase.__init__(self, *args, **kargs)
200 self.ipcmd = None
201 self.brctlcmd = None
202 self._running_vidinfo = {}
203 self._running_vidinfo_valid = False
204 self._resv_vlan_range = self._get_reserved_vlan_range()
205 self.logger.debug('%s: using reserved vlan range %s'
206 %(self.__class__.__name__, str(self._resv_vlan_range)))
207
208 def _is_bridge(self, ifaceobj):
209 if ifaceobj.get_attr_value_first('bridge-ports'):
210 return True
211 return False
212
213 def _is_bridge_port(self, ifaceobj):
214 if self.brctlcmd.is_bridge_port(ifaceobj.name):
215 return True
216 return False
217
218 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
219 if not self._is_bridge(ifaceobj):
220 return None
221 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
222 ifaceobj.link_type = ifaceLinkType.LINK_MASTER
223 return self.parse_port_list(ifaceobj.get_attr_value_first(
224 'bridge-ports'), ifacenames_all)
225
226 def get_dependent_ifacenames_running(self, ifaceobj):
227 self._init_command_handlers()
228 if not self.brctlcmd.bridge_exists(ifaceobj.name):
229 return None
230 return self.brctlcmd.get_bridge_ports(ifaceobj.name)
231
232 def _get_bridge_port_list(self, ifaceobj):
233
234 # port list is also available in the previously
235 # parsed dependent list. Use that if available, instead
236 # of parsing port expr again
237 port_list = ifaceobj.lowerifaces
238 if port_list:
239 return port_list
240 ports = ifaceobj.get_attr_value_first('bridge-ports')
241 if ports:
242 return self.parse_port_list(ports)
243 else:
244 return None
245
246 def _process_bridge_waitport(self, ifaceobj, portlist):
247 waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
248 if not waitport_value: return
249 try:
250 waitportvals = re.split(r'[\s\t]\s*', waitport_value, 1)
251 if not waitportvals: return
252 try:
253 waitporttime = int(waitportvals[0])
254 except:
255 self.log_warn('%s: invalid waitport value \'%s\''
256 %(ifaceobj.name, waitporttime))
257 return
258 if waitporttime <= 0: return
259 try:
260 waitportlist = self.parse_port_list(waitportvals[1])
261 except IndexError, e:
262 # ignore error and use all bridge ports
263 waitportlist = portlist
264 pass
265 if not waitportlist: return
266 self.logger.info('%s: waiting for ports %s to exist ...'
267 %(ifaceobj.name, str(waitportlist)))
268 starttime = time.time()
269 while ((time.time() - starttime) < waitporttime):
270 if all([False for p in waitportlist
271 if not self.ipcmd.link_exists(p)]):
272 break;
273 time.sleep(1)
274 except Exception, e:
275 self.log_warn('%s: unable to process waitport: %s'
276 %(ifaceobj.name, str(e)))
277
278 def _add_ports(self, ifaceobj):
279 bridgeports = self._get_bridge_port_list(ifaceobj)
280 runningbridgeports = []
281
282 self.ipcmd.batch_start()
283 self._process_bridge_waitport(ifaceobj, bridgeports)
284 self.ipcmd.batch_start()
285 # Delete active ports not in the new port list
286 if not self.PERFMODE:
287 runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
288 if runningbridgeports:
289 for bport in runningbridgeports:
290 if not bridgeports or bport not in bridgeports:
291 self.ipcmd.link_set(bport, 'nomaster')
292 self.ipcmd.link_set(bport, 'down')
293 else:
294 runningbridgeports = []
295 if not bridgeports:
296 self.ipcmd.batch_commit()
297 return
298 err = 0
299 for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
300 try:
301 if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
302 self.log_warn('%s: bridge port %s does not exist'
303 %(ifaceobj.name, bridgeport))
304 err += 1
305 continue
306 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
307 self.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport +
308 '/disable_ipv6', '1')
309 self.ipcmd.addr_flush(bridgeport)
310 except Exception, e:
311 self.logger.error(str(e))
312 pass
313 self.ipcmd.batch_commit()
314 if err:
315 self.log_error('bridge configuration failed (missing ports)')
316
317 def _process_bridge_maxwait(self, ifaceobj, portlist):
318 maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
319 if not maxwait: return
320 try:
321 maxwait = int(maxwait)
322 except:
323 self.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj.name,
324 maxwait))
325 return
326 if not maxwait: return
327 self.logger.info('%s: waiting for ports to go to fowarding state ..'
328 %ifaceobj.name)
329 try:
330 starttime = time.time()
331 while ((time.time() - starttime) < maxwait):
332 if all([False for p in portlist
333 if self.read_file_oneline(
334 '/sys/class/net/%s/brif/%s/state'
335 %(ifaceobj.name, p)) != '3']):
336 break;
337 time.sleep(1)
338 except Exception, e:
339 self.log_warn('%s: unable to process maxwait: %s'
340 %(ifaceobj.name, str(e)))
341
342 def _ints_to_ranges(self, ints):
343 for a, b in itertools.groupby(enumerate(ints), lambda (x, y): y - x):
344 b = list(b)
345 yield b[0][1], b[-1][1]
346
347 def _ranges_to_ints(self, rangelist):
348 """ returns expanded list of integers given set of string ranges
349 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
350 """
351 result = []
352 for part in rangelist:
353 if '-' in part:
354 a, b = part.split('-')
355 a, b = int(a), int(b)
356 result.extend(range(a, b + 1))
357 else:
358 a = int(part)
359 result.append(a)
360 return result
361
362 def _diff_vids(self, vids1, vids2):
363 vids_to_add = None
364 vids_to_del = None
365
366 vids1_ints = self._ranges_to_ints(vids1)
367 vids2_ints = self._ranges_to_ints(vids2)
368 vids1_diff = Set(vids1_ints).difference(vids2_ints)
369 vids2_diff = Set(vids2_ints).difference(vids1_ints)
370 if vids1_diff:
371 vids_to_add = ['%d' %start if start == end else '%d-%d' %(start, end)
372 for start, end in self._ints_to_ranges(vids1_diff)]
373 if vids2_diff:
374 vids_to_del = ['%d' %start if start == end else '%d-%d' %(start, end)
375 for start, end in self._ints_to_ranges(vids2_diff)]
376 return (vids_to_del, vids_to_add)
377
378 def _compare_vids(self, vids1, vids2):
379 """ Returns true if the vids are same else return false """
380
381 vids1_ints = self._ranges_to_ints(vids1)
382 vids2_ints = self._ranges_to_ints(vids2)
383 if Set(vids1_ints).symmetric_difference(vids2_ints):
384 return False
385 else:
386 return True
387
388 def _set_bridge_mcqv4src_compat(self, ifaceobj):
389 #
390 # Sets old style igmp querier
391 #
392 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
393 if attrval:
394 running_mcqv4src = {}
395 if not self.PERFMODE:
396 running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name)
397 mcqs = {}
398 srclist = attrval.split()
399 for s in srclist:
400 k, v = s.split('=')
401 mcqs[k] = v
402
403 k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
404 for v in k_to_del:
405 self.brctlcmd.del_mcqv4src(ifaceobj.name, v)
406 for v in mcqs.keys():
407 self.brctlcmd.set_mcqv4src(ifaceobj.name, v, mcqs[v])
408
409 def _get_running_vidinfo(self):
410 if self._running_vidinfo_valid:
411 return self._running_vidinfo
412 self._running_vidinfo = {}
413 if not self.PERFMODE:
414 self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
415 self._running_vidinfo_valid = True
416 return self._running_vidinfo
417
418 def _flush_running_vidinfo(self):
419 self._running_vidinfo = {}
420 self._running_vidinfo_valid = False
421
422 def _set_bridge_vidinfo_compat(self, ifaceobj):
423 #
424 # Supports old style vlan vid info format
425 # for compatibility
426 #
427
428 # Handle bridge vlan attrs
429 running_vidinfo = self._get_running_vidinfo()
430
431 # Install pvids
432 attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
433 if attrval:
434 portlist = self.parse_port_list(attrval)
435 if not portlist:
436 self.log_warn('%s: could not parse \'%s %s\''
437 %(ifaceobj.name, attrname, attrval))
438 return
439 for p in portlist:
440 try:
441 (port, pvid) = p.split('=')
442 running_pvid = running_vidinfo.get(port, {}).get('pvid')
443 if running_pvid:
444 if running_pvid == pvid:
445 continue
446 else:
447 self.ipcmd.bridge_port_pvid_del(port, running_pvid)
448 self.ipcmd.bridge_port_pvid_add(port, pvid)
449 except Exception, e:
450 self.log_warn('%s: failed to set pvid `%s` (%s)'
451 %(ifaceobj.name, p, str(e)))
452
453 # install port vids
454 attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
455 if attrval:
456 portlist = self.parse_port_list(attrval)
457 if not portlist:
458 self.log_warn('%s: could not parse \'%s %s\''
459 %(ifaceobj.name, attrname, attrval))
460 return
461 for p in portlist:
462 try:
463 (port, val) = p.split('=')
464 vids = val.split(',')
465 if running_vidinfo.get(port):
466 (vids_to_del, vids_to_add) = \
467 self._diff_vids(vids,
468 running_vidinfo.get(port).get('vlan'))
469 if vids_to_del:
470 self.ipcmd.bridge_port_vids_del(port, vids_to_del)
471 if vids_to_add:
472 self.ipcmd.bridge_port_vids_add(port, vids_to_add)
473 else:
474 self.ipcmd.bridge_port_vids_add(port, vids)
475 except Exception, e:
476 self.log_warn('%s: failed to set vid `%s` (%s)'
477 %(ifaceobj.name, p, str(e)))
478
479 # install vids
480 # XXX: Commenting out this code for now because it was decided
481 # that this is not needed
482 #attrval = ifaceobj.get_attr_value_first('bridge-vids')
483 #if attrval:
484 # vids = re.split(r'[\s\t]\s*', attrval)
485 # if running_vidinfo.get(ifaceobj.name):
486 # (vids_to_del, vids_to_add) = \
487 # self._diff_vids(vids,
488 # running_vidinfo.get(ifaceobj.name).get('vlan'))
489 # if vids_to_del:
490 # self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
491 # if vids_to_add:
492 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
493 # else:
494 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
495 #else:
496 # running_vids = running_vidinfo.get(ifaceobj.name)
497 # if running_vids:
498 # self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
499
500 def _apply_bridge_settings(self, ifaceobj):
501 try:
502 stp = ifaceobj.get_attr_value_first('bridge-stp')
503 if stp:
504 self.brctlcmd.set_stp(ifaceobj.name, stp)
505 else:
506 # If stp not specified and running stp state on, set it to off
507 running_stp_state = self.read_file_oneline(
508 '/sys/class/net/%s/bridge/stp_state' %ifaceobj.name)
509 if running_stp_state and running_stp_state != '0':
510 self.brctlcmd.set_stp(ifaceobj.name, 'no')
511
512 if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes':
513 self.write_file('/sys/class/net/%s/bridge/vlan_filtering'
514 %ifaceobj.name, '1')
515 # Use the brctlcmd bulk set method: first build a dictionary
516 # and then call set
517 bridgeattrs = { k:v for k,v in
518 {'ageing' :
519 ifaceobj.get_attr_value_first('bridge-ageing'),
520 'bridgeprio' :
521 ifaceobj.get_attr_value_first(
522 'bridge-bridgeprio'),
523 'fd' :
524 ifaceobj.get_attr_value_first('bridge-fd'),
525 'gcint' :
526 ifaceobj.get_attr_value_first('bridge-gcint'),
527 'hello' :
528 ifaceobj.get_attr_value_first('bridge-hello'),
529 'maxage' :
530 ifaceobj.get_attr_value_first('bridge-maxage'),
531 'mclmc' :
532 ifaceobj.get_attr_value_first('bridge-mclmc'),
533 'mcrouter' :
534 ifaceobj.get_attr_value_first(
535 'bridge-mcrouter'),
536 'mcsnoop' :
537 ifaceobj.get_attr_value_first('bridge-mcsnoop'),
538 'mcsqc' :
539 ifaceobj.get_attr_value_first('bridge-mcsqc'),
540 'mcqifaddr' :
541 ifaceobj.get_attr_value_first(
542 'bridge-mcqifaddr'),
543 'mcquerier' :
544 ifaceobj.get_attr_value_first(
545 'bridge-mcquerier'),
546 'hashel' :
547 ifaceobj.get_attr_value_first('bridge-hashel'),
548 'hashmax' :
549 ifaceobj.get_attr_value_first('bridge-hashmax'),
550 'mclmi' :
551 ifaceobj.get_attr_value_first('bridge-mclmi'),
552 'mcmi' :
553 ifaceobj.get_attr_value_first('bridge-mcmi'),
554 'mcqpi' :
555 ifaceobj.get_attr_value_first('bridge-mcqpi'),
556 'mcqi' :
557 ifaceobj.get_attr_value_first('bridge-mcqi'),
558 'mcqri' :
559 ifaceobj.get_attr_value_first('bridge-mcqri'),
560 'mcsqi' :
561 ifaceobj.get_attr_value_first('bridge-mcsqi')
562 }.items()
563 if v }
564 if bridgeattrs:
565 self.brctlcmd.set_bridge_attrs(ifaceobj.name, bridgeattrs)
566 portattrs = {}
567 for attrname, dstattrname in {'bridge-pathcosts' : 'pathcost',
568 'bridge-portprios' : 'portprio',
569 'bridge-portmcrouter' : 'portmcrouter',
570 'bridge-portmcfl' : 'portmcfl'}.items():
571 attrval = ifaceobj.get_attr_value_first(attrname)
572 if not attrval:
573 continue
574 portlist = self.parse_port_list(attrval)
575 if not portlist:
576 self.log_warn('%s: could not parse \'%s %s\''
577 %(ifaceobj.name, attrname, attrval))
578 continue
579 for p in portlist:
580 try:
581 (port, val) = p.split('=')
582 if not portattrs.get(port):
583 portattrs[port] = {}
584 portattrs[port].update({dstattrname : val})
585 except Exception, e:
586 self.log_warn('%s: could not parse %s (%s)'
587 %(ifaceobj.name, attrname, str(e)))
588 for port, attrdict in portattrs.iteritems():
589 self.brctlcmd.set_bridgeport_attrs(ifaceobj.name, port,
590 attrdict)
591 self._set_bridge_vidinfo_compat(ifaceobj)
592
593 self._set_bridge_mcqv4src_compat(ifaceobj)
594
595 self._process_bridge_maxwait(ifaceobj,
596 self._get_bridge_port_list(ifaceobj))
597 except Exception, e:
598 self.log_warn(str(e))
599
600 def _check_vids(self, ifaceobj, vids):
601 ret = True
602 for v in vids:
603 if '-' in v:
604 va, vb = v.split('-')
605 va, vb = int(va), int(vb)
606 if (self._handle_reserved_vlan(va, ifaceobj.name) or
607 self._handle_reserved_vlan(vb, ifaceobj.name)):
608 ret = False
609 else:
610 va = int(v)
611 if self._handle_reserved_vlan(va, ifaceobj.name):
612 ret = False
613 return ret
614
615 def _apply_bridge_vids(self, bportifaceobj, vids, running_vids, isbridge):
616 try:
617 if not self._check_vids(bportifaceobj, vids):
618 return
619 if running_vids:
620 (vids_to_del, vids_to_add) = \
621 self._diff_vids(vids, running_vids)
622 if vids_to_del:
623 self.ipcmd.bridge_vids_del(bportifaceobj.name,
624 vids_to_del, isbridge)
625 if vids_to_add:
626 self.ipcmd.bridge_vids_add(bportifaceobj.name,
627 vids_to_add, isbridge)
628 else:
629 self.ipcmd.bridge_vids_add(bportifaceobj.name, vids, isbridge)
630 except Exception, e:
631 self.log_warn('%s: failed to set vid `%s` (%s)'
632 %(bportifaceobj.name, str(vids), str(e)))
633
634 def _apply_bridge_port_pvids(self, bportifaceobj, pvid, running_pvid):
635 # Install pvids
636 try:
637 if running_pvid:
638 if running_pvid != pvid:
639 self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
640 running_pvid)
641 self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
642 else:
643 self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
644 except Exception, e:
645 self.log_warn('%s: failed to set pvid `%s` (%s)'
646 %(bportifaceobj.name, pvid, str(e)))
647
648 def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
649 bridge_vids=None,
650 bridge_pvid=None):
651 running_vidinfo = self._get_running_vidinfo()
652 vids = None
653 pvids = None
654 bport_access = bportifaceobj.get_attr_value_first('bridge-access')
655 if bport_access:
656 vids = re.split(r'[\s\t]\s*', bport_access)
657 pvids = vids
658 else:
659 bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
660 if bport_vids:
661 vids = re.split(r'[\s\t,]\s*', bport_vids)
662
663 bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
664 if bport_pvids:
665 pvids = re.split(r'[\s\t]\s*', bport_pvids)
666
667 if pvids:
668 self._apply_bridge_port_pvids(bportifaceobj, pvids[0],
669 running_vidinfo.get(bportifaceobj.name, {}).get('pvid'))
670 elif bridge_pvid:
671 self._apply_bridge_port_pvids(bportifaceobj,
672 bridge_pvid, running_vidinfo.get(bportifaceobj.name,
673 {}).get('pvid'))
674 # XXX: default pvid is already one
675 #else:
676 # self._apply_bridge_port_pvids(bportifaceobj,
677 # '1', running_vidinfo.get(bportifaceobj.name,
678 # {}).get('pvid'))
679
680 if vids:
681 self._apply_bridge_vids(bportifaceobj, vids,
682 running_vidinfo.get(bportifaceobj.name,
683 {}).get('vlan'), False)
684 elif bridge_vids:
685 self._apply_bridge_vids(bportifaceobj,
686 bridge_vids, running_vidinfo.get(
687 bportifaceobj.name, {}).get('vlan'), False)
688
689
690 def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
691 bridgeifaceobj=None):
692 if not bridgename and bridgeifaceobj:
693 bridgename = bridgeifaceobj.name
694 # Set other stp and igmp attributes
695 portattrs = {}
696 for attrname, dstattrname in {
697 'bridge-pathcosts' : 'pathcost',
698 'bridge-portprios' : 'portprio',
699 'bridge-portmcrouter' : 'portmcrouter',
700 'bridge-portmcfl' : 'portmcfl'}.items():
701 attrval = bportifaceobj.get_attr_value_first(attrname)
702 if not attrval:
703 # Check if bridge has that attribute
704 #if bridgeifaceobj:
705 # attrval = bridgeifaceobj.get_attr_value_first(attrname)
706 # if not attrval:
707 # continue
708 #else:
709 continue
710 portattrs[dstattrname] = attrval
711 try:
712 self.brctlcmd.set_bridgeport_attrs(bridgename,
713 bportifaceobj.name, portattrs)
714 except Exception, e:
715 self.log_warn(str(e))
716
717 def _apply_bridge_port_settings_all(self, ifaceobj,
718 ifaceobj_getfunc=None):
719 bridge_vlan_aware = ifaceobj.get_attr_value_first(
720 'bridge-vlan-aware')
721 if bridge_vlan_aware and bridge_vlan_aware == 'yes':
722 bridge_vlan_aware = True
723 else:
724 bridge_vlan_aware = False
725
726 if (ifaceobj.get_attr_value_first('bridge-port-vids') and
727 ifaceobj.get_attr_value_first('bridge-port-pvids')):
728 # Old style bridge port vid info
729 # skip new style setting on ports
730 return
731 self.logger.info('%s: applying bridge configuration '
732 %ifaceobj.name + 'specific to ports')
733
734 bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
735 if bridge_vids:
736 bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
737 else:
738 bridge_vids = None
739
740 bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
741 if bridge_pvid:
742 bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)[0]
743 else:
744 bridge_pvid = None
745
746 bridgeports = self._get_bridge_port_list(ifaceobj)
747 if not bridgeports:
748 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
749 return
750 for bport in bridgeports:
751 # Use the brctlcmd bulk set method: first build a dictionary
752 # and then call set
753 if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
754 self.logger.info('%s: skipping bridge config' %ifaceobj.name +
755 ' for port %s (missing port)' %bport)
756 continue
757 self.logger.info('%s: processing bridge config for port %s'
758 %(ifaceobj.name, bport))
759 bportifaceobjlist = ifaceobj_getfunc(bport)
760 if not bportifaceobjlist:
761 continue
762 for bportifaceobj in bportifaceobjlist:
763 # Dont process bridge port if it already has been processed
764 if bportifaceobj.priv_flags & self._BRIDGE_PORT_PROCESSED:
765 continue
766
767 # Add attributes specific to the vlan aware bridge
768 if bridge_vlan_aware:
769 self._apply_bridge_vlan_aware_port_settings_all(
770 bportifaceobj, bridge_vids, bridge_pvid)
771 self._apply_bridge_port_settings(bportifaceobj,
772 bridgeifaceobj=ifaceobj)
773
774 def _up(self, ifaceobj, ifaceobj_getfunc=None):
775 # Check if bridge port
776 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
777 if bridgename:
778 if self.ipcmd.bridge_is_vlan_aware(bridgename):
779 bridge_vids = self._get_bridge_vids(bridgename,
780 ifaceobj_getfunc)
781 bridge_pvid = self._get_bridge_pvid(bridgename,
782 ifaceobj_getfunc)
783 self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
784 bridge_vids,
785 bridge_pvid)
786 self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
787 ifaceobj.priv_flags |= self._BRIDGE_PORT_PROCESSED
788 return
789 if not self._is_bridge(ifaceobj):
790 return
791 try:
792 link_exists = False
793 porterr = False
794 porterrstr = ''
795 if not self.PERFMODE:
796 if not self.ipcmd.link_exists(ifaceobj.name):
797 self.ipcmd.link_create(ifaceobj.name, 'bridge')
798 else:
799 self.ipcmd.link_create(ifaceobj.name, 'bridge')
800 link_exists = True
801 try:
802 self._add_ports(ifaceobj)
803 except Exception, e:
804 porterr = True
805 porterrstr = str(e)
806 pass
807 self._apply_bridge_settings(ifaceobj)
808 self._apply_bridge_port_settings_all(ifaceobj,
809 ifaceobj_getfunc=ifaceobj_getfunc)
810 #self._flush_running_vidinfo()
811 except Exception, e:
812 self.log_error(str(e))
813 finally:
814 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
815 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
816 [rtnetlink_api.rtnl_api.link_set(p, "up")
817 for p in running_ports]
818 if link_exists and ifaceobj.addr_method == 'manual':
819 rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
820 if porterr:
821 raise Exception(porterrstr)
822
823 def _down(self, ifaceobj, ifaceobj_getfunc=None):
824 try:
825 if ifaceobj.get_attr_value_first('bridge-ports'):
826 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
827 self.brctlcmd.delete_bridge(ifaceobj.name)
828 if ports:
829 for p in ports:
830 proc_file = ('/proc/sys/net/ipv6/conf/%s' %p +
831 '/disable_ipv6')
832 self.write_file(proc_file, '0')
833 if ifaceobj.link_type == ifaceLinkType.LINK_MASTER:
834 rtnetlink_api.rtnl_api.link_set(p, "down")
835 except Exception, e:
836 self.log_error(str(e))
837
838 def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
839 running_attrs = {}
840 running_vidinfo = self._get_running_vidinfo()
841 if ports:
842 running_bridge_port_vids = ''
843 for p in ports:
844 try:
845 running_vids = running_vidinfo.get(p, {}).get('vlan')
846 if running_vids:
847 running_bridge_port_vids += ' %s=%s' %(p,
848 ','.join(running_vids))
849 except Exception:
850 pass
851 running_attrs['bridge-port-vids'] = running_bridge_port_vids
852
853 running_bridge_port_pvids = ''
854 for p in ports:
855 try:
856 running_pvids = running_vidinfo.get(p, {}).get('pvid')
857 if running_pvids:
858 running_bridge_port_pvids += ' %s=%s' %(p,
859 running_pvids)
860 except Exception:
861 pass
862 running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
863
864 running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
865 {}).get('vlan')
866 if running_bridge_vids:
867 running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
868 return running_attrs
869
870 def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
871 bridgeports=None):
872 running_attrs = {}
873 running_vidinfo = self._get_running_vidinfo()
874 if not running_vidinfo:
875 return running_attrs
876
877 # 'bridge-vids' under the bridge is all about 'vids' on the port.
878 # so query the ports
879 running_bridgeport_vids = []
880 running_bridgeport_pvids = []
881 for bport in bridgeports:
882 vids = running_vidinfo.get(bport, {}).get('vlan')
883 if vids:
884 running_bridgeport_vids.append(' '.join(vids))
885 pvids = running_vidinfo.get(bport, {}).get('pvid')
886 if pvids:
887 running_bridgeport_pvids.append(pvids[0])
888
889 bridge_vids = None
890 if running_bridgeport_vids:
891 (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
892 if freq == len(bridgeports):
893 running_attrs['bridge-vids'] = vidval
894 bridge_vids = vidval.split()
895
896 bridge_pvid = None
897 if running_bridgeport_pvids:
898 (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
899 if freq == len(bridgeports) and vidval != '1':
900 running_attrs['bridge-pvid'] = vidval
901 bridge_pvid = vidval.split()
902
903 # Go through all bridge ports and find their vids
904 for bport in bridgeports:
905 bportifaceobj = ifaceobj_getfunc(bport)
906 if not bportifaceobj:
907 continue
908 bport_vids = None
909 bport_pvids = None
910 vids = running_vidinfo.get(bport, {}).get('vlan')
911 if vids and vids != bridge_vids:
912 bport_vids = vids
913 pvids = running_vidinfo.get(bport, {}).get('pvid')
914 if pvids and pvids[0] != bridge_pvid:
915 bport_pvids = pvids
916 if not bport_vids and bport_pvids and bport_pvids[0] != '1':
917 bportifaceobj[0].replace_config('bridge-access', bport_pvids[0])
918 else:
919 if bport_pvids and bport_pvids[0] != '1':
920 bportifaceobj[0].replace_config('bridge-pvid', bport_pvids[0])
921 else:
922 # delete any stale bridge-vids under ports
923 bportifaceobj[0].delete_config('bridge-pvid')
924 if bport_vids:
925 bportifaceobj[0].replace_config('bridge-vids',
926 ' '.join(bport_vids))
927 else:
928 # delete any stale bridge-vids under ports
929 bportifaceobj[0].delete_config('bridge-vids')
930 return running_attrs
931
932 def _query_running_mcqv4src(self, ifaceobjrunning):
933 running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
934 mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
935 mcqs.sort()
936 mcq = ' '.join(mcqs)
937 return mcq
938
939 def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
940 bridge_vlan_aware=False):
941 bridgeattrdict = {}
942 userspace_stp = 0
943 ports = None
944 skip_kernel_stp_attrs = 0
945
946 if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
947 userspace_stp = 1
948
949 tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
950 if not tmpbridgeattrdict:
951 self.logger.warn('%s: unable to get bridge attrs'
952 %ifaceobjrunning.name)
953 return bridgeattrdict
954
955 # Fill bridge_ports and bridge stp attributes first
956 ports = tmpbridgeattrdict.get('ports')
957 if ports:
958 bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
959 stp = tmpbridgeattrdict.get('stp', 'no')
960 if stp != self.get_mod_subattr('bridge-stp', 'default'):
961 bridgeattrdict['bridge-stp'] = [stp]
962
963 if stp == 'yes' and userspace_stp:
964 skip_kernel_stp_attrs = 1
965
966 # pick all other attributes
967 for k,v in tmpbridgeattrdict.items():
968 if not v:
969 continue
970 if k == 'ports' or k == 'stp':
971 continue
972
973 if skip_kernel_stp_attrs and k[:2] != 'mc':
974 # only include igmp attributes if kernel stp is off
975 continue
976 attrname = 'bridge-' + k
977 if v != self.get_mod_subattr(attrname, 'default'):
978 bridgeattrdict[attrname] = [v]
979
980 if bridge_vlan_aware:
981 bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
982 ifaceobj_getfunc,
983 ports.keys())
984 else:
985 bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
986 ports)
987 if bridgevidinfo:
988 bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
989 if v})
990
991 mcq = self._query_running_mcqv4src(ifaceobjrunning)
992 if mcq:
993 bridgeattrdict['bridge-mcqv4src'] = [mcq]
994
995 if skip_kernel_stp_attrs:
996 return bridgeattrdict
997
998 if ports:
999 portconfig = {'bridge-pathcosts' : '',
1000 'bridge-portprios' : ''}
1001 for p, v in ports.items():
1002 v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
1003 if v and v != self.get_mod_subattr('bridge-pathcosts',
1004 'default'):
1005 portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
1006
1007 v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
1008 if v and v != self.get_mod_subattr('bridge-portprios',
1009 'default'):
1010 portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
1011
1012 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
1013 if v})
1014
1015 return bridgeattrdict
1016
1017 def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
1018 running_mcqs = self._query_running_mcqv4src(ifaceobj)
1019 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
1020 if attrval:
1021 mcqs = attrval.split()
1022 mcqs.sort()
1023 mcqsout = ' '.join(mcqs)
1024 ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
1025 running_mcqs, 1 if running_mcqs != mcqsout else 0)
1026
1027 def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
1028 err = 0
1029 running_vidinfo = self._get_running_vidinfo()
1030 attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
1031 if attrval:
1032 running_bridge_port_vids = ''
1033 portlist = self.parse_port_list(attrval)
1034 if not portlist:
1035 self.log_warn('%s: could not parse \'%s %s\''
1036 %(ifaceobj.name, attrname, attrval))
1037 return
1038 err = 0
1039 for p in portlist:
1040 try:
1041 (port, val) = p.split('=')
1042 vids = val.split(',')
1043 running_vids = running_vidinfo.get(port, {}).get('vlan')
1044 if running_vids:
1045 if not self._compare_vids(vids, running_vids):
1046 err += 1
1047 running_bridge_port_vids += ' %s=%s' %(port,
1048 ','.join(running_vids))
1049 else:
1050 running_bridge_port_vids += ' %s' %p
1051 else:
1052 err += 1
1053 except Exception, e:
1054 self.log_warn('%s: failure checking vid %s (%s)'
1055 %(ifaceobj.name, p, str(e)))
1056 if err:
1057 ifaceobjcurr.update_config_with_status('bridge-port-vids',
1058 running_bridge_port_vids, 1)
1059 else:
1060 ifaceobjcurr.update_config_with_status('bridge-port-vids',
1061 attrval, 0)
1062
1063 attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
1064 if attrval:
1065 portlist = self.parse_port_list(attrval)
1066 if not portlist:
1067 self.log_warn('%s: could not parse \'%s %s\''
1068 %(ifaceobj.name, attrname, attrval))
1069 return
1070 running_bridge_port_pvids = ''
1071 err = 0
1072 for p in portlist:
1073 try:
1074 (port, pvid) = p.split('=')
1075 running_pvid = running_vidinfo.get(port, {}).get('pvid')
1076 if running_pvid and running_pvid == pvid:
1077 running_bridge_port_pvids += ' %s' %p
1078 else:
1079 err += 1
1080 running_bridge_port_pvids += ' %s=%s' %(port,
1081 running_pvid)
1082 except Exception, e:
1083 self.log_warn('%s: failure checking pvid %s (%s)'
1084 %(ifaceobj.name, pvid, str(e)))
1085 if err:
1086 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
1087 running_bridge_port_pvids, 1)
1088 else:
1089 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
1090 running_bridge_port_pvids, 0)
1091
1092 # XXX: No need to check for bridge-vids on the bridge
1093 # This is used by the ports. The vids on the bridge
1094 # come from the vlan interfaces on the bridge.
1095 #
1096 attrval = ifaceobj.get_attr_value_first('bridge-vids')
1097 #if attrval:
1098 # vids = re.split(r'[\s\t]\s*', attrval)
1099 # running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
1100 # if running_vids:
1101 # if self._compare_vids(vids, running_vids):
1102 # ifaceobjcurr.update_config_with_status('bridge-vids',
1103 # attrval, 0)
1104 # else:
1105 # ifaceobjcurr.update_config_with_status('bridge-vids',
1106 # ','.join(running_vids), 1)
1107 # else:
1108 # ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
1109 # 1)
1110 if attrval:
1111 ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1)
1112
1113 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
1114 ifaceobj_getfunc=None):
1115 if not self._is_bridge(ifaceobj):
1116 return
1117 if not self.brctlcmd.bridge_exists(ifaceobj.name):
1118 self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
1119 return
1120
1121 ifaceattrs = self.dict_key_subset(ifaceobj.config,
1122 self.get_mod_attrs())
1123 if not ifaceattrs:
1124 return
1125 try:
1126 runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
1127 if not runningattrs:
1128 self.logger.debug('%s: bridge: unable to get bridge attrs'
1129 %ifaceobj.name)
1130 runningattrs = {}
1131 except Exception, e:
1132 self.logger.warn(str(e))
1133 runningattrs = {}
1134 filterattrs = ['bridge-vids', 'bridge-port-vids',
1135 'bridge-port-pvids']
1136 for k in Set(ifaceattrs).difference(filterattrs):
1137 # get the corresponding ifaceobj attr
1138 v = ifaceobj.get_attr_value_first(k)
1139 if not v:
1140 continue
1141 rv = runningattrs.get(k[7:])
1142 if k == 'bridge-mcqv4src':
1143 continue
1144 if k == 'bridge-vlan-aware' and v == 'yes':
1145 if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
1146 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
1147 v, 0)
1148 else:
1149 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
1150 v, 1)
1151 elif k == 'bridge-stp':
1152 # special case stp compare because it may
1153 # contain more than one valid values
1154 stp_on_vals = ['on', 'yes']
1155 stp_off_vals = ['off']
1156 if ((v in stp_on_vals and rv in stp_on_vals) or
1157 (v in stp_off_vals and rv in stp_off_vals)):
1158 ifaceobjcurr.update_config_with_status('bridge-stp',
1159 v, 0)
1160 else:
1161 ifaceobjcurr.update_config_with_status('bridge-stp',
1162 v, 1)
1163 elif k == 'bridge-ports':
1164 # special case ports because it can contain regex or glob
1165 running_port_list = rv.keys() if rv else []
1166 bridge_port_list = self._get_bridge_port_list(ifaceobj)
1167 if not running_port_list and not bridge_port_list:
1168 continue
1169 portliststatus = 1
1170 if running_port_list and bridge_port_list:
1171 difference = set(running_port_list
1172 ).symmetric_difference(bridge_port_list)
1173 if not difference:
1174 portliststatus = 0
1175 ifaceobjcurr.update_config_with_status('bridge-ports',
1176 ' '.join(running_port_list)
1177 if running_port_list else '', portliststatus)
1178 elif (k == 'bridge-pathcosts' or
1179 k == 'bridge-portprios' or k == 'bridge-portmcrouter'
1180 or k == 'bridge-portmcfl'):
1181 brctlcmdattrname = k[11:].rstrip('s')
1182 # for port attributes, the attributes are in a list
1183 # <portname>=<portattrvalue>
1184 status = 0
1185 currstr = ''
1186 vlist = self.parse_port_list(v)
1187 if not vlist:
1188 continue
1189 for vlistitem in vlist:
1190 try:
1191 (p, v) = vlistitem.split('=')
1192 currv = self.brctlcmd.get_bridgeport_attr(
1193 ifaceobj.name, p,
1194 brctlcmdattrname)
1195 if currv:
1196 currstr += ' %s=%s' %(p, currv)
1197 else:
1198 currstr += ' %s=%s' %(p, 'None')
1199 if currv != v:
1200 status = 1
1201 except Exception, e:
1202 self.log_warn(str(e))
1203 pass
1204 ifaceobjcurr.update_config_with_status(k, currstr, status)
1205 elif not rv:
1206 ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
1207 continue
1208 elif v != rv:
1209 ifaceobjcurr.update_config_with_status(k, rv, 1)
1210 else:
1211 ifaceobjcurr.update_config_with_status(k, rv, 0)
1212
1213 self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
1214
1215 self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
1216
1217 def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
1218 ifaceobjs = ifaceobj_getfunc(bridgename)
1219 for ifaceobj in ifaceobjs:
1220 vids = ifaceobj.get_attr_value_first('bridge-vids')
1221 if vids: return re.split(r'[\s\t,]\s*', vids)
1222 return None
1223
1224 def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
1225 ifaceobjs = ifaceobj_getfunc(bridgename)
1226 pvid = None
1227 for ifaceobj in ifaceobjs:
1228 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
1229 return pvid
1230
1231 def _get_bridge_name(self, ifaceobj):
1232 return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
1233
1234 def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
1235 ifaceobj_getfunc, bridgename):
1236 running_vidinfo = self._get_running_vidinfo()
1237
1238 attr_name = 'bridge-access'
1239 vids = ifaceobj.get_attr_value_first(attr_name)
1240 if vids:
1241 running_pvids = running_vidinfo.get(ifaceobj.name,
1242 {}).get('pvid')
1243 running_vids = running_vidinfo.get(ifaceobj.name,
1244 {}).get('vlan')
1245 if (not running_pvids or running_pvids != vids or
1246 running_vids):
1247 ifaceobjcurr.update_config_with_status(attr_name,
1248 running_pvids, 1)
1249 else:
1250 ifaceobjcurr.update_config_with_status(attr_name, vids, 0)
1251 return
1252
1253 attr_name = 'bridge-vids'
1254 vids = ifaceobj.get_attr_value_first(attr_name)
1255 if vids:
1256 vids = re.split(r'[\s\t]\s*', vids)
1257 running_vids = running_vidinfo.get(ifaceobj.name,
1258 {}).get('vlan')
1259 if not running_vids or not self._compare_vids(vids, running_vids):
1260 ifaceobjcurr.update_config_with_status(attr_name,
1261 ' '.join(running_vids), 1)
1262 else:
1263 ifaceobjcurr.update_config_with_status(attr_name,
1264 ' '.join(running_vids), 0)
1265 else:
1266 # check if it matches the bridge vids
1267 bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
1268 running_vids = running_vidinfo.get(ifaceobj.name,
1269 {}).get('vlan')
1270 if (bridge_vids and (not running_vids or
1271 not self._compare_vids(bridge_vids, running_vids))):
1272 ifaceobjcurr.status = ifaceStatus.ERROR
1273 ifaceobjcurr.status_str = 'bridge vid error'
1274
1275 running_pvid = running_vidinfo.get(ifaceobj.name,
1276 {}).get('pvid')
1277 attr_name = 'bridge-pvid'
1278 pvid = ifaceobj.get_attr_value_first(attr_name)
1279 if pvid:
1280 if running_pvid and running_pvid == pvid:
1281 ifaceobjcurr.update_config_with_status(attr_name,
1282 running_pvid, 0)
1283 else:
1284 ifaceobjcurr.update_config_with_status(attr_name,
1285 running_pvid, 1)
1286 elif not running_pvid or running_pvid != '1':
1287 ifaceobjcurr.status = ifaceStatus.ERROR
1288 ifaceobjcurr.status_str = 'bridge pvid error'
1289
1290 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
1291 ifaceobj_getfunc):
1292 if not self._is_bridge_port(ifaceobj):
1293 # Mark all bridge attributes as failed
1294 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
1295 ['bridge-vids', 'bridge-pvid', 'bridge-access',
1296 'bridge-pathcosts', 'bridge-portprios',
1297 'bridge-portmcrouter',
1298 'bridge-portmcfl'], 1)
1299 return
1300 bridgename = self._get_bridge_name(ifaceobj)
1301 if not bridgename:
1302 self.logger.warn('%s: unable to determine bridge name'
1303 %ifaceobj.name)
1304 return
1305
1306 if self.ipcmd.bridge_is_vlan_aware(bridgename):
1307 self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
1308 ifaceobj_getfunc,
1309 bridgename)
1310 for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
1311 'bridge-portprios' : 'priority',
1312 'bridge-portmcrouter' : 'mcrouter',
1313 'bridge-portmcfl' : 'mcfl' }.items():
1314 attrval = ifaceobj.get_attr_value_first(attr)
1315 if not attrval:
1316 continue
1317
1318 try:
1319 running_attrval = self.brctlcmd.get_bridgeport_attr(
1320 bridgename, ifaceobj.name, dstattr)
1321 if running_attrval != attrval:
1322 ifaceobjcurr.update_config_with_status(attr,
1323 running_attrval, 1)
1324 else:
1325 ifaceobjcurr.update_config_with_status(attr,
1326 running_attrval, 0)
1327 except Exception, e:
1328 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
1329
1330 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
1331 if self._is_bridge(ifaceobj):
1332 self._query_check_bridge(ifaceobj, ifaceobjcurr)
1333 else:
1334 self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
1335 ifaceobj_getfunc)
1336
1337 def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
1338 if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
1339 ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
1340 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1341 ifaceobjrunning,
1342 ifaceobj_getfunc,
1343 bridge_vlan_aware=True))
1344 else:
1345 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1346 ifaceobjrunning, None))
1347
1348 def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
1349 if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
1350 return
1351
1352 v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
1353 if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
1354 ifaceobjrunning.update_config('bridge-pathcosts', v)
1355
1356 v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
1357 if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
1358 ifaceobjrunning.update_config('bridge-portprios', v)
1359
1360 def _query_running_bridge_port(self, ifaceobjrunning,
1361 ifaceobj_getfunc=None):
1362 bridgename = self.ipcmd.bridge_port_get_bridge_name(
1363 ifaceobjrunning.name)
1364 bridge_vids = None
1365 bridge_pvid = None
1366 if not bridgename:
1367 self.logger.warn('%s: unable to find bridgename'
1368 %ifaceobjrunning.name)
1369 return
1370 if not self.ipcmd.bridge_is_vlan_aware(bridgename):
1371 return
1372
1373 running_vidinfo = self._get_running_vidinfo()
1374 bridge_port_vids = running_vidinfo.get(ifaceobjrunning.name,
1375 {}).get('vlan')
1376 bridge_port_pvid = running_vidinfo.get(ifaceobjrunning.name,
1377 {}).get('pvid')
1378
1379 bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
1380 if bridgeifaceobjlist:
1381 bridge_vids = bridgeifaceobjlist[0].get_attr_value('bridge-vids')
1382 bridge_pvid = bridgeifaceobjlist[0].get_attr_value_first('bridge-pvid')
1383
1384 if not bridge_port_vids and bridge_port_pvid:
1385 # must be an access port
1386 if bridge_port_pvid != '1':
1387 ifaceobjrunning.update_config('bridge-access',
1388 bridge_port_pvid)
1389 else:
1390 if bridge_port_vids:
1391 if (not bridge_vids or bridge_port_vids != bridge_vids):
1392 ifaceobjrunning.update_config('bridge-vids',
1393 ' '.join(bridge_port_vids))
1394 if bridge_port_pvid and bridge_port_pvid != '1':
1395 if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
1396 ifaceobjrunning.update_config('bridge-pvid',
1397 bridge_port_pvid)
1398 self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
1399
1400 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
1401 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
1402 self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
1403 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
1404 self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
1405
1406 _run_ops = {'pre-up' : _up,
1407 'post-down' : _down,
1408 'query-checkcurr' : _query_check,
1409 'query-running' : _query_running}
1410
1411 def get_ops(self):
1412 """ returns list of ops supported by this module """
1413 return self._run_ops.keys()
1414
1415 def _init_command_handlers(self):
1416 flags = self.get_flags()
1417 if not self.ipcmd:
1418 self.ipcmd = iproute2(**flags)
1419 if not self.brctlcmd:
1420 self.brctlcmd = brctl(**flags)
1421
1422 def run(self, ifaceobj, operation, query_ifaceobj=None,
1423 ifaceobj_getfunc=None):
1424 """ run bridge configuration on the interface object passed as
1425 argument. Can create bridge interfaces if they dont exist already
1426
1427 Args:
1428 **ifaceobj** (object): iface object
1429
1430 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1431 'query-running'
1432
1433 Kwargs:
1434 **query_ifaceobj** (object): query check ifaceobject. This is only
1435 valid when op is 'query-checkcurr'. It is an object same as
1436 ifaceobj, but contains running attribute values and its config
1437 status. The modules can use it to return queried running state
1438 of interfaces. status is success if the running state is same
1439 as user required state in ifaceobj. error otherwise.
1440 """
1441 op_handler = self._run_ops.get(operation)
1442 if not op_handler:
1443 return
1444 self._init_command_handlers()
1445 self._flush_running_vidinfo()
1446 if operation == 'query-checkcurr':
1447 op_handler(self, ifaceobj, query_ifaceobj,
1448 ifaceobj_getfunc=ifaceobj_getfunc)
1449 else:
1450 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)