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