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