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