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