]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/bridge.py
some more ifquery support (for vxlan devices 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-pvid' :
173 { 'help' : 'bridge port pvid. Must be specified under' +
174 ' the bridge port',
175 'example' : ['bridge-pvid 1']},
176 'bridge-access' :
177 { 'help' : 'bridge port access vlan. Must be ' +
178 'specified under the bridge port',
179 'example' : ['bridge-access 300']},
180 'bridge-port-vids' :
181 { 'help' : 'bridge vlans',
182 'compat': True,
183 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
184 'bridge-port-pvids' :
185 { 'help' : 'bridge port vlans',
186 'compat': True,
187 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
188 'bridge-igmp-querier-src' :
189 { 'help' : 'bridge igmp querier src. Must be ' +
190 'specified under the vlan interface',
191 'example' : ['bridge-igmp-querier-src 172.16.101.1']},
192 }}
193
194 # declare some ifaceobj priv_flags.
195 # XXX: This assumes that the priv_flags is owned by this module
196 # which it is not.
197 _BRIDGE_PORT_PROCESSED = 0x1
198
199 def __init__(self, *args, **kargs):
200 moduleBase.__init__(self, *args, **kargs)
201 self.ipcmd = None
202 self.brctlcmd = None
203 self._running_vidinfo = {}
204 self._running_vidinfo_valid = False
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 running_vidinfo = self._get_running_vidinfo()
614 vids = None
615 pvids = None
616 bport_access = bportifaceobj.get_attr_value_first('bridge-access')
617 if bport_access:
618 vids = re.split(r'[\s\t]\s*', bport_access)
619 pvids = vids
620
621 bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
622 if bport_vids:
623 vids = re.split(r'[\s\t]\s*', bport_vids)
624
625 bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
626 if bport_pvids:
627 pvids = re.split(r'[\s\t]\s*', bport_pvids)
628
629 if pvids:
630 self._apply_bridge_port_pvids(bportifaceobj, pvids[0],
631 running_vidinfo.get(bportifaceobj.name, {}).get('pvid'))
632 else:
633 self._apply_bridge_port_pvids(bportifaceobj,
634 '1', running_vidinfo.get(bportifaceobj.name,
635 {}).get('pvid'))
636
637 if vids:
638 self._apply_bridge_vids(bportifaceobj, vids,
639 running_vidinfo.get(bportifaceobj.name,
640 {}).get('vlan'), False)
641 elif bridge_vids:
642 self._apply_bridge_vids(bportifaceobj,
643 bridge_vids, running_vidinfo.get(
644 bportifaceobj.name, {}).get('vlan'), False)
645
646
647 def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
648 bridgeifaceobj=None):
649 if not bridgename and bridgeifaceobj:
650 bridgename = bridgeifaceobj.name
651 # Set other stp and igmp attributes
652 portattrs = {}
653 for attrname, dstattrname in {
654 'bridge-pathcosts' : 'pathcost',
655 'bridge-portprios' : 'portprio',
656 'bridge-portmcrouter' : 'portmcrouter',
657 'bridge-portmcfl' : 'portmcfl'}.items():
658 attrval = bportifaceobj.get_attr_value_first(attrname)
659 if not attrval:
660 # Check if bridge has that attribute
661 #if bridgeifaceobj:
662 # attrval = bridgeifaceobj.get_attr_value_first(attrname)
663 # if not attrval:
664 # continue
665 #else:
666 continue
667 portattrs[dstattrname] = attrval
668 try:
669 self.brctlcmd.set_bridgeport_attrs(bridgename,
670 bportifaceobj.name, portattrs)
671 except Exception, e:
672 self.log_warn(str(e))
673
674 def _apply_bridge_port_settings_all(self, ifaceobj,
675 ifaceobj_getfunc=None):
676 bridge_vlan_aware = ifaceobj.get_attr_value_first(
677 'bridge-vlan-aware')
678 if bridge_vlan_aware and bridge_vlan_aware == 'yes':
679 bridge_vlan_aware = True
680 else:
681 bridge_vlan_aware = False
682
683 if (ifaceobj.get_attr_value_first('bridge-port-vids') and
684 ifaceobj.get_attr_value_first('bridge-port-pvids')):
685 # Old style bridge port vid info
686 # skip new style setting on ports
687 return
688 self.logger.info('%s: applying bridge configuration '
689 %ifaceobj.name + 'specific to ports')
690
691 bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
692 if bridge_vids:
693 bridge_vids = re.split(r'[\s\t]\s*', bridge_vids)
694 else:
695 bridge_vids = None
696
697 bridgeports = self._get_bridge_port_list(ifaceobj)
698 for bport in bridgeports:
699 # Use the brctlcmd bulk set method: first build a dictionary
700 # and then call set
701 if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
702 self.logger.info('%s: skipping bridge config' %ifaceobj.name +
703 ' for port %s (missing port)' %bport)
704 continue
705 self.logger.info('%s: processing bridge config for port %s'
706 %(ifaceobj.name, bport))
707 bportifaceobjlist = ifaceobj_getfunc(bport)
708 if not bportifaceobjlist:
709 continue
710 for bportifaceobj in bportifaceobjlist:
711 # Dont process bridge port if it already has been processed
712 if bportifaceobj.priv_flags & self._BRIDGE_PORT_PROCESSED:
713 continue
714
715 # Add attributes specific to the vlan aware bridge
716 if bridge_vlan_aware:
717 self._apply_bridge_vlan_aware_port_settings_all(
718 bportifaceobj, bridge_vids)
719 self._apply_bridge_port_settings(bportifaceobj,
720 bridgeifaceobj=ifaceobj)
721
722 def _up(self, ifaceobj, ifaceobj_getfunc=None):
723 # Check if bridge port
724 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
725 if bridgename:
726 if self.ipcmd.bridge_is_vlan_aware(bridgename):
727 bridge_vids = self._get_bridge_vids(bridgename,
728 ifaceobj_getfunc)
729 self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
730 bridge_vids)
731 self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
732 ifaceobj.priv_flags |= self._BRIDGE_PORT_PROCESSED
733 return
734 if not self._is_bridge(ifaceobj):
735 return
736 try:
737 porterr = False
738 porterrstr = ''
739 self.ipcmd.batch_start()
740 if not self.PERFMODE:
741 if not self.ipcmd.link_exists(ifaceobj.name):
742 self.ipcmd.link_create(ifaceobj.name, 'bridge')
743 else:
744 self.ipcmd.link_create(ifaceobj.name, 'bridge')
745 try:
746 self._add_ports(ifaceobj)
747 except Exception, e:
748 porterr = True
749 porterrstr = str(e)
750 pass
751 finally:
752 self.ipcmd.batch_commit()
753 self._apply_bridge_settings(ifaceobj)
754 self._apply_bridge_port_settings_all(ifaceobj,
755 ifaceobj_getfunc=ifaceobj_getfunc)
756 self._flush_running_vidinfo()
757 except Exception, e:
758 self.log_error(str(e))
759 if porterr:
760 raise Exception(porterrstr)
761
762 def _down(self, ifaceobj, ifaceobj_getfunc=None):
763 try:
764 if ifaceobj.get_attr_value_first('bridge-ports'):
765 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
766 if ports:
767 for p in ports:
768 proc_file = ('/proc/sys/net/ipv6/conf/%s' %p +
769 '/disable_ipv6')
770 self.write_file(proc_file, '0')
771 self.brctlcmd.delete_bridge(ifaceobj.name)
772 except Exception, e:
773 self.log_error(str(e))
774
775 def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
776 running_attrs = {}
777 running_vidinfo = self._get_running_vidinfo()
778 if ports:
779 running_bridge_port_vids = ''
780 for p in ports:
781 try:
782 running_vids = running_vidinfo.get(p, {}).get('vlan')
783 if running_vids:
784 running_bridge_port_vids += ' %s=%s' %(p,
785 ','.join(running_vids))
786 except Exception:
787 pass
788 running_attrs['bridge-port-vids'] = running_bridge_port_vids
789
790 running_bridge_port_pvids = ''
791 for p in ports:
792 try:
793 running_pvids = running_vidinfo.get(p, {}).get('pvid')
794 if running_pvids:
795 running_bridge_port_pvids += ' %s=%s' %(p,
796 running_pvids)
797 except Exception:
798 pass
799 running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
800
801 running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
802 {}).get('vlan')
803 if running_bridge_vids:
804 running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
805 return running_attrs
806
807 def _query_running_vidinfo(self, ifaceobjrunning):
808 running_attrs = {}
809 running_vidinfo = self._get_running_vidinfo()
810 running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
811 {}).get('vlan')
812 if running_bridge_vids:
813 running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
814 return running_attrs
815
816 def _query_running_mcqv4src(self, ifaceobjrunning):
817 running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
818 mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
819 mcqs.sort()
820 mcq = ' '.join(mcqs)
821 return mcq
822
823 def _query_running_attrs(self, ifaceobjrunning, bridge_vlan_aware=False):
824 bridgeattrdict = {}
825 userspace_stp = 0
826 ports = None
827 skip_kernel_stp_attrs = 0
828
829 if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
830 userspace_stp = 1
831
832 tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
833 if not tmpbridgeattrdict:
834 self.logger.warn('%s: unable to get bridge attrs'
835 %ifaceobjrunning.name)
836 return bridgeattrdict
837
838 # Fill bridge_ports and bridge stp attributes first
839 ports = tmpbridgeattrdict.get('ports')
840 if ports:
841 bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
842 stp = tmpbridgeattrdict.get('stp', 'no')
843 if stp != self.get_mod_subattr('bridge-stp', 'default'):
844 bridgeattrdict['bridge-stp'] = [stp]
845
846 if stp == 'yes' and userspace_stp:
847 skip_kernel_stp_attrs = 1
848
849 # pick all other attributes
850 for k,v in tmpbridgeattrdict.items():
851 if not v:
852 continue
853 if k == 'ports' or k == 'stp':
854 continue
855
856 if skip_kernel_stp_attrs and k[:2] != 'mc':
857 # only include igmp attributes if kernel stp is off
858 continue
859 attrname = 'bridge-' + k
860 if v != self.get_mod_subattr(attrname, 'default'):
861 bridgeattrdict[attrname] = [v]
862
863 if bridge_vlan_aware:
864 bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning)
865 else:
866 bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
867 ports)
868 if bridgevidinfo:
869 bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
870 if v})
871
872 mcq = self._query_running_mcqv4src(ifaceobjrunning)
873 if mcq:
874 bridgeattrdict['bridge-mcqv4src'] = [mcq]
875
876 if skip_kernel_stp_attrs:
877 return bridgeattrdict
878
879 if ports:
880 portconfig = {'bridge-pathcosts' : '',
881 'bridge-portprios' : ''}
882 for p, v in ports.items():
883 v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
884 if v and v != self.get_mod_subattr('bridge-pathcosts',
885 'default'):
886 portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
887
888 v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
889 if v and v != self.get_mod_subattr('bridge-portprios',
890 'default'):
891 portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
892
893 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
894 if v})
895
896 return bridgeattrdict
897
898 def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
899 running_mcqs = self._query_running_mcqv4src(ifaceobj)
900 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
901 if attrval:
902 mcqs = attrval.split()
903 mcqs.sort()
904 mcqsout = ' '.join(mcqs)
905 ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
906 running_mcqs, 1 if running_mcqs != mcqsout else 0)
907
908 def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
909 err = 0
910 running_vidinfo = self._get_running_vidinfo()
911 attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
912 if attrval:
913 running_bridge_port_vids = ''
914 portlist = self.parse_port_list(attrval)
915 if not portlist:
916 self.log_warn('%s: could not parse \'%s %s\''
917 %(ifaceobj.name, attrname, attrval))
918 return
919 err = 0
920 for p in portlist:
921 try:
922 (port, val) = p.split('=')
923 vids = val.split(',')
924 running_vids = running_vidinfo.get(port, {}).get('vlan')
925 if running_vids:
926 if not self._compare_vids(vids, running_vids):
927 err += 1
928 running_bridge_port_vids += ' %s=%s' %(port,
929 ','.join(running_vids))
930 else:
931 running_bridge_port_vids += ' %s' %p
932 else:
933 err += 1
934 except Exception, e:
935 self.log_warn('%s: failure checking vid %s (%s)'
936 %(ifaceobj.name, p, str(e)))
937 if err:
938 ifaceobjcurr.update_config_with_status('bridge-port-vids',
939 running_bridge_port_vids, 1)
940 else:
941 ifaceobjcurr.update_config_with_status('bridge-port-vids',
942 attrval, 0)
943
944 attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
945 if attrval:
946 portlist = self.parse_port_list(attrval)
947 if not portlist:
948 self.log_warn('%s: could not parse \'%s %s\''
949 %(ifaceobj.name, attrname, attrval))
950 return
951 running_bridge_port_pvids = ''
952 err = 0
953 for p in portlist:
954 try:
955 (port, pvid) = p.split('=')
956 running_pvid = running_vidinfo.get(port, {}).get('pvid')
957 if running_pvid and running_pvid == pvid:
958 running_bridge_port_pvids += ' %s' %p
959 else:
960 err += 1
961 running_bridge_port_pvids += ' %s=%s' %(port,
962 running_pvid)
963 except Exception, e:
964 self.log_warn('%s: failure checking pvid %s (%s)'
965 %(ifaceobj.name, pvid, str(e)))
966 if err:
967 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
968 running_bridge_port_pvids, 1)
969 else:
970 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
971 running_bridge_port_pvids, 0)
972
973 # XXX: No need to check for bridge-vids on the bridge
974 # This is used by the ports. The vids on the bridge
975 # come from the vlan interfaces on the bridge.
976 #
977 attrval = ifaceobj.get_attr_value_first('bridge-vids')
978 #if attrval:
979 # vids = re.split(r'[\s\t]\s*', attrval)
980 # running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
981 # if running_vids:
982 # if self._compare_vids(vids, running_vids):
983 # ifaceobjcurr.update_config_with_status('bridge-vids',
984 # attrval, 0)
985 # else:
986 # ifaceobjcurr.update_config_with_status('bridge-vids',
987 # ','.join(running_vids), 1)
988 # else:
989 # ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
990 # 1)
991 if attrval:
992 ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1)
993
994 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
995 ifaceobj_getfunc=None):
996 if not self._is_bridge(ifaceobj):
997 return
998 if not self.brctlcmd.bridge_exists(ifaceobj.name):
999 self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
1000 ifaceobjcurr.status = ifaceStatus.NOTFOUND
1001 return
1002
1003 ifaceattrs = self.dict_key_subset(ifaceobj.config,
1004 self.get_mod_attrs())
1005 if not ifaceattrs:
1006 return
1007 try:
1008 runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
1009 if not runningattrs:
1010 self.logger.debug('%s: bridge: unable to get bridge attrs'
1011 %ifaceobj.name)
1012 runningattrs = {}
1013 except Exception, e:
1014 self.logger.warn(str(e))
1015 runningattrs = {}
1016 filterattrs = ['bridge-vids', 'bridge-port-vids',
1017 'bridge-port-pvids']
1018 for k in Set(ifaceattrs).difference(filterattrs):
1019 # get the corresponding ifaceobj attr
1020 v = ifaceobj.get_attr_value_first(k)
1021 if not v:
1022 continue
1023 rv = runningattrs.get(k[7:])
1024 if k == 'bridge-mcqv4src':
1025 continue
1026 if k == 'bridge-vlan-aware' and v == 'yes':
1027 if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
1028 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
1029 v, 0)
1030 else:
1031 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
1032 v, 1)
1033 elif k == 'bridge-stp':
1034 # special case stp compare because it may
1035 # contain more than one valid values
1036 stp_on_vals = ['on', 'yes']
1037 stp_off_vals = ['off']
1038 if ((v in stp_on_vals and rv in stp_on_vals) or
1039 (v in stp_off_vals and rv in stp_off_vals)):
1040 ifaceobjcurr.update_config_with_status('bridge-stp',
1041 v, 0)
1042 else:
1043 ifaceobjcurr.update_config_with_status('bridge-stp',
1044 v, 1)
1045 elif k == 'bridge-ports':
1046 # special case ports because it can contain regex or glob
1047 running_port_list = rv.keys() if rv else []
1048 bridge_port_list = self._get_bridge_port_list(ifaceobj)
1049 if not running_port_list and not bridge_port_list:
1050 continue
1051 portliststatus = 1
1052 if running_port_list and bridge_port_list:
1053 difference = set(running_port_list
1054 ).symmetric_difference(bridge_port_list)
1055 if not difference:
1056 portliststatus = 0
1057 ifaceobjcurr.update_config_with_status('bridge-ports',
1058 ' '.join(running_port_list)
1059 if running_port_list else '', portliststatus)
1060 elif (k == 'bridge-pathcosts' or
1061 k == 'bridge-portprios' or k == 'bridge-portmcrouter'
1062 or k == 'bridge-portmcfl'):
1063 brctlcmdattrname = k[11:].rstrip('s')
1064 # for port attributes, the attributes are in a list
1065 # <portname>=<portattrvalue>
1066 status = 0
1067 currstr = ''
1068 vlist = self.parse_port_list(v)
1069 if not vlist:
1070 continue
1071 for vlistitem in vlist:
1072 try:
1073 (p, v) = vlistitem.split('=')
1074 currv = self.brctlcmd.get_bridgeport_attr(
1075 ifaceobj.name, p,
1076 brctlcmdattrname)
1077 if currv:
1078 currstr += ' %s=%s' %(p, currv)
1079 else:
1080 currstr += ' %s=%s' %(p, 'None')
1081 if currv != v:
1082 status = 1
1083 except Exception, e:
1084 self.log_warn(str(e))
1085 pass
1086 ifaceobjcurr.update_config_with_status(k, currstr, status)
1087 elif not rv:
1088 ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
1089 continue
1090 elif v != rv:
1091 ifaceobjcurr.update_config_with_status(k, rv, 1)
1092 else:
1093 ifaceobjcurr.update_config_with_status(k, rv, 0)
1094
1095 self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
1096
1097 self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
1098
1099 def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
1100 ifaceobjs = ifaceobj_getfunc(bridgename)
1101 for ifaceobj in ifaceobjs:
1102 vids = ifaceobj.get_attr_value_first('bridge-vids')
1103 if vids: return re.split(r'[\s\t]\s*', vids)
1104 return None
1105
1106 def _get_bridge_name(self, ifaceobj):
1107 return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
1108
1109 def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
1110 ifaceobj_getfunc, bridgename):
1111 running_vidinfo = self._get_running_vidinfo()
1112
1113 attr_name = 'bridge-access'
1114 vids = ifaceobj.get_attr_value_first(attr_name)
1115 if vids:
1116 running_pvids = running_vidinfo.get(ifaceobj.name,
1117 {}).get('pvid')
1118 running_vids = running_vidinfo.get(ifaceobj.name,
1119 {}).get('vlan')
1120 if (not running_pvids or running_pvids != vids or
1121 running_vids):
1122 ifaceobjcurr.update_config_with_status(attr_name,
1123 running_pvids, 1)
1124 else:
1125 ifaceobjcurr.update_config_with_status(attr_name, vids, 0)
1126 return
1127
1128 attr_name = 'bridge-vids'
1129 vids = ifaceobj.get_attr_value_first(attr_name)
1130 if vids:
1131 vids = re.split(r'[\s\t]\s*', vids)
1132 running_vids = running_vidinfo.get(ifaceobj.name,
1133 {}).get('vlan')
1134 if not running_vids or not self._compare_vids(vids, running_vids):
1135 ifaceobjcurr.update_config_with_status(attr_name,
1136 ' '.join(running_vids), 1)
1137 else:
1138 ifaceobjcurr.update_config_with_status(attr_name,
1139 ' '.join(running_vids), 0)
1140 else:
1141 # check if it matches the bridge vids
1142 bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
1143 running_vids = running_vidinfo.get(ifaceobj.name,
1144 {}).get('vlan')
1145 if (bridge_vids and (not running_vids or
1146 not self._compare_vids(bridge_vids, running_vids))):
1147 ifaceobjcurr.status = ifaceStatus.ERROR
1148 ifaceobjcurr.status_str = 'bridge vid error'
1149
1150 running_pvid = running_vidinfo.get(ifaceobj.name,
1151 {}).get('pvid')
1152 attr_name = 'bridge-pvid'
1153 pvid = ifaceobj.get_attr_value_first(attr_name)
1154 if pvid:
1155 if running_pvid and running_pvid == pvid:
1156 ifaceobjcurr.update_config_with_status(attr_name,
1157 running_pvid, 0)
1158 else:
1159 ifaceobjcurr.update_config_with_status(attr_name,
1160 running_pvid, 1)
1161 elif not running_pvid or running_pvid != '1':
1162 ifaceobjcurr.status = ifaceStatus.ERROR
1163 ifaceobjcurr.status_str = 'bridge pvid error'
1164
1165 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
1166 ifaceobj_getfunc):
1167 if not self._is_bridge_port(ifaceobj):
1168 # Mark all bridge attributes as failed
1169 ifaceobj.check_n_update_config_with_status_many(
1170 ['bridge-vids', 'bridge-pvid', 'bridge-access',
1171 'bridge-pathcosts', 'bridge-portprios',
1172 'bridge-portmcrouter',
1173 'bridge-portmcfl',
1174 'bridge-igmp-querier-src'], 0)
1175 return
1176 bridgename = self._get_bridge_name(ifaceobj)
1177 if not bridgename:
1178 self.logger.warn('%s: unable to determine bridge name'
1179 %ifaceobj.name)
1180 return
1181
1182 if self.ipcmd.bridge_is_vlan_aware(bridgename):
1183 self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
1184 ifaceobj_getfunc,
1185 bridgename)
1186 for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
1187 'bridge-portprios' : 'priority',
1188 'bridge-portmcrouter' : 'mcrouter',
1189 'bridge-portmcfl' : 'mcfl' }.items():
1190 attrval = ifaceobj.get_attr_value_first(attr)
1191 if not attrval:
1192 continue
1193
1194 try:
1195 running_attrval = self.brctlcmd.get_bridgeport_attr(
1196 bridgename, ifaceobj.name, dstattr)
1197 if running_attrval != attrval:
1198 ifaceobjcurr.update_config_with_status(attr,
1199 running_attrval, 1)
1200 else:
1201 ifaceobjcurr.update_config_with_status(attr,
1202 running_attrval, 0)
1203 except Exception, e:
1204 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
1205
1206 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
1207 if self._is_bridge(ifaceobj):
1208 self._query_check_bridge(ifaceobj, ifaceobjcurr)
1209 else:
1210 self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
1211 ifaceobj_getfunc)
1212
1213 def _query_running_bridge(self, ifaceobjrunning):
1214 if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
1215 ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
1216 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1217 ifaceobjrunning,
1218 bridge_vlan_aware=True))
1219 else:
1220 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1221 ifaceobjrunning))
1222
1223 def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
1224 if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
1225 return
1226
1227 v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
1228 if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
1229 ifaceobjrunning.update_config('bridge-pathcosts', v)
1230
1231 v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
1232 if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
1233 ifaceobjrunning.update_config('bridge-portprios', v)
1234
1235 def _query_running_bridge_port(self, ifaceobjrunning,
1236 ifaceobj_getfunc=None):
1237 bridgename = self.ipcmd.bridge_port_get_bridge_name(
1238 ifaceobjrunning.name)
1239 if not bridgename:
1240 self.logger.warn('%s: unable to find bridgename'
1241 %ifaceobjrunning.name)
1242 return
1243 if not self.ipcmd.bridge_is_vlan_aware(bridgename):
1244 return
1245
1246 running_vidinfo = self._get_running_vidinfo()
1247 # Check vidinfo
1248 bridge_vids = running_vidinfo.get(bridgename, {}).get('vlan')
1249
1250 bridge_port_vids = running_vidinfo.get(ifaceobjrunning.name,
1251 {}).get('vlan')
1252 bridge_port_pvid = running_vidinfo.get(ifaceobjrunning.name,
1253 {}).get('pvid')
1254
1255 if not bridge_port_vids and bridge_port_pvid:
1256 # must be an access port
1257 ifaceobjrunning.update_config('bridge-access',
1258 bridge_port_pvid)
1259 else:
1260 if bridge_port_vids:
1261 if bridge_vids and bridge_port_vids != bridge_vids:
1262 ifaceobjrunning.update_config('bridge-vids',
1263 ' '.join(bridge_port_vids))
1264
1265 if bridge_port_pvid and bridge_port_pvid != '1':
1266 ifaceobjrunning.update_config('bridge-pvid',
1267 bridge_port_pvid)
1268
1269 self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
1270
1271
1272 def _query_running(self, ifaceobjrunning, **extra_args):
1273 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
1274 self._query_running_bridge(ifaceobjrunning)
1275 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
1276 self._query_running_bridge_port(ifaceobjrunning)
1277
1278 _run_ops = {'pre-up' : _up,
1279 'post-down' : _down,
1280 'query-checkcurr' : _query_check,
1281 'query-running' : _query_running}
1282
1283 def get_ops(self):
1284 """ returns list of ops supported by this module """
1285 return self._run_ops.keys()
1286
1287 def _init_command_handlers(self):
1288 flags = self.get_flags()
1289 if not self.ipcmd:
1290 self.ipcmd = iproute2(**flags)
1291 if not self.brctlcmd:
1292 self.brctlcmd = brctl(**flags)
1293
1294 def run(self, ifaceobj, operation, query_ifaceobj=None,
1295 ifaceobj_getfunc=None):
1296 """ run bridge configuration on the interface object passed as
1297 argument. Can create bridge interfaces if they dont exist already
1298
1299 Args:
1300 **ifaceobj** (object): iface object
1301
1302 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1303 'query-running'
1304
1305 Kwargs:
1306 **query_ifaceobj** (object): query check ifaceobject. This is only
1307 valid when op is 'query-checkcurr'. It is an object same as
1308 ifaceobj, but contains running attribute values and its config
1309 status. The modules can use it to return queried running state
1310 of interfaces. status is success if the running state is same
1311 as user required state in ifaceobj. error otherwise.
1312 """
1313 op_handler = self._run_ops.get(operation)
1314 if not op_handler:
1315 return
1316 self._init_command_handlers()
1317 self._flush_running_vidinfo()
1318 if operation == 'query-checkcurr':
1319 op_handler(self, ifaceobj, query_ifaceobj,
1320 ifaceobj_getfunc=ifaceobj_getfunc)
1321 else:
1322 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)