]>
Commit | Line | Data |
---|---|---|
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 | ||
7 | from sets import Set | |
8 | from ifupdown.iface import * | |
8b43d01d | 9 | import ifupdown.policymanager as policymanager |
594fb088 | 10 | from ifupdown.utils import utils |
15ef32ea RP |
11 | from ifupdownaddons.modulebase import moduleBase |
12 | from ifupdownaddons.bridgeutils import brctl | |
13 | from ifupdownaddons.iproute2 import iproute2 | |
d8e3554d | 14 | from collections import Counter |
2864d6f3 | 15 | from ifupdown.netlink import netlink |
fc5e1735 | 16 | import ifupdown.ifupdownflags as ifupdownflags |
15ef32ea RP |
17 | import itertools |
18 | import re | |
48ca05db | 19 | import time |
15ef32ea | 20 | |
4c773918 ST |
21 | class bridgeFlags: |
22 | PORT_PROCESSED = 0x1 | |
641cbd1e | 23 | PORT_PROCESSED_OVERRIDE = 0x2 |
4c773918 | 24 | |
15ef32ea RP |
25 | class 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) |