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