]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/bridge.py
ifupdown2 2.0.0 release
[mirror_ifupdown2.git] / ifupdown2 / addons / bridge.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 import re
8 import time
9 import itertools
10
11 from sets import Set
12 from collections import Counter
13
14 try:
15 import ifupdown2.ifupdown.exceptions as exceptions
16 import ifupdown2.ifupdown.policymanager as policymanager
17 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
18
19 from ifupdown2.nlmanager.nlmanager import Link
20
21 from ifupdown2.ifupdown.iface import *
22 from ifupdown2.ifupdown.utils import utils
23 from ifupdown2.ifupdown.netlink import netlink
24
25 from ifupdown2.ifupdownaddons.cache import *
26 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
27 from ifupdown2.ifupdownaddons.modulebase import moduleBase
28 except ImportError:
29 import ifupdown.exceptions as exceptions
30 import ifupdown.policymanager as policymanager
31 import ifupdown.ifupdownflags as ifupdownflags
32
33 from nlmanager.nlmanager import Link
34
35 from ifupdown.iface import *
36 from ifupdown.utils import utils
37 from ifupdown.netlink import netlink
38
39 from ifupdownaddons.cache import *
40 from ifupdownaddons.LinkUtils import LinkUtils
41 from ifupdownaddons.modulebase import moduleBase
42
43
44 class bridgeFlags:
45 PORT_PROCESSED = 0x1
46 PORT_PROCESSED_OVERRIDE = 0x2
47
48
49 class bridge(moduleBase):
50 """ ifupdown2 addon module to configure linux bridges """
51
52 _modinfo = { 'mhelp' : 'Bridge configuration module. Supports both ' +
53 'vlan aware and non vlan aware bridges. For the vlan ' +
54 'aware bridge, the port specific attributes must be ' +
55 'specified under the port. And for vlan unaware bridge ' +
56 'port specific attributes must be specified under the ' +
57 'bridge.',
58 'attrs' : {
59 'bridge-vlan-aware' :
60 {'help' : 'vlan aware bridge. Setting this ' +
61 'attribute to yes enables vlan filtering' +
62 ' on the bridge',
63 'validvals' : ['yes', 'no'],
64 'example' : ['bridge-vlan-aware yes/no'],
65 'default': 'no'
66 },
67 'bridge-ports' :
68 {'help' : 'bridge ports',
69 'multivalue' : True,
70 'required' : True,
71 'validvals': ['<interface-list>'],
72 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
73 'bridge-ports glob swp1-3.100',
74 'bridge-ports regex (swp[1|2|3].100)']},
75 'bridge-stp' :
76 {'help': 'bridge-stp yes/no',
77 'example' : ['bridge-stp no'],
78 'validvals' : ['yes', 'on', 'off', 'no'],
79 'default' : 'no'},
80 'bridge-bridgeprio' :
81 {'help': 'bridge priority',
82 'validrange' : ['0', '65535'],
83 'example' : ['bridge-bridgeprio 32768'],
84 'default' : '32768'},
85 'bridge-ageing' :
86 {'help': 'bridge ageing',
87 'validrange' : ['0', '65535'],
88 'example' : ['bridge-ageing 300'],
89 'default' : '300'},
90 'bridge-fd' :
91 { 'help' : 'bridge forward delay',
92 'validrange' : ['0', '255'],
93 'example' : ['bridge-fd 15'],
94 'default' : '15'},
95 'bridge-gcint' :
96 # XXX: recheck values
97 { 'help' : 'bridge garbage collection interval in secs',
98 'validrange' : ['0', '255'],
99 'example' : ['bridge-gcint 4'],
100 'default' : '4',
101 'compat' : True,
102 'deprecated': True},
103 'bridge-hello' :
104 { 'help' : 'bridge set hello time',
105 'validrange' : ['0', '255'],
106 'example' : ['bridge-hello 2'],
107 'default' : '2'},
108 'bridge-maxage' :
109 { 'help' : 'bridge set maxage',
110 'validrange' : ['0', '255'],
111 'example' : ['bridge-maxage 20'],
112 'default' : '20'},
113 'bridge-pathcosts' :
114 { 'help' : 'bridge set port path costs',
115 'validvals': ['<interface-range-list>'],
116 'validrange' : ['0', '65535'],
117 'example' : ['under the port (for vlan aware bridge): bridge-pathcosts 100',
118 'under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100'],
119 'default' : '100'},
120 'bridge-portprios' :
121 { 'help' : 'bridge port prios',
122 'validvals': ['<interface-range-list>'],
123 'validrange' : ['0', '65535'],
124 'example' : ['under the port (for vlan aware bridge): bridge-portprios 32',
125 'under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32'],
126 'default' : '32'},
127 'bridge-mclmc' :
128 { 'help' : 'set multicast last member count',
129 'validrange' : ['0', '255'],
130 'example' : ['bridge-mclmc 2'],
131 'default' : '2'},
132 'bridge-mcrouter' :
133 { 'help' : 'set multicast router',
134 'validvals' : ['yes', 'no', '0', '1', '2'],
135 'example' : ['bridge-mcrouter 1'],
136 'default': 'yes'
137 },
138 'bridge-mcsnoop' :
139 { 'help' : 'set multicast snooping',
140 'validvals' : ['yes', 'no', '0', '1'],
141 'default' : 'yes',
142 'example' : ['bridge-mcsnoop yes']},
143 'bridge-mcsqc' :
144 { 'help' : 'set multicast startup query count',
145 'validrange' : ['0', '255'],
146 'default' : '2',
147 'example' : ['bridge-mcsqc 2']},
148 'bridge-mcqifaddr' :
149 { 'help' : 'set multicast query to use ifaddr',
150 'validvals' : ['yes', 'no', '0', '1'],
151 'default' : 'no',
152 'example' : ['bridge-mcqifaddr no']},
153 'bridge-mcquerier' :
154 { 'help' : 'set multicast querier',
155 'validvals' : ['yes', 'no', '0', '1'],
156 'default' : 'no',
157 'example' : ['bridge-mcquerier no']},
158 'bridge-hashel' :
159 { 'help' : 'set hash elasticity',
160 'validrange' : ['0', '4096'],
161 'default' : '4',
162 'example' : ['bridge-hashel 4096']},
163 'bridge-hashmax' :
164 { 'help' : 'set hash max',
165 'validrange' : ['0', '4096'],
166 'default' : '512',
167 'example' : ['bridge-hashmax 4096']},
168 'bridge-mclmi' :
169 { 'help' : 'set multicast last member interval (in secs)',
170 'validrange' : ['0', '255'],
171 'default' : '1',
172 'example' : ['bridge-mclmi 1']},
173 'bridge-mcmi' :
174 { 'help' : 'set multicast membership interval (in secs)',
175 'validrange' : ['0', '255'],
176 'default' : '260',
177 'example' : ['bridge-mcmi 260']},
178 'bridge-mcqpi' :
179 { 'help' : 'set multicast querier interval (in secs)',
180 'validrange' : ['0', '255'],
181 'default' : '255',
182 'example' : ['bridge-mcqpi 255']},
183 'bridge-mcqi' :
184 { 'help' : 'set multicast query interval (in secs)',
185 'validrange' : ['0', '255'],
186 'default' : '125',
187 'example' : ['bridge-mcqi 125']},
188 'bridge-mcqri' :
189 { 'help' : 'set multicast query response interval (in secs)',
190 'validrange' : ['0', '255'],
191 'default' : '10',
192 'example' : ['bridge-mcqri 10']},
193 'bridge-mcsqi' :
194 { 'help' : 'set multicast startup query interval (in secs)',
195 'validrange' : ['0', '255'],
196 'default' : '31',
197 'example' : ['bridge-mcsqi 31']},
198 'bridge-mcqv4src' :
199 { 'help' : 'set per VLAN v4 multicast querier source address',
200 'validvals' : ['<number-ipv4-list>', ],
201 'multivalue' : True,
202 'compat' : True,
203 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
204 'bridge-portmcrouter':
205 {
206 'help': 'set port multicast routers',
207 'validvals': ['<interface-disabled-automatic-enabled>'],
208 'example': [
209 'under the port (for vlan aware bridge): bridge-portmcrouter 0',
210 'under the port (for vlan aware bridge): bridge-portmcrouter 1',
211 'under the port (for vlan aware bridge): bridge-portmcrouter 2',
212 'under the port (for vlan aware bridge): bridge-portmcrouter disabled',
213 'under the port (for vlan aware bridge): bridge-portmcrouter automatic',
214 'under the port (for vlan aware bridge): bridge-portmcrouter enabled',
215 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2',
216 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled',
217 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1',
218 ]
219 },
220 'bridge-portmcfl' :
221 { 'help' : 'port multicast fast leave.',
222 'validvals': ['<interface-yes-no-0-1-list>'],
223 'validrange' : ['yes', 'no', '0', '1'],
224 'default' : 'no',
225 'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
226 'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
227 'bridge-waitport' :
228 { 'help' : 'wait for a max of time secs for the' +
229 ' specified ports to become available,' +
230 'if no ports are specified then those' +
231 ' specified on bridge-ports will be' +
232 ' used here. Specifying no ports here ' +
233 'should not be used if we are using ' +
234 'regex or \"all\" on bridge_ports,' +
235 'as it wouldnt work.',
236 'default' : '0',
237 'validvals': ['<number-interface-list>'],
238 'example' : ['bridge-waitport 4 swp1 swp2']},
239 'bridge-maxwait' :
240 { 'help' : 'forces to time seconds the maximum time ' +
241 'that the Debian bridge setup scripts will ' +
242 'wait for the bridge ports to get to the ' +
243 'forwarding status, doesn\'t allow factional ' +
244 'part. If it is equal to 0 then no waiting' +
245 ' is done',
246 'validrange' : ['0', '255'],
247 'default' : '0',
248 'example' : ['bridge-maxwait 3']},
249 'bridge-vids' :
250 { 'help' : 'bridge port vids. Can be specified ' +
251 'under the bridge or under the port. ' +
252 'If specified under the bridge the ports ' +
253 'inherit it unless overridden by a ' +
254 'bridge-vids attribute under the port',
255 'multivalue' : True,
256 'validvals': ['<number-comma-range-list>'],
257 'example' : ['bridge-vids 4000',
258 'bridge-vids 2000 2200-3000'],
259 'aliases': ['bridge-trunk']},
260 'bridge-pvid' :
261 { 'help' : 'bridge port pvid. Must be specified under' +
262 ' the bridge port',
263 'validrange' : ['0', '4096'],
264 'example' : ['bridge-pvid 1']},
265 'bridge-access' :
266 { 'help' : 'bridge port access vlan. Must be ' +
267 'specified under the bridge port',
268 'validrange' : ['1', '4094'],
269 'example' : ['bridge-access 300']},
270 'bridge-allow-untagged' :
271 { 'help' : 'indicate if the bridge port accepts ' +
272 'untagged packets or not. Must be ' +
273 'specified under the bridge port. ' +
274 'Default is \'yes\'',
275 'validvals' : ['yes', 'no'],
276 'example' : ['bridge-allow-untagged yes'],
277 'default' : 'yes'},
278 'bridge-port-vids' :
279 { 'help' : 'bridge vlans',
280 'compat': True,
281 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
282 'bridge-port-pvids' :
283 { 'help' : 'bridge port vlans',
284 'compat': True,
285 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
286 'bridge-learning' :
287 { 'help' : 'bridge port learning flag',
288 'validvals': ['on', 'off', '<interface-on-off-list>'],
289 'default': 'on',
290 'example' : ['bridge-learning off']},
291 'bridge-igmp-version' :
292 { 'help' : 'mcast igmp version',
293 'validvals': ['2', '3'],
294 'default' : '2',
295 'example' : ['bridge-igmp-version 2']},
296 'bridge-mld-version':
297 { 'help' : 'mcast mld version',
298 'validvals': ['1', '2'],
299 'default' : '1',
300 'example' : ['bridge-mld-version 1']},
301 'bridge-unicast-flood' :
302 { 'help' : 'bridge port unicast flood flag',
303 'validvals': ['on', 'off', '<interface-on-off-list>'],
304 'default': 'on',
305 'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
306 'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
307 'bridge-multicast-flood' :
308 { 'help' : 'bridge port multicast flood flag',
309 'validvals': ['on', 'off', '<interface-on-off-list>'],
310 'default': 'on',
311 'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
312 'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
313 'bridge-vlan-protocol' :
314 { 'help' : 'bridge vlan protocol',
315 'default' : '802.1q',
316 'validvals': ['802.1q', '802.1ad'],
317 'example' : ['bridge-vlan-protocol 802.1q']},
318 'bridge-vlan-stats' :
319 { 'help' : 'bridge vlan stats',
320 'default' : 'off',
321 'validvals': ['on', 'off'],
322 'example' : ['bridge-vlan-stats off']},
323 'bridge-arp-nd-suppress' :
324 { 'help' : 'bridge port arp nd suppress flag',
325 'validvals': ['on', 'off', '<interface-on-off-list>'],
326 'default': 'off',
327 'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
328 'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
329 'bridge-mcstats' :
330 { 'help' : 'bridge multicast stats',
331 'default' : 'off',
332 'validvals': ['on', 'off'],
333 'example' : ['bridge-mcstats off']},
334 'bridge-l2protocol-tunnel': {
335 'help': 'layer 2 protocol tunneling',
336 'validvals': [ # XXX: lists all combinations, should move to
337 # a better representation
338 'all',
339 'cdp',
340 'cdp lacp',
341 'cdp lacp lldp',
342 'cdp lacp lldp pvst',
343 'cdp lacp lldp stp',
344 'cdp lacp pvst',
345 'cdp lacp pvst stp',
346 'cdp lacp stp',
347 'cdp lldp',
348 'cdp lldp pvst',
349 'cdp lldp pvst stp',
350 'cdp lldp stp',
351 'cdp pvst',
352 'cdp pvst stp',
353 'cdp stp',
354 'lacp',
355 'lacp lldp',
356 'lacp lldp pvst',
357 'lacp lldp pvst stp',
358 'lacp lldp stp',
359 'lacp pvst',
360 'lacp pvst stp',
361 'lacp stp',
362 'lldp',
363 'lldp pvst',
364 'lldp pvst stp',
365 'lldp stp',
366 'pvst',
367 'pvst stp',
368 'stp',
369 '<interface-l2protocol-tunnel-list>'],
370 'example': [
371 'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
372 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
373 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
374 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
375 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
376 ]
377 }
378 }}
379
380 # Netlink attributes not associated with ifupdown2
381 # attributes are left commented-out for a future use
382 # and kept in order :)
383 _ifla_br_attributes_map = (
384 # Link.IFLA_BR_UNSPEC,
385 ('bridge-fd', Link.IFLA_BR_FORWARD_DELAY),
386 ('bridge-hello', Link.IFLA_BR_HELLO_TIME),
387 ('bridge-maxage', Link.IFLA_BR_MAX_AGE),
388 ('bridge-ageing', Link.IFLA_BR_AGEING_TIME),
389 ('bridge-stp', Link.IFLA_BR_STP_STATE),
390 ('bridge-bridgeprio', Link.IFLA_BR_PRIORITY),
391 ('bridge-vlan-aware', Link.IFLA_BR_VLAN_FILTERING),
392 ('bridge-vlan-protocol', Link.IFLA_BR_VLAN_PROTOCOL),
393 # Link.IFLA_BR_GROUP_FWD_MASK,
394 # Link.IFLA_BR_ROOT_ID,
395 # Link.IFLA_BR_BRIDGE_ID,
396 # Link.IFLA_BR_ROOT_PORT,
397 # (Link.IFLA_BR_ROOT_PATH_COST,,
398 # Link.IFLA_BR_TOPOLOGY_CHANGE,
399 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
400 # Link.IFLA_BR_HELLO_TIMER,
401 # Link.IFLA_BR_TCN_TIMER,
402 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
403 # Link.IFLA_BR_GC_TIMER,
404 # Link.IFLA_BR_GROUP_ADDR,
405 # Link.IFLA_BR_FDB_FLUSH,
406 ('bridge-mcrouter', Link.IFLA_BR_MCAST_ROUTER),
407 #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
408 ('bridge-mcqifaddr', Link.IFLA_BR_MCAST_QUERY_USE_IFADDR),
409 ('bridge-mcquerier', Link.IFLA_BR_MCAST_QUERIER),
410 ('bridge-hashel', Link.IFLA_BR_MCAST_HASH_ELASTICITY),
411 ('bridge-hashmax', Link.IFLA_BR_MCAST_HASH_MAX),
412 ('bridge-mclmc', Link.IFLA_BR_MCAST_LAST_MEMBER_CNT),
413 ('bridge-mcsqc', Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT),
414 ('bridge-mclmi', Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL),
415 ('bridge-mcmi', Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL),
416 ('bridge-mcqpi', Link.IFLA_BR_MCAST_QUERIER_INTVL),
417 ('bridge-mcqi', Link.IFLA_BR_MCAST_QUERY_INTVL),
418 ('bridge-mcqri', Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL),
419 ('bridge-mcsqi', Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL),
420 # Link.IFLA_BR_NF_CALL_IPTABLES,
421 # Link.IFLA_BR_NF_CALL_IP6TABLES,
422 # Link.IFLA_BR_NF_CALL_ARPTABLES,
423 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
424 # Link.IFLA_BR_PAD,
425 # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
426 ('bridge-igmp-version', Link.IFLA_BR_MCAST_IGMP_VERSION, ),
427 ('bridge-mcstats', Link.IFLA_BR_MCAST_STATS_ENABLED),
428 ('bridge-mld-version', Link.IFLA_BR_MCAST_MLD_VERSION)
429 )
430 # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
431 # they are supported. It is done this way because this dictionary is used
432 # in a loop, but these attributes require additional work. Thus they are
433 # excluded from this loop without overhead.
434
435 # we are still using the old linkCache we need an easy way
436 # to use this cache with the new full-netlink approach
437 _ifla_br_attributes_old_cache_key_map = dict(
438 (
439 (Link.IFLA_BR_FORWARD_DELAY, 'fd'),
440 (Link.IFLA_BR_HELLO_TIME, 'hello'),
441 (Link.IFLA_BR_MAX_AGE, 'maxage'),
442 (Link.IFLA_BR_AGEING_TIME, 'ageing'),
443 (Link.IFLA_BR_STP_STATE, 'stp'),
444 (Link.IFLA_BR_PRIORITY, 'bridgeprio'),
445 (Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering'),
446 (Link.IFLA_BR_VLAN_PROTOCOL, 'vlan-protocol'),
447 (Link.IFLA_BR_MCAST_ROUTER, 'mcrouter'),
448 (Link.IFLA_BR_MCAST_SNOOPING, 'mcsnoop'),
449 (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, 'mcqifaddr'),
450 (Link.IFLA_BR_MCAST_QUERIER, 'mcquerier'),
451 (Link.IFLA_BR_MCAST_HASH_ELASTICITY, 'hashel'),
452 (Link.IFLA_BR_MCAST_HASH_MAX, 'hashmax'),
453 (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, 'mclmc'),
454 (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, 'mcsqc'),
455 (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, 'mclmi'),
456 (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, 'mcmi'),
457 (Link.IFLA_BR_MCAST_QUERIER_INTVL, 'mcqpi'),
458 (Link.IFLA_BR_MCAST_QUERY_INTVL, 'mcqi'),
459 (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, 'mcqri'),
460 (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, 'mcsqi'),
461 (Link.IFLA_BR_VLAN_STATS_ENABLED, 'vlan-stats'),
462 (Link.IFLA_BR_MCAST_STATS_ENABLED, 'mcstats'),
463 (Link.IFLA_BR_MCAST_IGMP_VERSION, 'igmp-version'),
464 (Link.IFLA_BR_MCAST_MLD_VERSION, 'mld-version')
465 )
466 )
467
468 _ifla_br_attributes_translate_user_config_to_netlink_map = dict(
469 (
470 # Link.IFLA_BR_UNSPEC,
471 (Link.IFLA_BR_FORWARD_DELAY, lambda x: int(x) * 100),
472 (Link.IFLA_BR_HELLO_TIME, lambda x: int(x) * 100),
473 (Link.IFLA_BR_MAX_AGE, lambda x: int(x) * 100),
474 (Link.IFLA_BR_AGEING_TIME, lambda x: int(x) * 100),
475 # Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
476 (Link.IFLA_BR_PRIORITY, int),
477 (Link.IFLA_BR_VLAN_FILTERING, utils.get_boolean_from_string),
478 (Link.IFLA_BR_VLAN_PROTOCOL, str),
479 # Link.IFLA_BR_GROUP_FWD_MASK,
480 # Link.IFLA_BR_ROOT_ID,
481 # Link.IFLA_BR_BRIDGE_ID,
482 # Link.IFLA_BR_ROOT_PORT,
483 # Link.IFLA_BR_ROOT_PATH_COST,
484 # Link.IFLA_BR_TOPOLOGY_CHANGE,
485 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
486 # Link.IFLA_BR_HELLO_TIMER,
487 # Link.IFLA_BR_TCN_TIMER,
488 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
489 # Link.IFLA_BR_GC_TIMER,
490 # Link.IFLA_BR_GROUP_ADDR,
491 # Link.IFLA_BR_FDB_FLUSH,
492 (Link.IFLA_BR_MCAST_ROUTER, utils.get_int_from_boolean_and_string),
493 (Link.IFLA_BR_MCAST_SNOOPING, utils.get_boolean_from_string),
494 (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, utils.get_boolean_from_string),
495 (Link.IFLA_BR_MCAST_QUERIER, utils.get_boolean_from_string),
496 (Link.IFLA_BR_MCAST_HASH_ELASTICITY, int),
497 (Link.IFLA_BR_MCAST_HASH_MAX, int),
498 (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, int),
499 (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, int),
500 (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, lambda x: int(x) * 100),
501 (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, lambda x: int(x) * 100),
502 (Link.IFLA_BR_MCAST_QUERIER_INTVL, lambda x: int(x) * 100),
503 (Link.IFLA_BR_MCAST_QUERY_INTVL, lambda x: int(x) * 100),
504 (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, lambda x: int(x) * 100),
505 (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, lambda x: int(x) * 100),
506 # Link.IFLA_BR_NF_CALL_IPTABLES,
507 # Link.IFLA_BR_NF_CALL_IP6TABLES,
508 # Link.IFLA_BR_NF_CALL_ARPTABLES,
509 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
510 # Link.IFLA_BR_PAD,
511 (Link.IFLA_BR_VLAN_STATS_ENABLED, utils.get_boolean_from_string),
512 (Link.IFLA_BR_MCAST_IGMP_VERSION, int),
513 (Link.IFLA_BR_MCAST_STATS_ENABLED, utils.get_boolean_from_string),
514 (Link.IFLA_BR_MCAST_MLD_VERSION, int)
515 )
516 )
517
518 _ifla_brport_attributes_map = (
519 # Link.IFLA_BRPORT_UNSPEC,
520 # Link.IFLA_BRPORT_STATE,
521 ('bridge-portprios', Link.IFLA_BRPORT_PRIORITY),
522 ('bridge-pathcosts', Link.IFLA_BRPORT_COST),
523 # Link.IFLA_BRPORT_MODE,
524 # Link.IFLA_BRPORT_GUARD,
525 # Link.IFLA_BRPORT_PROTECT,
526 ('bridge-portmcfl', Link.IFLA_BRPORT_FAST_LEAVE),
527 ('bridge-learning', Link.IFLA_BRPORT_LEARNING),
528 ('bridge-unicast-flood', Link.IFLA_BRPORT_UNICAST_FLOOD),
529 # Link.IFLA_BRPORT_PROXYARP,
530 # Link.IFLA_BRPORT_LEARNING_SYNC,
531 # Link.IFLA_BRPORT_PROXYARP_WIFI,
532 # Link.IFLA_BRPORT_ROOT_ID,
533 # Link.IFLA_BRPORT_BRIDGE_ID,
534 # Link.IFLA_BRPORT_DESIGNATED_PORT,
535 # Link.IFLA_BRPORT_DESIGNATED_COST,
536 # Link.IFLA_BRPORT_ID,
537 # Link.IFLA_BRPORT_NO,
538 # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
539 # Link.IFLA_BRPORT_CONFIG_PENDING,
540 # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
541 # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
542 # Link.IFLA_BRPORT_HOLD_TIMER,
543 # Link.IFLA_BRPORT_FLUSH,
544 ('bridge-portmcrouter', Link.IFLA_BRPORT_MULTICAST_ROUTER),
545 # Link.IFLA_BRPORT_PAD,
546 ('bridge-multicast-flood', Link.IFLA_BRPORT_MCAST_FLOOD),
547 # Link.IFLA_BRPORT_MCAST_TO_UCAST,
548 # Link.IFLA_BRPORT_VLAN_TUNNEL,
549 # Link.IFLA_BRPORT_BCAST_FLOOD
550 ('bridge-l2protocol-tunnel', Link.IFLA_BRPORT_GROUP_FWD_MASK),
551 # Link.IFLA_BRPORT_PEER_LINK,
552 # Link.IFLA_BRPORT_DUAL_LINK,
553 ('bridge-arp-nd-suppress', Link.IFLA_BRPORT_ARP_SUPPRESS),
554 )
555
556 _ifla_brport_multicast_router_dict_to_int = {
557 'disabled': 0,
558 '0': 0,
559 'no': 0,
560 'automatic': 1,
561 '1': 1,
562 'yes': 1,
563 'enabled': 2,
564 '2': 2,
565 }
566
567 # callable to translate <interface-yes-no-0-1-list> to netlink value
568 _ifla_brport_attributes_translate_user_config_to_netlink_map = dict(
569 (
570 (Link.IFLA_BRPORT_PRIORITY, int),
571 (Link.IFLA_BRPORT_COST, int),
572 (Link.IFLA_BRPORT_MULTICAST_ROUTER, lambda x: bridge._ifla_brport_multicast_router_dict_to_int.get(x, 0)),
573 (Link.IFLA_BRPORT_FAST_LEAVE, utils.get_boolean_from_string),
574 (Link.IFLA_BRPORT_LEARNING, utils.get_boolean_from_string),
575 (Link.IFLA_BRPORT_UNICAST_FLOOD, utils.get_boolean_from_string),
576 (Link.IFLA_BRPORT_MCAST_FLOOD, utils.get_boolean_from_string),
577 (Link.IFLA_BRPORT_GROUP_FWD_MASK, lambda x: x),
578 (Link.IFLA_BRPORT_ARP_SUPPRESS, utils.get_boolean_from_string)
579 )
580 )
581
582 def __init__(self, *args, **kargs):
583 moduleBase.__init__(self, *args, **kargs)
584 self.ipcmd = None
585 self.name = self.__class__.__name__
586 self.brctlcmd = None
587 self._running_vidinfo = {}
588 self._running_vidinfo_valid = False
589 self._resv_vlan_range = self._get_reserved_vlan_range()
590 self.logger.debug('%s: using reserved vlan range %s' % (self.__class__.__name__, str(self._resv_vlan_range)))
591
592 self.default_stp_on = utils.get_boolean_from_string(
593 policymanager.policymanager_api.get_attr_default(
594 module_name=self.__class__.__name__,
595 attr='bridge-stp'
596 )
597 )
598
599 self.default_vlan_stats = policymanager.policymanager_api.get_attr_default(
600 module_name=self.__class__.__name__,
601 attr='bridge-vlan-stats'
602 )
603
604 self.warn_on_untagged_bridge_absence = utils.get_boolean_from_string(
605 policymanager.policymanager_api.get_module_globals(
606 module_name=self.__class__.__name__,
607 attr='warn_on_untagged_bridge_absence'
608 )
609 )
610 self.logger.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
611 % self.warn_on_untagged_bridge_absence)
612
613 self._vxlan_bridge_default_igmp_snooping = policymanager.policymanager_api.get_module_globals(
614 self.__class__.__name__,
615 'vxlan_bridge_default_igmp_snooping'
616 )
617 self.logger.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
618 % self._vxlan_bridge_default_igmp_snooping)
619
620 self.arp_nd_suppress_only_on_vxlan = utils.get_boolean_from_string(
621 policymanager.policymanager_api.get_module_globals(
622 module_name=self.__class__.__name__,
623 attr='allow_arp_nd_suppress_only_on_vxlan'
624 )
625 )
626 self.logger.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self.arp_nd_suppress_only_on_vxlan)
627
628 try:
629 self.bridge_allow_multiple_vlans = utils.get_boolean_from_string(
630 self.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
631 )
632 except:
633 # Cumulus Linux specific variable. Failure probably means that
634 # ifupdown2 is running a a different system.
635 self.bridge_allow_multiple_vlans = True
636 self.logger.debug('bridge: init: multiple vlans allowed %s' % self.bridge_allow_multiple_vlans)
637
638 self.bridge_mac_iface_list = policymanager.policymanager_api.get_module_globals(self.__class__.__name__, 'bridge_mac_iface') or []
639 self.bridge_mac_iface = None, None # ifname, mac
640
641 self.bridge_set_static_mac_from_port = utils.get_boolean_from_string(
642 policymanager.policymanager_api.get_module_globals(
643 self.__class__.__name__, 'bridge_set_static_mac_from_port'
644 )
645 )
646
647 self.l2protocol_tunnel_callback = {
648 'all': self._l2protocol_tunnel_set_all,
649 'stp': self._l2protocol_tunnel_set_stp,
650 'cdp': self._l2protocol_tunnel_set_cdp,
651 'pvst': self._l2protocol_tunnel_set_pvst,
652 'lldp': self._l2protocol_tunnel_set_lldp,
653 'lacp': self._l2protocol_tunnel_set_lacp
654 }
655
656 self.query_check_l2protocol_tunnel_callback = {
657 'all': self._query_check_l2protocol_tunnel_all,
658 'stp': self._query_check_l2protocol_tunnel_stp,
659 'cdp': self._query_check_l2protocol_tunnel_cdp,
660 'pvst': self._query_check_l2protocol_tunnel_pvst,
661 'lldp': self._query_check_l2protocol_tunnel_lldp,
662 'lacp': self._query_check_l2protocol_tunnel_lacp
663 }
664
665 @staticmethod
666 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask, ifla_brport_group_maskhi):
667 ifla_brport_group_maskhi |= 0x1
668 return ifla_brport_group_mask, ifla_brport_group_maskhi
669
670 @staticmethod
671 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask, ifla_brport_group_maskhi):
672 ifla_brport_group_maskhi |= 0x2
673 return ifla_brport_group_mask, ifla_brport_group_maskhi
674
675 @staticmethod
676 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask, ifla_brport_group_maskhi):
677 ifla_brport_group_mask |= 0x1
678 return ifla_brport_group_mask, ifla_brport_group_maskhi
679
680 @staticmethod
681 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask, ifla_brport_group_maskhi):
682 ifla_brport_group_mask |= 0x4
683 return ifla_brport_group_mask, ifla_brport_group_maskhi
684
685 @staticmethod
686 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask, ifla_brport_group_maskhi):
687 ifla_brport_group_mask |= 0x4000
688 return ifla_brport_group_mask, ifla_brport_group_maskhi
689
690 @staticmethod
691 def _l2protocol_tunnel_set_all(ifla_brport_group_mask, ifla_brport_group_maskhi):
692 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
693 return 0x1 | 0x4 | 0x4000, 0x1 | 0x2
694
695 @staticmethod
696 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask, ifla_brport_group_maskhi):
697 return ifla_brport_group_mask & 0x1
698
699 @staticmethod
700 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask, ifla_brport_group_maskhi):
701 return ifla_brport_group_maskhi & 0x2
702
703 @staticmethod
704 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask, ifla_brport_group_maskhi):
705 return ifla_brport_group_maskhi & 0x1
706
707 @staticmethod
708 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask, ifla_brport_group_maskhi):
709 return ifla_brport_group_mask & 0x4000
710
711 @staticmethod
712 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask, ifla_brport_group_maskhi):
713 return ifla_brport_group_mask & 0x4
714
715 @staticmethod
716 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask, ifla_brport_group_maskhi):
717 return ifla_brport_group_mask == (0x1 | 0x4 | 0x4000) and ifla_brport_group_maskhi == (0x1 | 0x2)
718
719 def syntax_check(self, ifaceobj, ifaceobj_getfunc):
720 retval = self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc)
721 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
722 if not self.check_bridge_port_vid_attrs(ifaceobj):
723 retval = False
724 c1 = self.syntax_check_vxlan_in_vlan_aware_br(ifaceobj, ifaceobj_getfunc)
725 c2 = self.syntax_check_bridge_allow_multiple_vlans(ifaceobj, ifaceobj_getfunc)
726 return retval and c1 #and c2
727
728 def syntax_check_bridge_allow_multiple_vlans(self, ifaceobj, ifaceobj_getfunc):
729 result = True
730 if not self.bridge_allow_multiple_vlans and ifaceobj.link_kind & ifaceLinkKind.BRIDGE and ifaceobj.lowerifaces:
731 vlan_id = None
732 for brport_name in ifaceobj.lowerifaces:
733 for obj in ifaceobj_getfunc(brport_name) or []:
734 if obj.link_kind & ifaceLinkKind.VLAN:
735 sub_intf_vlan_id = self._get_vlan_id(obj)
736 if vlan_id and vlan_id != sub_intf_vlan_id:
737 self.logger.error('%s: ignore %s: multiple vlans not allowed under bridge '
738 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
739 % (ifaceobj.name, brport_name))
740 result = False
741 continue
742 vlan_id = sub_intf_vlan_id
743 return result
744
745 def check_bridge_port_vid_attrs(self, ifaceobj):
746 if (ifaceobj.get_attr_value('bridge-access') and
747 (self.get_ifaceobj_bridge_vids_value(ifaceobj) or
748 ifaceobj.get_attr_value('bridge-pvid'))):
749 self.logger.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
750 'will be ignored' % ifaceobj.name)
751 return False
752 return True
753
754 def check_bridge_vlan_aware_port(self, ifaceobj, ifaceobj_getfunc):
755 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
756 ports = self._get_bridge_port_list(ifaceobj)
757 if not ports:
758 return True
759 result = True
760 for port_name in ports:
761 port_obj_l = ifaceobj_getfunc(port_name)
762 if port_obj_l and port_obj_l[0].link_kind & ifaceLinkKind.VLAN:
763 self.logger.error('%s: %s: vlan sub-interface is not '
764 'supported in a vlan-aware bridge'
765 % (ifaceobj.name, port_name))
766 result = False
767 if (port_obj_l and
768 port_obj_l[0].get_attr_value('bridge-arp-nd-suppress') and
769 self.arp_nd_suppress_only_on_vxlan and
770 not port_obj_l[0].link_kind & ifaceLinkKind.VXLAN):
771 self.log_error('\'bridge-arp-nd-suppress\' is not '
772 'supported on a non-vxlan port %s'
773 %port_obj_l[0].name)
774 result = False
775 return result
776 return True
777
778 def _error_vxlan_in_vlan_aware_br(self, ifaceobj, bridgename):
779 self.log_error('`bridge-access` attribute is mandatory when vxlan '
780 'device (%s) is part of vlan aware bridge (%s)'
781 % (ifaceobj.name, bridgename), ifaceobj)
782
783 def syntax_check_vxlan_in_vlan_aware_br(self, ifaceobj, ifaceobj_getfunc):
784 if not ifaceobj_getfunc:
785 return True
786 if (ifaceobj.link_kind & ifaceLinkKind.VXLAN
787 and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
788 if ifaceobj.get_attr_value('bridge-access'):
789 return True
790 for iface in ifaceobj.upperifaces if ifaceobj.upperifaces else []:
791 ifaceobj_upper_list = ifaceobj_getfunc(iface)
792 if not ifaceobj_upper_list:
793 continue
794 ifaceobj_upper = ifaceobj_upper_list[0]
795 bridge_vids = self._get_bridge_vids(iface, ifaceobj_getfunc)
796 if ifaceobj_upper.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
797 vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
798 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
799 if (not vids
800 or not pvid
801 or not self._compare_vids(bridge_vids,
802 vids,
803 pvid=pvid)):
804 self._error_vxlan_in_vlan_aware_br(ifaceobj,
805 ifaceobj_upper.name)
806 return False
807 return True
808
809 @staticmethod
810 def _is_bridge(ifaceobj):
811 return (ifaceobj.link_kind & ifaceLinkKind.BRIDGE or
812 ifaceobj.get_attr_value_first('bridge-ports') or
813 ifaceobj.get_attr_value_first('bridge-vlan-aware'))
814
815 def _get_ifaceobj_bridge_ports(self, ifaceobj, warn=True):
816 ports = ifaceobj.get_attr_value('bridge-ports')
817 if warn and ports and len(ports) > 1:
818 self.log_warn('%s: ignoring duplicate bridge-ports lines: %s'
819 %(ifaceobj.name, ports[1:]))
820 if ports:
821 if 'none' in ports[0]:
822 return []
823 return ports[0]
824 return None
825
826 def _is_bridge_port(self, ifaceobj):
827 if self.brctlcmd.is_bridge_port(ifaceobj.name):
828 return True
829 return False
830
831 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
832 if not self._is_bridge(ifaceobj):
833 return None
834 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
835 ifaceobj.link_type = ifaceLinkType.LINK_MASTER
836 ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
837 # for special vlan aware bridges, we need to add another bit
838 if utils.get_boolean_from_string(ifaceobj.get_attr_value_first('bridge-vlan-aware')):
839 ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
840 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE
841 ifaceobj.role |= ifaceRole.MASTER
842 ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
843 return self.parse_port_list(ifaceobj.name,
844 self._get_ifaceobj_bridge_ports(ifaceobj),
845 ifacenames_all)
846
847 def get_dependent_ifacenames_running(self, ifaceobj):
848 self._init_command_handlers()
849 if not self.brctlcmd.bridge_exists(ifaceobj.name):
850 return None
851 return self.brctlcmd.get_bridge_ports(ifaceobj.name)
852
853 def _get_bridge_port_list(self, ifaceobj):
854
855 # port list is also available in the previously
856 # parsed dependent list. Use that if available, instead
857 # of parsing port expr again
858 port_list = ifaceobj.lowerifaces
859 if port_list:
860 return port_list
861 ports = self._get_ifaceobj_bridge_ports(ifaceobj)
862 if ports:
863 return self.parse_port_list(ifaceobj.name, ports)
864 else:
865 return None
866
867 def _get_bridge_port_list_user_ordered(self, ifaceobj):
868 # When enslaving bridge-ports we need to return the exact user
869 # configured bridge ports list (bridge will inherit the mac of the
870 # first device.
871 ports = self._get_ifaceobj_bridge_ports(ifaceobj)
872 return self.parse_port_list(ifaceobj.name, ports) if ports else None
873
874 def _process_bridge_waitport(self, ifaceobj, portlist):
875 waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
876 if not waitport_value: return
877 try:
878 waitportvals = re.split(r'[\s\t]\s*', waitport_value, 1)
879 if not waitportvals: return
880 try:
881 waitporttime = int(waitportvals[0])
882 except:
883 self.log_warn('%s: invalid waitport value \'%s\''
884 %(ifaceobj.name, waitportvals[0]))
885 return
886 if waitporttime <= 0: return
887 try:
888 waitportlist = self.parse_port_list(ifaceobj.name,
889 waitportvals[1])
890 except IndexError, e:
891 # ignore error and use all bridge ports
892 waitportlist = portlist
893 pass
894 if not waitportlist: return
895 self.logger.info('%s: waiting for ports %s to exist ...'
896 %(ifaceobj.name, str(waitportlist)))
897 starttime = time.time()
898 while ((time.time() - starttime) < waitporttime):
899 if all([False for p in waitportlist
900 if not self.ipcmd.link_exists(p)]):
901 break;
902 time.sleep(1)
903 except Exception, e:
904 self.log_warn('%s: unable to process waitport: %s'
905 %(ifaceobj.name, str(e)))
906
907 def _enable_disable_ipv6(self, port, enable='1'):
908 try:
909 self.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port, enable)
910 except Exception, e:
911 self.logger.info(str(e))
912
913 def handle_ipv6(self, ports, state, ifaceobj=None):
914 if (ifaceobj and
915 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN) and
916 not ifaceobj.get_attr_value('address')):
917 self._enable_disable_ipv6(ifaceobj.name, state)
918 for p in ports:
919 self._enable_disable_ipv6(p, state)
920
921 def _pretty_print_add_ports_error(self, errstr, bridgeifaceobj, bridgeports):
922 """ pretty print bridge port add errors.
923 since the commands are batched and the kernel only returns error
924 codes, this function tries to interpret some error codes
925 and prints clearer errors """
926
927 if re.search('RTNETLINK answers: Invalid argument', errstr):
928 # Cumulus Linux specific error checks
929 try:
930 if self.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
931 vlanid = None
932 for bport in bridgeports:
933 currvlanid = self._get_vlan_id_from_ifacename(bport)
934 if vlanid:
935 if currvlanid != vlanid:
936 self.log_error('%s: ' %bridgeifaceobj.name +
937 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj)
938 break
939 if currvlanid:
940 vlanid = currvlanid
941 except Exception as e:
942 errstr += '\n%s' % str(e)
943 self.log_error(bridgeifaceobj.name + ': ' + errstr, bridgeifaceobj)
944
945 def _add_ports(self, ifaceobj, ifaceobj_getfunc):
946 bridgeports = self._get_bridge_port_list(ifaceobj)
947 runningbridgeports = []
948
949 self.ipcmd.batch_start()
950 self._process_bridge_waitport(ifaceobj, bridgeports)
951 self.ipcmd.batch_start()
952 # Delete active ports not in the new port list
953 if not ifupdownflags.flags.PERFMODE:
954 runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
955 if runningbridgeports:
956 for bport in runningbridgeports:
957 if not bridgeports or bport not in bridgeports:
958 self.ipcmd.link_set(bport, 'nomaster')
959 # set admin DOWN on all removed ports
960 # that don't have config outside bridge
961 if not ifaceobj_getfunc(bport):
962 netlink.link_set_updown(bport, "down")
963 # enable ipv6 for ports that were removed
964 self.handle_ipv6([bport], '0')
965 else:
966 runningbridgeports = []
967 if not bridgeports:
968 self.ipcmd.batch_commit()
969 return []
970 err = 0
971 ports = 0
972 newbridgeports = Set(bridgeports).difference(Set(runningbridgeports))
973 newly_enslaved_ports = []
974
975 newbridgeports_ordered = []
976 for br_port in self._get_bridge_port_list_user_ordered(ifaceobj):
977 if br_port in newbridgeports:
978 newbridgeports_ordered.append(br_port)
979
980 for bridgeport in newbridgeports_ordered:
981 try:
982 if (not ifupdownflags.flags.DRYRUN and
983 not self.ipcmd.link_exists(bridgeport)):
984 self.log_error('%s: bridge port %s does not exist'
985 %(ifaceobj.name, bridgeport), ifaceobj)
986 err += 1
987 continue
988 hwaddress = self.ipcmd.link_get_hwaddress(bridgeport)
989 if not self._valid_ethaddr(hwaddress):
990 self.log_warn('%s: skipping port %s, ' %(ifaceobj.name,
991 bridgeport) + 'invalid ether addr %s'
992 %hwaddress)
993 continue
994 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
995 newly_enslaved_ports.append(bridgeport)
996 self.handle_ipv6([bridgeport], '1')
997 self.ipcmd.addr_flush(bridgeport)
998 ports += 1
999 if ports == 250:
1000 ports = 0
1001 self.ipcmd.batch_commit()
1002 self.ipcmd.batch_start()
1003 except Exception, e:
1004 self.logger.error(str(e))
1005 pass
1006 try:
1007 self.ipcmd.batch_commit()
1008 except Exception, e:
1009 self._pretty_print_add_ports_error(str(e), ifaceobj,
1010 bridgeports)
1011 pass
1012
1013 if err:
1014 self.log_error('bridge configuration failed (missing ports)')
1015
1016 return newly_enslaved_ports
1017
1018 def _process_bridge_maxwait(self, ifaceobj, portlist):
1019 maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
1020 if not maxwait: return
1021 try:
1022 maxwait = int(maxwait)
1023 except:
1024 self.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj.name,
1025 maxwait))
1026 return
1027 if not maxwait: return
1028 self.logger.info('%s: waiting for ports to go to fowarding state ..'
1029 %ifaceobj.name)
1030 try:
1031 starttime = time.time()
1032 while ((time.time() - starttime) < maxwait):
1033 if all([False for p in portlist
1034 if self.read_file_oneline(
1035 '/sys/class/net/%s/brif/%s/state'
1036 %(ifaceobj.name, p)) != '3']):
1037 break;
1038 time.sleep(1)
1039 except Exception, e:
1040 self.log_warn('%s: unable to process maxwait: %s'
1041 %(ifaceobj.name, str(e)))
1042
1043 def _ints_to_ranges(self, ints):
1044 for a, b in itertools.groupby(enumerate(ints), lambda (x, y): y - x):
1045 b = list(b)
1046 yield b[0][1], b[-1][1]
1047
1048 def _ranges_to_ints(self, rangelist):
1049 """ returns expanded list of integers given set of string ranges
1050 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1051 """
1052 result = []
1053 try:
1054 for part in rangelist:
1055 if '-' in part:
1056 a, b = part.split('-')
1057 a, b = int(a), int(b)
1058 result.extend(range(a, b + 1))
1059 else:
1060 a = int(part)
1061 result.append(a)
1062 except:
1063 self.logger.warn('unable to parse vids \'%s\''
1064 %''.join(rangelist))
1065 pass
1066 return result
1067
1068 def _compress_into_ranges(self, vids_ints):
1069 return ['%d' %start if start == end else '%d-%d' %(start, end)
1070 for start, end in self._ints_to_ranges(vids_ints)]
1071
1072 def _diff_vids(self, vids1_ints, vids2_ints):
1073 return Set(vids2_ints).difference(vids1_ints), Set(vids1_ints).difference(vids2_ints)
1074
1075 def _compare_vids(self, vids1, vids2, pvid=None):
1076 """ Returns true if the vids are same else return false """
1077
1078 vids1_ints = self._ranges_to_ints(vids1)
1079 vids2_ints = self._ranges_to_ints(vids2)
1080 set_diff = Set(vids1_ints).symmetric_difference(vids2_ints)
1081 if pvid and int(pvid) in set_diff:
1082 set_diff.remove(int(pvid))
1083 if set_diff:
1084 return False
1085 else:
1086 return True
1087
1088 def _set_bridge_mcqv4src_compat(self, ifaceobj):
1089 #
1090 # Sets old style igmp querier
1091 #
1092 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
1093 if attrval:
1094 running_mcqv4src = {}
1095 if not ifupdownflags.flags.PERFMODE:
1096 running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src(ifaceobj.name)
1097 mcqs = {}
1098 srclist = attrval.split()
1099 for s in srclist:
1100 k, v = s.split('=')
1101 mcqs[k] = v
1102
1103 k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
1104 for v in k_to_del:
1105 self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
1106 for v in mcqs.keys():
1107 self.brctlcmd.bridge_set_mcqv4src(ifaceobj.name, v, mcqs[v])
1108 elif not ifupdownflags.flags.PERFMODE:
1109 running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src(ifaceobj.name)
1110 if running_mcqv4src:
1111 for v in running_mcqv4src.keys():
1112 self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
1113
1114 def _get_running_vidinfo(self):
1115 if self._running_vidinfo_valid:
1116 return self._running_vidinfo
1117 self._running_vidinfo = {}
1118
1119 # Removed check for PERFMODE. Need the get in all cases
1120 # including reboot, so that we can configure the pvid correctly.
1121 self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all_json()
1122 self._running_vidinfo_valid = True
1123 return self._running_vidinfo
1124
1125 def _set_bridge_vidinfo_compat(self, ifaceobj):
1126 #
1127 # Supports old style vlan vid info format
1128 # for compatibility
1129 #
1130 bridge_port_pvids = ifaceobj.get_attr_value_first('bridge-port-pvids')
1131 bridge_port_vids = ifaceobj.get_attr_value_first('bridge-port-vids')
1132 if not bridge_port_pvids and not bridge_port_vids:
1133 return
1134
1135 # Handle bridge vlan attrs
1136 # Install pvids
1137 if bridge_port_pvids:
1138 portlist = self.parse_port_list(ifaceobj.name, bridge_port_pvids)
1139 if not portlist:
1140 self.log_warn('%s: could not parse \'%s %s\''
1141 %(ifaceobj.name, 'bridge-port-pvids',
1142 bridge_port_pvids))
1143 return
1144 for p in portlist:
1145 try:
1146 (port, pvid) = p.split('=')
1147 pvid = int(pvid)
1148 running_pvid = self._get_running_pvid(port)
1149 if running_pvid:
1150 if running_pvid == pvid:
1151 continue
1152 else:
1153 self.ipcmd.bridge_port_pvid_del(port, running_pvid)
1154 self.ipcmd.bridge_port_pvid_add(port, pvid)
1155 except Exception, e:
1156 self.log_warn('%s: failed to set pvid `%s` (%s)'
1157 %(ifaceobj.name, p, str(e)))
1158
1159 # install port vids
1160 if bridge_port_vids:
1161 portlist = self.parse_port_list(ifaceobj.name, bridge_port_vids)
1162 if not portlist:
1163 self.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj.name,
1164 'bridge-port-vids', bridge_port_vids))
1165 return
1166 for p in portlist:
1167 try:
1168 (port, val) = p.split('=')
1169 vids = val.split(',')
1170 vids_int = self._ranges_to_ints(vids)
1171 running_vids = self.ipcmd.bridge_vlan_get_vids(port)
1172 if running_vids:
1173 (vids_to_del, vids_to_add) = \
1174 self._diff_vids(vids_int, running_vids)
1175 if vids_to_del:
1176 self.ipcmd.bridge_port_vids_del(port,
1177 self._compress_into_ranges(vids_to_del))
1178 if vids_to_add:
1179 self.ipcmd.bridge_port_vids_add(port,
1180 self._compress_into_ranges(vids_to_add))
1181 else:
1182 self.ipcmd.bridge_port_vids_add(port, vids_int)
1183 except Exception, e:
1184 self.log_warn('%s: failed to set vid `%s` (%s)'
1185 %(ifaceobj.name, p, str(e)))
1186
1187 def _is_running_stp_state_on(self, bridgename):
1188 """ Returns True if running stp state is on, else False """
1189
1190 stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
1191 try:
1192 running_stp_state = self.read_file_oneline(stp_state_file)
1193 return running_stp_state and running_stp_state != '0'
1194 except:
1195 return False
1196
1197 def _is_config_stp_state_on(self, ifaceobj):
1198 """ Returns true if user specified stp state is on, else False """
1199
1200 stp_attr = ifaceobj.get_attr_value_first('bridge-stp')
1201 if not stp_attr:
1202 return self.default_stp_on
1203 return utils.get_boolean_from_string(stp_attr)
1204
1205 def get_bridge_mcsnoop_value(self, ifaceobj):
1206 mcsnoop = ifaceobj.get_attr_value_first('bridge-mcsnoop')
1207 if not mcsnoop and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN:
1208 return self._vxlan_bridge_default_igmp_snooping
1209 return mcsnoop
1210
1211 def fill_ifla_info_data_with_ifla_br_attribute(self,
1212 ifla_info_data,
1213 link_just_created,
1214 ifname,
1215 nl_attr,
1216 attr_name,
1217 user_config):
1218 try:
1219 translate_func = self._ifla_br_attributes_translate_user_config_to_netlink_map.get(nl_attr)
1220
1221 if not callable(translate_func):
1222 return
1223
1224 if not user_config:
1225 user_config = policymanager.policymanager_api.get_iface_default(
1226 module_name=self.__class__.__name__,
1227 ifname=ifname,
1228 attr=attr_name
1229 )
1230
1231 old_cache_key = self._ifla_br_attributes_old_cache_key_map.get(nl_attr)
1232 if old_cache_key and not link_just_created:
1233 cached_value = self.brctlcmd.link_cache_get([ifname, 'linkinfo', old_cache_key])
1234 if not cached_value:
1235 # the link already exists but we don't have any value
1236 # cached for this attr, it probably means that the
1237 # capability is not available on this system (i.e old kernel)
1238 self.logger.debug('%s: ignoring %s %s: capability '
1239 'probably not supported on this system'
1240 % (ifname, attr_name, user_config))
1241 return
1242 # we need to convert the cache value to "netlink" format
1243 cached_value = translate_func(cached_value.lower())
1244 else:
1245 cached_value = None
1246
1247 if not user_config and not link_just_created and cached_value is not None:
1248 # there is no user configuration for this attribute
1249 # if the bridge existed before we need to check if
1250 # this attribute needs to be reset to default value
1251 default_value = self.get_attr_default_value(attr_name)
1252
1253 if default_value:
1254 # the attribute has a default value, we need to convert it to
1255 # netlink format to compare it with the cache value
1256 default_value_nl = translate_func(default_value) # default_value.lower()
1257
1258 if default_value_nl != cached_value:
1259 # the running value difers from the default value
1260 # but the user didn't specify any config
1261 # resetting attribute to default
1262 ifla_info_data[nl_attr] = default_value_nl
1263 self.logger.info('%s: reset %s to default: %s' % (ifname, attr_name, default_value))
1264 elif user_config:
1265 user_config_nl = translate_func(user_config) # user_config.lower()
1266
1267 if user_config_nl != cached_value:
1268 ifla_info_data[nl_attr] = user_config_nl
1269
1270 if cached_value is not None:
1271 self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value))
1272 else:
1273 self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config))
1274 except Exception as e:
1275 self.logger.warning('%s: %s: %s' % (ifname, attr_name, str(e)))
1276
1277 def up_apply_bridge_settings(self, ifaceobj, link_just_created, bridge_vlan_aware):
1278 ifla_info_data = dict()
1279 ifname = ifaceobj.name
1280
1281 self.logger.info('%s: apply bridge settings' % ifname)
1282
1283 for attr_name, nl_attr in self._ifla_br_attributes_map:
1284 self.fill_ifla_info_data_with_ifla_br_attribute(
1285 ifla_info_data=ifla_info_data,
1286 link_just_created=link_just_created,
1287 ifname=ifname,
1288 nl_attr=nl_attr,
1289 attr_name=attr_name,
1290 user_config=ifaceobj.get_attr_value_first(attr_name)
1291 )
1292
1293 # bridge-mcsnoop
1294 self.fill_ifla_info_data_with_ifla_br_attribute(
1295 ifla_info_data=ifla_info_data,
1296 link_just_created=link_just_created,
1297 ifname=ifname,
1298 nl_attr=Link.IFLA_BR_MCAST_SNOOPING,
1299 attr_name='bridge-mcsnoop',
1300 user_config=self.get_bridge_mcsnoop_value(ifaceobj)
1301 )
1302
1303 # bridge-vlan-stats
1304 if bridge_vlan_aware:
1305 self.fill_ifla_info_data_with_ifla_br_attribute(
1306 ifla_info_data=ifla_info_data,
1307 link_just_created=link_just_created,
1308 ifname=ifname,
1309 nl_attr=Link.IFLA_BR_VLAN_STATS_ENABLED,
1310 attr_name='bridge-vlan-stats',
1311 user_config=ifaceobj.get_attr_value_first('bridge-vlan-stats') or self.default_vlan_stats
1312 )
1313
1314 try:
1315 if self._is_config_stp_state_on(ifaceobj):
1316 if not self._is_running_stp_state_on(ifname):
1317 ifla_info_data[Link.IFLA_BR_STP_STATE] = 1
1318 self.logger.info('%s: stp state reset, reapplying port settings' % ifname)
1319 ifaceobj.module_flags[ifaceobj.name] = \
1320 ifaceobj.module_flags.setdefault(self.name, 0) | \
1321 bridgeFlags.PORT_PROCESSED_OVERRIDE
1322 else:
1323 # If stp not specified and running stp state on, set it to off
1324 if self._is_running_stp_state_on(ifname):
1325 self.logger.info('%s: bridge-stp not specified but running: turning stp off')
1326 ifla_info_data[Link.IFLA_BR_STP_STATE] = 0
1327 except Exception as e:
1328 self.logger.warning('%s: bridge stp: %s' % (ifname, str(e)))
1329
1330 if ifla_info_data:
1331 netlink.link_add_set(ifname=ifname, kind='bridge', ifla_info_data=ifla_info_data, link_exists=True)
1332
1333 def _check_vids(self, ifaceobj, vids):
1334 ret = True
1335 for v in vids:
1336 try:
1337 if '-' in v:
1338 va, vb = v.split('-')
1339 va, vb = int(va), int(vb)
1340 self._handle_reserved_vlan(va, ifaceobj.name, end=vb)
1341 else:
1342 va = int(v)
1343 self._handle_reserved_vlan(va, ifaceobj.name)
1344 except exceptions.ReservedVlanException as e:
1345 raise e
1346 except Exception:
1347 self.logger.warn('%s: unable to parse vid \'%s\''
1348 %(ifaceobj.name, v))
1349 return ret
1350
1351 def _get_running_pvid(self, ifacename):
1352 pvid = 0
1353
1354 running_vidinfo = self._get_running_vidinfo()
1355 for vinfo in running_vidinfo.get(ifacename, {}):
1356 v = vinfo.get('vlan')
1357 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1358 if pvid:
1359 return pvid
1360 return pvid
1361
1362 def _get_running_vids_n_pvid_str(self, ifacename):
1363 vids = []
1364 pvid = None
1365
1366 (vids, pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(ifacename)
1367
1368 if vids:
1369 ret_vids = self._compress_into_ranges(vids)
1370 else:
1371 ret_vids = None
1372
1373 if pvid:
1374 ret_pvid = '%s' %pvid
1375 else:
1376 ret_pvid = None
1377 return (ret_vids, ret_pvid)
1378
1379 def _apply_bridge_vids_and_pvid(self, bportifaceobj, vids, pvid,
1380 isbridge):
1381 """ This method is a combination of methods _apply_bridge_vids and
1382 _apply_bridge_port_pvids above. A combined function is
1383 found necessary to do the deletes first and the adds later
1384 because kernel does honor vid info flags during deletes.
1385
1386 """
1387 if not isbridge and bportifaceobj.link_kind & ifaceLinkKind.VXLAN:
1388 if not vids or not pvid or len(vids) > 1 or vids[0] != pvid:
1389 self._error_vxlan_in_vlan_aware_br(bportifaceobj,
1390 bportifaceobj.upperifaces[0])
1391 return
1392
1393 vids_int = self._ranges_to_ints(vids)
1394 try:
1395 pvid_int = int(pvid) if pvid else 0
1396 except Exception:
1397 self.logger.warn('%s: unable to parse pvid \'%s\''
1398 %(bportifaceobj.name, pvid))
1399 pvid_int = 0
1400 pass
1401
1402 vids_to_del = []
1403 vids_to_add = vids_int
1404 pvid_to_del = None
1405 pvid_to_add = pvid_int
1406
1407 try:
1408 if not self._check_vids(bportifaceobj, vids):
1409 return
1410
1411 (running_vids, running_pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(
1412 bportifaceobj.name)
1413
1414 if not running_vids and not running_pvid:
1415 # There cannot be a no running pvid.
1416 # It might just not be in our cache:
1417 # this can happen if at the time we were
1418 # creating the bridge vlan cache, the port
1419 # was not part of the bridge. And we need
1420 # to make sure both vids and pvid is not in
1421 # the cache, to declare that our cache may
1422 # be stale.
1423 running_pvid = 1
1424 running_vids = [1]
1425
1426 if running_vids:
1427 (vids_to_del, vids_to_add) = \
1428 self._diff_vids(vids_to_add, running_vids)
1429
1430 if running_pvid:
1431 if running_pvid != pvid_int and running_pvid != 0:
1432 pvid_to_del = running_pvid
1433
1434 if (pvid_to_del and (pvid_to_del in vids_int) and
1435 (pvid_to_del not in vids_to_add)):
1436 # kernel deletes dont take into account
1437 # bridge vid flags and its possible that
1438 # the pvid deletes we do end up deleting
1439 # the vids. Be proactive and add the pvid
1440 # to the vid add list if it is in the vids
1441 # and not already part of vids_to_add.
1442 # This helps with a small corner case:
1443 # - running
1444 # pvid 100
1445 # vid 101 102
1446 # - new change is going to move the state to
1447 # pvid 101
1448 # vid 100 102
1449 vids_to_add.add(pvid_to_del)
1450 except exceptions.ReservedVlanException as e:
1451 raise e
1452 except Exception, e:
1453 self.log_error('%s: failed to process vids/pvids'
1454 %bportifaceobj.name + ' vids = %s' %str(vids) +
1455 'pvid = %s ' %pvid + '(%s)' %str(e),
1456 bportifaceobj, raise_error=False)
1457 try:
1458 if vids_to_del:
1459 if pvid_to_add in vids_to_del:
1460 vids_to_del.remove(pvid_to_add)
1461 self.ipcmd.bridge_vids_del(bportifaceobj.name,
1462 self._compress_into_ranges(
1463 vids_to_del), isbridge)
1464 except Exception, e:
1465 self.log_warn('%s: failed to del vid `%s` (%s)'
1466 %(bportifaceobj.name, str(vids_to_del), str(e)))
1467
1468 try:
1469 if pvid_to_del:
1470 self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
1471 pvid_to_del)
1472 except Exception, e:
1473 self.log_warn('%s: failed to del pvid `%s` (%s)'
1474 %(bportifaceobj.name, pvid_to_del, str(e)))
1475
1476 try:
1477 if vids_to_add:
1478 self.ipcmd.bridge_vids_add(bportifaceobj.name,
1479 self._compress_into_ranges(
1480 vids_to_add), isbridge)
1481 except Exception, e:
1482 self.log_error('%s: failed to set vid `%s` (%s)'
1483 %(bportifaceobj.name, str(vids_to_add),
1484 str(e)), bportifaceobj, raise_error=False)
1485
1486 try:
1487 if pvid_to_add and pvid_to_add != running_pvid:
1488 self.ipcmd.bridge_port_pvid_add(bportifaceobj.name,
1489 pvid_to_add)
1490 except Exception, e:
1491 self.log_error('%s: failed to set pvid `%s` (%s)'
1492 %(bportifaceobj.name, pvid_to_add, str(e)),
1493 bportifaceobj)
1494
1495 def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
1496 bridge_vids=None,
1497 bridge_pvid=None):
1498 vids = None
1499 pvids = None
1500 vids_final = []
1501 pvid_final = None
1502 bport_access = bportifaceobj.get_attr_value_first('bridge-access')
1503 if bport_access:
1504 vids = re.split(r'[\s\t]\s*', bport_access)
1505 pvids = vids
1506 allow_untagged = 'yes'
1507 self.check_bridge_port_vid_attrs(bportifaceobj)
1508 else:
1509 allow_untagged = bportifaceobj.get_attr_value_first('bridge-allow-untagged') or 'yes'
1510
1511 bport_vids = self.get_ifaceobj_bridge_vids_value(bportifaceobj)
1512 if bport_vids:
1513 vids = re.split(r'[\s\t,]\s*', bport_vids)
1514
1515 bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
1516 if bport_pvids:
1517 pvids = re.split(r'[\s\t]\s*', bport_pvids)
1518
1519 if vids:
1520 vids_final = vids
1521 elif bridge_vids:
1522 vids_final = bridge_vids
1523
1524 if allow_untagged == 'yes':
1525 if pvids:
1526 pvid_final = pvids[0]
1527 elif bridge_pvid:
1528 pvid_final = bridge_pvid
1529 else:
1530 pvid_final = '1'
1531 else:
1532 pvid_final = None
1533
1534 self._apply_bridge_vids_and_pvid(bportifaceobj, vids_final,
1535 pvid_final, False)
1536
1537 def _apply_bridge_port_settings_all(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware):
1538 err = False
1539
1540 if (ifaceobj.get_attr_value_first('bridge-port-vids') and
1541 ifaceobj.get_attr_value_first('bridge-port-pvids')):
1542 # Old style bridge port vid info
1543 # skip new style setting on ports
1544 return
1545 self.logger.info('%s: applying bridge configuration '
1546 %ifaceobj.name + 'specific to ports')
1547
1548 bridge_vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
1549 if bridge_vids:
1550 bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
1551 else:
1552 bridge_vids = None
1553
1554 bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
1555 if bridge_pvid:
1556 bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)[0]
1557 else:
1558 bridge_pvid = None
1559
1560 if (ifaceobj.module_flags.get(self.name, 0x0) &
1561 bridgeFlags.PORT_PROCESSED_OVERRIDE):
1562 port_processed_override = True
1563 else:
1564 port_processed_override = False
1565
1566 bridgeports = self._get_bridge_port_list(ifaceobj)
1567 if not bridgeports:
1568 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
1569 return
1570 self.ipcmd.batch_start()
1571 for bport in bridgeports:
1572 # Use the brctlcmd bulk set method: first build a dictionary
1573 # and then call set
1574 if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
1575 self.logger.info('%s: skipping bridge config' %ifaceobj.name +
1576 ' for port %s (missing port)' %bport)
1577 continue
1578 self.logger.info('%s: processing bridge config for port %s'
1579 %(ifaceobj.name, bport))
1580 bportifaceobjlist = ifaceobj_getfunc(bport)
1581 if not bportifaceobjlist:
1582 continue
1583 for bportifaceobj in bportifaceobjlist:
1584 # Dont process bridge port if it already has been processed
1585 # and there is no override on port_processed
1586 if (not port_processed_override and
1587 (bportifaceobj.module_flags.get(self.name,0x0) &
1588 bridgeFlags.PORT_PROCESSED)):
1589 continue
1590 try:
1591 # Add attributes specific to the vlan aware bridge
1592 if bridge_vlan_aware:
1593 self._apply_bridge_vlan_aware_port_settings_all(
1594 bportifaceobj, bridge_vids, bridge_pvid)
1595 elif self.warn_on_untagged_bridge_absence:
1596 self._check_untagged_bridge(ifaceobj.name, bportifaceobj, ifaceobj_getfunc)
1597 except exceptions.ReservedVlanException as e:
1598 raise e
1599 except Exception, e:
1600 err = True
1601 self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
1602 pass
1603 self.ipcmd.bridge_batch_commit()
1604 if err:
1605 raise Exception('%s: errors applying port settings' %ifaceobj.name)
1606
1607 def _check_untagged_bridge(self, bridgename, bridgeportifaceobj, ifaceobj_getfunc):
1608 if bridgeportifaceobj.link_kind & ifaceLinkKind.VLAN:
1609 lower_ifaceobj_list = ifaceobj_getfunc(bridgeportifaceobj.lowerifaces[0])
1610 if lower_ifaceobj_list and lower_ifaceobj_list[0] and \
1611 not lower_ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
1612 self.logger.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename)
1613 self.warn_on_untagged_bridge_absence = False
1614
1615 def bridge_port_get_bridge_name(self, ifaceobj):
1616 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
1617 if not bridgename:
1618 # bridge port is not enslaved to a bridge we need to find
1619 # the bridge in it's upper ifaces then enslave it
1620 for u in ifaceobj.upperifaces:
1621 if self.ipcmd.is_bridge(u):
1622 return True, u
1623 return False, None
1624 # return should_enslave port, bridgename
1625 return False, bridgename
1626
1627 def up_bridge_port_vlan_aware_bridge(self, ifaceobj, ifaceobj_getfunc, bridge_name, should_enslave_port):
1628 if should_enslave_port:
1629 netlink.link_set_master(ifaceobj.name, bridge_name)
1630 self.handle_ipv6([ifaceobj.name], '1')
1631
1632 bridge_vids = self._get_bridge_vids(bridge_name, ifaceobj_getfunc)
1633 bridge_pvid = self._get_bridge_pvid(bridge_name, ifaceobj_getfunc)
1634 try:
1635 self._apply_bridge_vlan_aware_port_settings_all(ifaceobj, bridge_vids, bridge_pvid)
1636 except Exception as e:
1637 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
1638 return
1639
1640 def up_bridge_port(self, ifaceobj, ifaceobj_getfunc):
1641 should_enslave_port, bridge_name = self.bridge_port_get_bridge_name(ifaceobj)
1642
1643 if not bridge_name:
1644 # bridge doesn't exist
1645 return
1646
1647 vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridge_name)
1648 if vlan_aware_bridge:
1649 self.up_bridge_port_vlan_aware_bridge(ifaceobj,
1650 ifaceobj_getfunc,
1651 bridge_name,
1652 should_enslave_port)
1653
1654 bridge_ifaceobj = ifaceobj_getfunc(bridge_name)[0]
1655
1656 self.up_apply_brports_attributes(target_ports=[ifaceobj.name],
1657 ifaceobj=bridge_ifaceobj,
1658 ifaceobj_getfunc=ifaceobj_getfunc,
1659 bridge_vlan_aware=vlan_aware_bridge)
1660
1661 ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED
1662
1663 def up_check_bridge_vlan_aware(self, ifaceobj, ifaceobj_getfunc, link_exists):
1664 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
1665 if not self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc):
1666 return False
1667 if link_exists:
1668 ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED_OVERRIDE
1669 return True
1670 return False
1671
1672 @staticmethod
1673 def parse_interface_list_value(user_config):
1674 config = dict()
1675 for entry in user_config.split():
1676 ifname, value = entry.split('=')
1677 config[ifname] = value
1678 return config
1679
1680 def sync_bridge_learning_to_vxlan_brport(self, bridge_name, bridge_vlan_aware, brport_ifaceobj,
1681 brport_name, brport_ifla_info_slave_data, brport_learning):
1682 """
1683 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1684 and
1685 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1686
1687 Checks are not performed in this function and must be verified
1688 before. This is done this way to avoid calling this method on
1689 non vlan & bridge port interfaces thus wasting a bit less time
1690 """
1691
1692 kind = None
1693 ifla_info_data = {}
1694
1695 brport_vxlan_learning_config = brport_ifaceobj.get_attr_value_first('vxlan-learning')
1696 # if the user explicitly defined vxlan-learning we need to honor his config
1697 # and not sync vxlan-learning with bridge-learning
1698
1699 brport_vxlan_learning = self.ipcmd.get_vxlandev_learning(brport_name)
1700
1701 # if BRIDGE_LEARNING is in the desired configuration
1702 # and differs from the running vxlan configuration
1703 if brport_learning is not None and brport_learning != brport_vxlan_learning and not brport_vxlan_learning_config:
1704 kind = 'vxlan'
1705 ifla_info_data = {Link.IFLA_VXLAN_LEARNING: brport_learning}
1706 self.logger.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1707 % (bridge_name, brport_name, brport_learning))
1708
1709 elif brport_learning is None and bridge_vlan_aware:
1710 # is bridge-learning is not configured but the bridge is vlan-aware
1711
1712 running_value = self.ipcmd.get_brport_learning_bool(brport_name)
1713 default_value = utils.get_boolean_from_string(self.get_mod_subattr('bridge-learning', 'default'))
1714
1715 if default_value != running_value:
1716 brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING] = default_value
1717
1718 if not brport_vxlan_learning_config:
1719 kind = 'vxlan'
1720 ifla_info_data = {Link.IFLA_VXLAN_LEARNING: default_value}
1721 self.logger.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1722 % (bridge_name, brport_name, default_value))
1723
1724 # if kind and ifla_info_data are set they will be added to the
1725 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1726 return kind, ifla_info_data
1727
1728 def check_vxlan_brport_arp_suppress(self, ifaceobj, bridge_vlan_aware, brport_ifaceobj, brport_name, user_config):
1729 if user_config:
1730 if self.arp_nd_suppress_only_on_vxlan and not brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
1731 self.logger.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1732 'is not supported on a non-vxlan port'
1733 % (ifaceobj.name, brport_name))
1734 raise Exception()
1735 elif (bridge_vlan_aware and
1736 (not self.arp_nd_suppress_only_on_vxlan or
1737 (self.arp_nd_suppress_only_on_vxlan and
1738 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN))):
1739 return self.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1740 return None
1741
1742 def up_apply_brports_attributes(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware, target_ports=[], newly_enslaved_ports=[]):
1743 ifname = ifaceobj.name
1744
1745 try:
1746 brports_ifla_info_slave_data = dict()
1747 brport_ifaceobj_dict = dict()
1748
1749 running_brports = self.brctlcmd.get_bridge_ports(ifname)
1750
1751 if target_ports:
1752 new_targets = []
1753 for brport_name in target_ports:
1754 if brport_name not in running_brports:
1755 self.logger.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name, ifname))
1756 else:
1757 new_targets.append(brport_name)
1758 running_brports = new_targets
1759
1760 self.logger.info('%s: applying bridge port configuration: %s' % (ifname, running_brports))
1761
1762 # If target_ports is specified we want to configure only this
1763 # sub-list of port we need to check if these ports are already
1764 # enslaved, if not they will be ignored.
1765 # If target_ports is not populated we will apply the brport
1766 # attributes on all running brport.
1767
1768 for port in running_brports:
1769 brport_list = ifaceobj_getfunc(port)
1770 if brport_list:
1771 brport_ifaceobj_dict[port] = brport_list[0]
1772 brports_ifla_info_slave_data[port] = dict()
1773
1774 bridge_ports_learning = {}
1775
1776 # we iterate through all IFLA_BRPORT supported attributes
1777 for attr_name, nl_attr in self._ifla_brport_attributes_map:
1778 br_config = ifaceobj.get_attr_value_first(attr_name)
1779 translate_func = self._ifla_brport_attributes_translate_user_config_to_netlink_map.get(nl_attr)
1780
1781 if not translate_func:
1782 # if no translation function is found,
1783 # we ignore this attribute and continue
1784 continue
1785
1786 if not br_config:
1787 # user didn't specify any value for this attribute
1788 # looking at policy overrides
1789 br_config = policymanager.policymanager_api.get_iface_default(
1790 module_name=self.__class__.__name__,
1791 ifname=ifname,
1792 attr=attr_name
1793 )
1794
1795 if br_config:
1796 #if bridge_vlan_aware:
1797 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1798 # 'should be configured under the ports'
1799 # % (ifname, attr_name, br_config))
1800
1801 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1802 # brport_name: { attr: value }
1803 # example:
1804 # bridge-portprios swp1=5 swp2=32
1805 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1806 if '=' in br_config:
1807 try:
1808 br_config = self.parse_interface_list_value(br_config)
1809 except:
1810 self.log_error('error while parsing \'%s %s\'' % (attr_name, br_config))
1811 continue
1812
1813 for brport_ifaceobj in brport_ifaceobj_dict.values():
1814 brport_config = brport_ifaceobj.get_attr_value_first(attr_name)
1815 brport_name = brport_ifaceobj.name
1816
1817 if not ifupdownflags.flags.PERFMODE and brport_name not in newly_enslaved_ports:
1818 # if the port has just been enslaved, info_slave_data is not cached yet
1819 cached_value = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', nl_attr])
1820 else:
1821 cached_value = None
1822
1823 if not brport_config:
1824 # if a brport attribute was specified under the bridge and not under the port
1825 # we assign the bridge value to the port. If an attribute is both defined under
1826 # the bridge and the brport we keep the value of the port and ignore the br val.
1827 if type(br_config) == dict:
1828 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1829 # br_config is a dictionary, example:
1830 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1831 brport_config = br_config.get(brport_name)
1832 else:
1833 brport_config = br_config
1834
1835 if not brport_config:
1836 brport_config = policymanager.policymanager_api.get_iface_default(
1837 module_name=self.__class__.__name__,
1838 ifname=brport_name,
1839 attr=attr_name
1840 )
1841
1842 user_config = brport_config
1843
1844 # attribute specific work
1845 # This shouldn't be here but we don't really have a choice otherwise this
1846 # will require too much code duplication and will make the code very complex
1847 if nl_attr == Link.IFLA_BRPORT_ARP_SUPPRESS:
1848 try:
1849 arp_suppress = self.check_vxlan_brport_arp_suppress(ifaceobj,
1850 bridge_vlan_aware,
1851 brport_ifaceobj,
1852 brport_name,
1853 user_config)
1854 if arp_suppress:
1855 user_config = arp_suppress
1856 except:
1857 continue
1858 elif nl_attr == Link.IFLA_BRPORT_GROUP_FWD_MASK:
1859 # special handking for group_fwd_mask because Cisco proprietary
1860 # protocol needs to be set via a private netlink attribute
1861 self.ifla_brport_group_fwd_mask(ifname, brport_name,
1862 brports_ifla_info_slave_data,
1863 user_config, cached_value)
1864 continue
1865
1866 #if brport_config:
1867 # if not bridge_vlan_aware:
1868 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1869 # 'should be configured under the bridge'
1870 # % (ifname, brport_name,
1871 # attr_name, brport_config))
1872
1873 if user_config:
1874 user_config_nl = translate_func(user_config)
1875 # check config value against running value
1876 if user_config_nl != cached_value:
1877 brports_ifla_info_slave_data[brport_name][nl_attr] = user_config_nl
1878 self.logger.info('%s: %s: set %s %s' % (ifname, brport_name, attr_name, user_config))
1879 self.logger.debug('(cache %s)' % cached_value)
1880
1881 if nl_attr == Link.IFLA_BRPORT_LEARNING:
1882 # for vxlan-learning sync purposes we need to save the user config for each brports.
1883 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1884 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1885 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1886 # the brport since it might go out of sync for X and Y reasons.
1887 bridge_ports_learning[brport_name] = user_config_nl
1888
1889 elif cached_value is not None:
1890 # no config found, do we need to reset to default?
1891 default = self.get_attr_default_value(attr_name)
1892 if default:
1893 default_netlink = translate_func(default)
1894
1895 if (nl_attr == Link.IFLA_BRPORT_LEARNING
1896 and not ifupdownflags.flags.PERFMODE
1897 and brport_name not in newly_enslaved_ports):
1898 try:
1899 if self.ipcmd.get_brport_peer_link(brport_name):
1900 if default_netlink != cached_value:
1901 self.logger.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1902 % (ifname, brport_name))
1903 continue
1904 bridge_ports_learning[brport_name] = default_netlink
1905 except Exception as e:
1906 self.logger.debug('%s: %s: peerlink check: %s' % (ifname, brport_name, str(e)))
1907
1908 if default_netlink != cached_value:
1909 self.logger.info('%s: %s: %s: no configuration detected, resetting to default %s'
1910 % (ifname, brport_name, attr_name, default))
1911 self.logger.debug('(cache %s)' % cached_value)
1912 brports_ifla_info_slave_data[brport_name][nl_attr] = default_netlink
1913
1914 # applying bridge port configuration via netlink
1915 for brport_name, brport_ifla_info_slave_data in brports_ifla_info_slave_data.items():
1916
1917 brport_ifaceobj = brport_ifaceobj_dict.get(brport_name)
1918 if (brport_ifaceobj
1919 and brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1920 and brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
1921 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1922 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1923 kind, ifla_info_data = self.sync_bridge_learning_to_vxlan_brport(ifaceobj.name,
1924 bridge_vlan_aware,
1925 brport_ifaceobj,
1926 brport_name,
1927 brport_ifla_info_slave_data,
1928 bridge_ports_learning.get(brport_name))
1929 else:
1930 kind = None
1931 ifla_info_data = {}
1932
1933 if brport_ifla_info_slave_data or ifla_info_data:
1934 try:
1935 netlink.link_add_set(ifname=brport_name,
1936 kind=kind,
1937 ifla_info_data=ifla_info_data,
1938 slave_kind='bridge',
1939 ifla_info_slave_data=brport_ifla_info_slave_data)
1940 except Exception as e:
1941 self.logger.warning('%s: %s: %s' % (ifname, brport_name, str(e)))
1942
1943 self._set_bridge_vidinfo_compat(ifaceobj)
1944 self._set_bridge_mcqv4src_compat(ifaceobj)
1945 self._process_bridge_maxwait(ifaceobj, self._get_bridge_port_list(ifaceobj))
1946
1947 except Exception as e:
1948 self.log_error(str(e), ifaceobj)
1949
1950 def ifla_brport_group_fwd_mask(self, ifname, brport_name, brports_ifla_info_slave_data, user_config, cached_ifla_brport_group_fwd_mask):
1951 """
1952 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1953 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1954 field we need to have special handling for that.
1955 """
1956 ifla_brport_group_fwd_mask = 0
1957 ifla_brport_group_fwd_maskhi = 0
1958 if user_config:
1959 for group in re.split(',|\s*', user_config):
1960 if not group:
1961 continue
1962
1963 callback = self.l2protocol_tunnel_callback.get(group)
1964
1965 if not callable(callback):
1966 self.logger.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname, brport_name, group))
1967 else:
1968 ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi = callback(ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi)
1969
1970 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
1971 cached_ifla_brport_group_fwd_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
1972
1973 log_mask_change = True
1974 # if user specify bridge-l2protocol-tunnel stp cdp
1975 # we need to set both MASK and MASKHI but we only want to log once
1976
1977 if cached_ifla_brport_group_fwd_mask is None:
1978 cached_ifla_brport_group_fwd_mask = 0
1979 if cached_ifla_brport_group_fwd_maskhi is None:
1980 cached_ifla_brport_group_fwd_maskhi = 0
1981
1982 # if the cache value is None it means that the kernel doesn't support this attribute
1983 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
1984
1985 if ifla_brport_group_fwd_mask != cached_ifla_brport_group_fwd_mask:
1986 if log_mask_change:
1987 self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
1988 self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask)
1989 log_mask_change = False
1990 brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASK] = ifla_brport_group_fwd_mask
1991
1992 if ifla_brport_group_fwd_maskhi != cached_ifla_brport_group_fwd_maskhi:
1993 if log_mask_change:
1994 self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
1995 self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi)
1996 brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASKHI] = ifla_brport_group_fwd_maskhi
1997
1998 def up_bridge(self, ifaceobj, ifaceobj_getfunc):
1999 ifname = ifaceobj.name
2000
2001 if ifupdownflags.flags.PERFMODE:
2002 link_just_created = True
2003 link_exists = False
2004 else:
2005 link_exists = self.ipcmd.link_exists(ifaceobj.name)
2006 link_just_created = not link_exists
2007
2008 if not link_exists:
2009 netlink.link_add_bridge(ifname)
2010 else:
2011 self.logger.info('%s: bridge already exists' % ifname)
2012
2013 bridge_vlan_aware = self.up_check_bridge_vlan_aware(ifaceobj, ifaceobj_getfunc, not link_just_created)
2014
2015 self.up_apply_bridge_settings(ifaceobj, link_just_created, bridge_vlan_aware)
2016
2017 try:
2018 newly_enslaved_ports = self._add_ports(ifaceobj, ifaceobj_getfunc)
2019 self.up_apply_brports_attributes(ifaceobj, ifaceobj_getfunc, bridge_vlan_aware,
2020 newly_enslaved_ports=newly_enslaved_ports)
2021 except Exception as e:
2022 self.logger.warning('%s: apply bridge ports settings: %s' % (ifname, str(e)))
2023
2024 running_ports = ''
2025 try:
2026 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
2027 if not running_ports:
2028 return
2029 self.handle_ipv6([], '1', ifaceobj=ifaceobj)
2030 self._apply_bridge_port_settings_all(ifaceobj,
2031 ifaceobj_getfunc=ifaceobj_getfunc,
2032 bridge_vlan_aware=bridge_vlan_aware)
2033 except exceptions.ReservedVlanException as e:
2034 raise e
2035 except Exception as e:
2036 self.logger.warning('%s: apply bridge settings: %s' % (ifname, str(e)))
2037 finally:
2038 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
2039 for p in running_ports:
2040 if (ifaceobj_getfunc(p)[0].link_privflags &
2041 ifaceLinkPrivFlags.KEEP_LINK_DOWN):
2042 netlink.link_set_updown(p, "down")
2043 continue
2044 try:
2045 netlink.link_set_updown(p, "up")
2046 except Exception, e:
2047 self.logger.debug('%s: %s: link set up (%s)'
2048 % (ifaceobj.name, p, str(e)))
2049 pass
2050
2051 try:
2052 self._up_bridge_mac(ifaceobj, ifaceobj_getfunc)
2053 except Exception as e:
2054 self.logger.warning('%s: setting bridge mac address: %s' % (ifaceobj.name, str(e)))
2055
2056 def _get_bridge_mac(self, ifaceobj, ifname, ifaceobj_getfunc):
2057 if self.bridge_mac_iface and self.bridge_mac_iface[0] and self.bridge_mac_iface[1]:
2058 return self.bridge_mac_iface
2059
2060 if self.bridge_mac_iface_list:
2061 self.logger.debug('bridge mac iface list: %s' % self.bridge_mac_iface_list)
2062
2063 for bridge_mac_intf in self.bridge_mac_iface_list:
2064 ifaceobj_list = ifaceobj_getfunc(bridge_mac_intf)
2065 iface_mac = None
2066
2067 if ifaceobj_list:
2068 for obj in ifaceobj_list:
2069 iface_user_configured_hwaddress = utils.strip_hwaddress(obj.get_attr_value_first('hwaddress'))
2070 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2071 if iface_user_configured_hwaddress:
2072 iface_mac = iface_user_configured_hwaddress
2073
2074 if not iface_mac and not self.ipcmd.link_exists(bridge_mac_intf):
2075 continue
2076
2077 if not iface_mac:
2078 iface_mac = self.ipcmd.cache_get('link', [bridge_mac_intf, 'hwaddress'])
2079 # if hwaddress attribute is not configured we use the running mac addr
2080
2081 self.bridge_mac_iface = (bridge_mac_intf, iface_mac)
2082 return self.bridge_mac_iface
2083 elif self.bridge_set_static_mac_from_port:
2084 # no policy was provided, we need to get the first physdev or bond ports
2085 # and use its hwaddress to set the bridge mac
2086 for port in self._get_bridge_port_list_user_ordered(ifaceobj) or []:
2087 # iterate through the bridge-port list
2088 for port_obj in ifaceobj_getfunc(port) or []:
2089 # check if the port is a physdev (link_kind is null) or a bon
2090 if port_obj.link_kind != ifaceLinkKind.VXLAN:
2091 iface_user_configured_hwaddress = utils.strip_hwaddress(port_obj.get_attr_value_first('hwaddress'))
2092 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2093 if iface_user_configured_hwaddress:
2094 iface_mac = iface_user_configured_hwaddress.lower()
2095 # we need to "normalize" the user provided MAC so it can match with
2096 # what we have in the cache (data retrieved via a netlink dump by
2097 # nlmanager). nlmanager return all macs in lower-case
2098 else:
2099 iface_mac = self.ipcmd.link_get_hwaddress(port)
2100
2101 if iface_mac:
2102 self.bridge_mac_iface = (port, iface_mac)
2103 return self.bridge_mac_iface
2104
2105 return None, None
2106
2107 def _add_bridge_mac_to_fdb(self, ifaceobj, bridge_mac):
2108 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE and bridge_mac and ifaceobj.get_attr_value('address'):
2109 self.ipcmd.bridge_fdb_add(ifaceobj.name, bridge_mac, vlan=None, bridge=True, remote=None)
2110
2111 def _up_bridge_mac(self, ifaceobj, ifaceobj_getfunc):
2112 """
2113 We have a day one bridge mac changing problem with changing ports
2114 (basically bridge mac changes when the port it inherited the mac from
2115 gets de-enslaved).
2116
2117 We have discussed this problem many times before and tabled it.
2118 The issue has aggravated with vxlan bridge ports having auto-generated
2119 random macs...which change on every reboot.
2120
2121 ifupdown2 extract from policy files an iface to select a mac from and
2122 configure it automatically.
2123 """
2124 if ifaceobj.get_attr_value('hwaddress'):
2125 # if the user configured a static hwaddress
2126 # there is no need to assign one
2127 return
2128
2129 ifname = ifaceobj.name
2130 mac_intf, bridge_mac = self._get_bridge_mac(ifaceobj, ifname, ifaceobj_getfunc)
2131 self.logger.debug("%s: _get_bridge_mac returned (%s, %s)"
2132 %(ifname, mac_intf, bridge_mac))
2133
2134 if bridge_mac:
2135 # if an interface is configured with the following attribute:
2136 # hwaddress 08:00:27:42:42:4
2137 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2138 # from the kernel. The only way to counter that is to convert all mac to int
2139 # and compare the ints, it will increase perfs and be safer.
2140 cached_value = self.ipcmd.cache_get('link', [ifname, 'hwaddress'])
2141 self.logger.debug('%s: cached hwaddress value: %s' % (ifname, cached_value))
2142 if cached_value and cached_value == bridge_mac:
2143 # the bridge mac is already set to the bridge_mac_intf's mac
2144 return
2145
2146 self.logger.info('%s: setting bridge mac to port %s mac' % (ifname, mac_intf))
2147 try:
2148 self.ipcmd.link_set(ifname, 'address', value=bridge_mac, force=True)
2149 except Exception as e:
2150 self.logger.info('%s: %s' % (ifname, str(e)))
2151 # log info this error because the user didn't explicitly configured this
2152 else:
2153 self._add_bridge_mac_to_fdb(ifaceobj, self.ipcmd.link_get_hwaddress(ifname))
2154
2155 def _up(self, ifaceobj, ifaceobj_getfunc=None):
2156 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
2157 self.up_bridge_port(ifaceobj, ifaceobj_getfunc)
2158
2159 elif ifaceobj.link_kind & ifaceLinkKind.BRIDGE:
2160 self.up_bridge(ifaceobj, ifaceobj_getfunc)
2161
2162 def _down(self, ifaceobj, ifaceobj_getfunc=None):
2163 if not self._is_bridge(ifaceobj):
2164 return
2165 ifname = ifaceobj.name
2166 if not self.ipcmd.link_exists(ifname):
2167 return
2168 try:
2169 running_ports = self.brctlcmd.get_bridge_ports(ifname)
2170 if running_ports:
2171 self.handle_ipv6(running_ports, '0')
2172 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
2173 map(lambda p: netlink.link_set_updown(p, 'down'), running_ports)
2174 except Exception as e:
2175 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
2176 try:
2177 netlink.link_del(ifname)
2178 except Exception as e:
2179 ifaceobj.set_status(ifaceStatus.ERROR)
2180 self.logger.error(str(e))
2181 # netlink exception already contains the ifname
2182
2183 def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
2184 running_attrs = {}
2185 if ports:
2186 running_bridge_port_vids = ''
2187 for p in ports:
2188 try:
2189 running_vids = self._get_runing_vids(p)
2190 if running_vids:
2191 running_bridge_port_vids += ' %s=%s' %(p,
2192 ','.join(running_vids))
2193 except Exception:
2194 pass
2195 running_attrs['bridge-port-vids'] = running_bridge_port_vids
2196
2197 running_bridge_port_pvid = ''
2198 for p in ports:
2199 try:
2200 running_pvid = self._get_runing_pvid(p)
2201 if running_pvid:
2202 running_bridge_port_pvid += ' %s=%s' %(p,
2203 running_pvid)
2204 except Exception:
2205 pass
2206 running_attrs['bridge-port-pvids'] = running_bridge_port_pvid
2207
2208 running_bridge_vids = self.ipcmd.bridge_vlan_get_vids(ifaceobjrunning.name)
2209 if running_bridge_vids:
2210 running_attrs['bridge-vids'] = ','.join(self._compress_into_ranges(running_bridge_vids))
2211 return running_attrs
2212
2213 def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
2214 bridgeports=None):
2215 running_attrs = {}
2216
2217 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2218 # so query the ports
2219 running_bridgeport_vids = []
2220 running_bridgeport_pvids = []
2221 for bport in bridgeports:
2222 (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
2223 if vids:
2224 running_bridgeport_vids.append(' '.join(vids))
2225 if pvid:
2226 running_bridgeport_pvids.append(pvid)
2227
2228 bridge_vids = None
2229 if running_bridgeport_vids:
2230 (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
2231 if freq == len(bridgeports):
2232 running_attrs['bridge-vids'] = vidval
2233 bridge_vids = vidval.split()
2234
2235 bridge_pvid = None
2236 if running_bridgeport_pvids:
2237 (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
2238 if freq == len(bridgeports) and vidval != '1':
2239 running_attrs['bridge-pvid'] = vidval
2240 bridge_pvid = vidval.split()[0]
2241
2242 # Go through all bridge ports and find their vids
2243 for bport in bridgeports:
2244 bportifaceobj = ifaceobj_getfunc(bport)
2245 if not bportifaceobj:
2246 continue
2247 bport_vids = []
2248 bport_pvid = None
2249 (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
2250 if vids and vids != bridge_vids:
2251 bport_vids = vids
2252 if pvid and pvid != bridge_pvid:
2253 bport_pvid = pvid
2254 if bport_vids and bport_pvid in bport_vids:
2255 bport_vids.remove(bport_pvid)
2256 if (not bport_vids and bport_pvid and bport_pvid != '1'):
2257 bportifaceobj[0].replace_config('bridge-access', bport_pvid)
2258 bportifaceobj[0].delete_config('bridge-pvid')
2259 bportifaceobj[0].delete_config('bridge-vids')
2260 else:
2261 if bport_pvid and bport_pvid != '1':
2262 bportifaceobj[0].replace_config('bridge-pvid', bport_pvid)
2263 else:
2264 # delete any stale bridge-vids under ports
2265 bportifaceobj[0].delete_config('bridge-pvid')
2266 if bport_vids:
2267 bportifaceobj[0].replace_config('bridge-vids',
2268 ' '.join(bport_vids))
2269 else:
2270 # delete any stale bridge-vids under ports
2271 bportifaceobj[0].delete_config('bridge-vids')
2272 return running_attrs
2273
2274 def _query_running_mcqv4src(self, ifaceobjrunning):
2275 running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src(ifaceobjrunning.name)
2276 mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
2277 mcqs.sort()
2278 mcq = ' '.join(mcqs)
2279 return mcq
2280
2281 def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
2282 bridge_vlan_aware=False):
2283 bridgeattrdict = {}
2284 userspace_stp = 0
2285 ports = None
2286 skip_kernel_stp_attrs = 0
2287
2288 try:
2289 if self.systcl_get_net_bridge_stp_user_space() == '1':
2290 userspace_stp = 1
2291 except Exception as e:
2292 self.logger.info('%s: %s' % (ifaceobjrunning.name, str(e)))
2293
2294 tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
2295 if not tmpbridgeattrdict:
2296 self.logger.warn('%s: unable to get bridge attrs'
2297 %ifaceobjrunning.name)
2298 return bridgeattrdict
2299
2300 # Fill bridge_ports and bridge stp attributes first
2301 ports = tmpbridgeattrdict.get('ports')
2302 if ports:
2303 bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
2304 stp = tmpbridgeattrdict.get('stp', 'no')
2305 if stp != self.get_mod_subattr('bridge-stp', 'default'):
2306 bridgeattrdict['bridge-stp'] = [stp]
2307
2308 if stp == 'yes' and userspace_stp:
2309 skip_kernel_stp_attrs = 1
2310
2311 vlan_stats = utils.get_onff_from_onezero(
2312 tmpbridgeattrdict.get('vlan-stats', None))
2313 if (vlan_stats and
2314 vlan_stats != self.get_mod_subattr('bridge-vlan-stats', 'default')):
2315 bridgeattrdict['bridge-vlan-stats'] = [vlan_stats]
2316
2317 bool2str = {'0': 'no', '1': 'yes'}
2318 # pick all other attributes
2319 for k,v in tmpbridgeattrdict.items():
2320 if not v:
2321 continue
2322 if k == 'ports' or k == 'stp':
2323 continue
2324
2325 if skip_kernel_stp_attrs and k[:2] != 'mc':
2326 # only include igmp attributes if kernel stp is off
2327 continue
2328 attrname = 'bridge-' + k
2329 mod_default = self.get_mod_subattr(attrname, 'default')
2330 if v != mod_default:
2331 # convert '0|1' running values to 'no|yes'
2332 if v in bool2str.keys() and bool2str[v] == mod_default:
2333 continue
2334 bridgeattrdict[attrname] = [v]
2335
2336 if bridge_vlan_aware:
2337 if not ports:
2338 ports = {}
2339 bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
2340 ifaceobj_getfunc,
2341 ports.keys())
2342 else:
2343 bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
2344 ports)
2345 if bridgevidinfo:
2346 bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
2347 if v})
2348
2349 mcq = self._query_running_mcqv4src(ifaceobjrunning)
2350 if mcq:
2351 bridgeattrdict['bridge-mcqv4src'] = [mcq]
2352
2353 if skip_kernel_stp_attrs:
2354 return bridgeattrdict
2355
2356 # Do this only for vlan-UNAWARE-bridge
2357 if ports and not bridge_vlan_aware:
2358 portconfig = {'bridge-pathcosts' : '',
2359 'bridge-portprios' : '',
2360 'bridge-learning' : '',
2361 'bridge-unicast-flood' : '',
2362 'bridge-multicast-flood' : '',
2363 'bridge-arp-nd-suppress' : '',
2364 }
2365 for p, v in ports.items():
2366 v = self.brctlcmd.bridge_get_pathcost(ifaceobjrunning.name, p)
2367 if v and v != self.get_mod_subattr('bridge-pathcosts',
2368 'default'):
2369 portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
2370
2371 v = self.brctlcmd.bridge_get_portprio(ifaceobjrunning.name, p)
2372 if v and v != self.get_mod_subattr('bridge-portprios',
2373 'default'):
2374 portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
2375
2376 v = utils.get_onff_from_onezero(
2377 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2378 p, 'learning'))
2379 if (v and
2380 v != self.get_mod_subattr('bridge-learning', 'default')):
2381 portconfig['bridge-learning'] += ' %s=%s' %(p, v)
2382
2383 v = utils.get_onff_from_onezero(
2384 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2385 p, 'unicast-flood'))
2386 if (v and
2387 v != self.get_mod_subattr('bridge-unicast-flood',
2388 'default')):
2389 portconfig['bridge-unicast-flood'] += ' %s=%s' %(p, v)
2390
2391 v = utils.get_onff_from_onezero(
2392 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2393 p, 'multicast-flood'))
2394 if (v and
2395 v != self.get_mod_subattr('bridge-multicast-flood',
2396 'default')):
2397 portconfig['bridge-multicast-flood'] += ' %s=%s' %(p, v)
2398
2399 v = utils.get_onff_from_onezero(
2400 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2401 p, 'arp-nd-suppress'))
2402 if (v and
2403 v != self.get_mod_subattr('bridge-arp-nd-suppress',
2404 'default')):
2405 portconfig['bridge-arp-nd-suppress'] += ' %s=%s' %(p, v)
2406
2407 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
2408 if v})
2409
2410 return bridgeattrdict
2411
2412 def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
2413 running_mcqs = self._query_running_mcqv4src(ifaceobj)
2414 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
2415 if attrval:
2416 mcqs = attrval.split()
2417 mcqs.sort()
2418 mcqsout = ' '.join(mcqs)
2419 ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
2420 running_mcqs, 1 if running_mcqs != mcqsout else 0)
2421
2422 def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
2423 err = 0
2424 attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
2425 if attrval:
2426 running_bridge_port_vids = ''
2427 portlist = self.parse_port_list(ifaceobj.name, attrval)
2428 if not portlist:
2429 self.log_warn('%s: could not parse \'bridge-port-vids %s\''
2430 %(ifaceobj.name, attrval))
2431 return
2432 err = 0
2433 for p in portlist:
2434 try:
2435 (port, val) = p.split('=')
2436 vids = val.split(',')
2437 running_vids = self.ipcmd.bridge_vlan_get_vids(port)
2438 if running_vids:
2439 if not self._compare_vids(vids, running_vids):
2440 err += 1
2441 running_bridge_port_vids += ' %s=%s' %(port,
2442 ','.join(running_vids))
2443 else:
2444 running_bridge_port_vids += ' %s' %p
2445 else:
2446 err += 1
2447 except Exception, e:
2448 self.log_warn('%s: failure checking vid %s (%s)'
2449 %(ifaceobj.name, p, str(e)))
2450 if err:
2451 ifaceobjcurr.update_config_with_status('bridge-port-vids',
2452 running_bridge_port_vids, 1)
2453 else:
2454 ifaceobjcurr.update_config_with_status('bridge-port-vids',
2455 attrval, 0)
2456
2457 attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
2458 if attrval:
2459 portlist = self.parse_port_list(ifaceobj.name, attrval)
2460 if not portlist:
2461 self.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2462 %(ifaceobj.name, attrval))
2463 return
2464 running_bridge_port_pvids = ''
2465 err = 0
2466 for p in portlist:
2467 try:
2468 (port, pvid) = p.split('=')
2469 running_pvid = self.ipcmd.bridge_vlan_get_vids(port)
2470 if running_pvid and running_pvid == pvid:
2471 running_bridge_port_pvids += ' %s' %p
2472 else:
2473 err += 1
2474 running_bridge_port_pvids += ' %s=%s' %(port,
2475 running_pvid)
2476 except Exception, e:
2477 self.log_warn('%s: failure checking pvid %s (%s)'
2478 %(ifaceobj.name, pvid, str(e)))
2479 if err:
2480 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
2481 running_bridge_port_pvids, 1)
2482 else:
2483 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
2484 running_bridge_port_pvids, 0)
2485
2486 vids = self.get_ifaceobj_bridge_vids(ifaceobj)
2487 if vids[1]:
2488 ifaceobjcurr.update_config_with_status(vids[0], vids[1], -1)
2489
2490 def _query_check_snooping_wdefault(self, ifaceobj):
2491 if (ifupdownflags.flags.WITHDEFAULTS
2492 and not self._vxlan_bridge_default_igmp_snooping
2493 and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN):
2494 ifaceobj.replace_config('bridge-mcsnoop', 'no')
2495
2496 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
2497 ifaceobj_getfunc=None):
2498 if not self._is_bridge(ifaceobj):
2499 return
2500 if not self.brctlcmd.bridge_exists(ifaceobj.name):
2501 self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
2502 return
2503
2504 self._query_check_snooping_wdefault(ifaceobj)
2505
2506 ifaceattrs = self.dict_key_subset(ifaceobj.config,
2507 self.get_mod_attrs())
2508 #Add default attributes if --with-defaults is set
2509 if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in ifaceattrs:
2510 ifaceattrs.append('bridge-stp')
2511 if not ifaceattrs:
2512 return
2513 try:
2514 runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
2515 if not runningattrs:
2516 self.logger.debug('%s: bridge: unable to get bridge attrs'
2517 %ifaceobj.name)
2518 runningattrs = {}
2519 except Exception, e:
2520 self.logger.warn(str(e))
2521 runningattrs = {}
2522
2523 self._query_check_support_yesno_attrs(runningattrs, ifaceobj)
2524
2525 filterattrs = ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2526 'bridge-port-pvids']
2527
2528 diff = Set(ifaceattrs).difference(filterattrs)
2529
2530 if 'bridge-l2protocol-tunnel' in diff:
2531 diff.remove('bridge-l2protocol-tunnel')
2532 # bridge-l2protocol-tunnel requires separate handling
2533
2534 for k in diff:
2535 # get the corresponding ifaceobj attr
2536 v = ifaceobj.get_attr_value_first(k)
2537 if not v:
2538 if ifupdownflags.flags.WITHDEFAULTS and k == 'bridge-stp':
2539 v = 'on' if self.default_stp_on else 'off'
2540 else:
2541 continue
2542 rv = runningattrs.get(k[7:])
2543 if k == 'bridge-mcqv4src':
2544 continue
2545 if k == 'bridge-maxwait' or k == 'bridge-waitport':
2546 ifaceobjcurr.update_config_with_status(k, v, 0)
2547 continue
2548 if k == 'bridge-vlan-aware':
2549 rv = self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)
2550 if (rv and v == 'yes') or (not rv and v == 'no'):
2551 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
2552 v, 0)
2553 else:
2554 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
2555 v, 1)
2556 elif k == 'bridge-stp':
2557 # special case stp compare because it may
2558 # contain more than one valid values
2559 stp_on_vals = ['on', 'yes']
2560 stp_off_vals = ['off', 'no']
2561 if ((v in stp_on_vals and rv in stp_on_vals) or
2562 (v in stp_off_vals and rv in stp_off_vals)):
2563 ifaceobjcurr.update_config_with_status('bridge-stp',
2564 rv, 0)
2565 else:
2566 ifaceobjcurr.update_config_with_status('bridge-stp',
2567 rv, 1)
2568 elif k == 'bridge-ports':
2569 # special case ports because it can contain regex or glob
2570 running_port_list = rv.keys() if rv else []
2571 bridge_port_list = self._get_bridge_port_list(ifaceobj)
2572 if not running_port_list and not bridge_port_list:
2573 continue
2574 portliststatus = 1
2575 if running_port_list and bridge_port_list:
2576 difference = set(running_port_list
2577 ).symmetric_difference(bridge_port_list)
2578 if not difference:
2579 portliststatus = 0
2580 try:
2581 port_list = self._get_ifaceobj_bridge_ports(ifaceobj,
2582 warn=False).split()
2583 # we want to display the same bridge-ports list as provided
2584 # in the interfaces file but if this list contains regexes or
2585 # globs, for now, we won't try to change it.
2586 if 'regex' in port_list or 'glob' in port_list:
2587 port_list = running_port_list
2588 else:
2589 ordered = []
2590 for i in range(0, len(port_list)):
2591 if port_list[i] in running_port_list:
2592 ordered.append(port_list[i])
2593 port_list = ordered
2594 except:
2595 port_list = running_port_list
2596 ifaceobjcurr.update_config_with_status('bridge-ports',
2597 (' '.join(port_list)
2598 if port_list else ''),
2599 portliststatus)
2600 elif k in ['bridge-pathcosts',
2601 'bridge-portprios',
2602 'bridge-portmcrouter',
2603 'bridge-portmcfl',
2604 'bridge-learning',
2605 'bridge-unicast-flood',
2606 'bridge-multicast-flood',
2607 'bridge-arp-nd-suppress',
2608 ]:
2609 if k == 'bridge-arp-nd-suppress':
2610 brctlcmdattrname = k[7:]
2611 else:
2612 brctlcmdattrname = k[7:].rstrip('s')
2613 # for port attributes, the attributes are in a list
2614 # <portname>=<portattrvalue>
2615 status = 0
2616 currstr = ''
2617 vlist = self.parse_port_list(ifaceobj.name, v)
2618 if not vlist:
2619 continue
2620 for vlistitem in vlist:
2621 try:
2622 (p, v) = vlistitem.split('=')
2623 if k in ['bridge-learning',
2624 'bridge-unicast-flood',
2625 'bridge-multicast-flood',
2626 'bridge-arp-nd-suppress',
2627 ]:
2628 currv = utils.get_onoff_bool(
2629 self.brctlcmd.get_bridgeport_attr(
2630 ifaceobj.name, p,
2631 brctlcmdattrname))
2632 else:
2633 currv = self.brctlcmd.get_bridgeport_attr(
2634 ifaceobj.name, p,
2635 brctlcmdattrname)
2636 if currv:
2637 currstr += ' %s=%s' %(p, currv)
2638 else:
2639 currstr += ' %s=%s' %(p, 'None')
2640
2641 if k == 'bridge-portmcrouter':
2642 if self._ifla_brport_multicast_router_dict_to_int.get(v) != int(currv):
2643 status = 1
2644 elif currv != v:
2645 status = 1
2646 except Exception, e:
2647 self.log_warn(str(e))
2648 pass
2649 ifaceobjcurr.update_config_with_status(k, currstr, status)
2650 elif k == 'bridge-vlan-stats' or k == 'bridge-mcstats':
2651 rv = utils.get_onff_from_onezero(rv)
2652 if v != rv:
2653 ifaceobjcurr.update_config_with_status(k, rv, 1)
2654 else:
2655 ifaceobjcurr.update_config_with_status(k, rv, 0)
2656 elif not rv:
2657 if k == 'bridge-pvid' or k == 'bridge-vids' or k == 'bridge-trunk' or k == 'bridge-allow-untagged':
2658 # bridge-pvid and bridge-vids on a bridge does
2659 # not correspond directly to a running config
2660 # on the bridge. They correspond to default
2661 # values for the bridge ports. And they are
2662 # already checked against running config of the
2663 # bridge port and reported against a bridge port.
2664 # So, ignore these attributes under the bridge.
2665 # Use '2' for ignore today. XXX: '2' will be
2666 # mapped to a defined value in subsequent patches.
2667 ifaceobjcurr.update_config_with_status(k, v, 2)
2668 else:
2669 ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
2670 continue
2671 elif v.upper() != rv.upper():
2672 ifaceobjcurr.update_config_with_status(k, rv, 1)
2673 else:
2674 ifaceobjcurr.update_config_with_status(k, rv, 0)
2675
2676 self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
2677
2678 self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
2679 self._query_check_l2protocol_tunnel_on_bridge(ifaceobj, ifaceobjcurr, runningattrs)
2680
2681 def get_ifaceobj_bridge_vids(self, ifaceobj):
2682 vids = ('bridge-vids', ifaceobj.get_attr_value_first('bridge-vids'))
2683 if not vids[1]:
2684 vids = ('bridge-trunk', ifaceobj.get_attr_value_first('bridge-trunk'))
2685 return vids
2686
2687 def get_ifaceobj_bridge_vids_value(self, ifaceobj):
2688 return self.get_ifaceobj_bridge_vids(ifaceobj)[1]
2689
2690 def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
2691 ifaceobjs = ifaceobj_getfunc(bridgename)
2692 for ifaceobj in ifaceobjs:
2693 vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
2694 if vids: return re.split(r'[\s\t,]\s*', vids)
2695 return None
2696
2697 def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
2698 ifaceobjs = ifaceobj_getfunc(bridgename)
2699 pvid = None
2700 for ifaceobj in ifaceobjs:
2701 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
2702 if pvid:
2703 break
2704 return pvid
2705
2706 def _get_bridge_name(self, ifaceobj):
2707 return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
2708
2709 def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
2710 ifaceobj_getfunc, bridgename):
2711 attr_name = 'bridge-access'
2712 vid = ifaceobj.get_attr_value_first(attr_name)
2713 if vid:
2714 (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
2715 ifaceobj.name)
2716 if (not running_pvid or running_pvid != vid or
2717 (running_vids and running_vids[0] != vid)):
2718 ifaceobjcurr.update_config_with_status(attr_name,
2719 running_pvid, 1)
2720 else:
2721 ifaceobjcurr.update_config_with_status(attr_name, vid, 0)
2722 return
2723
2724 (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
2725 ifaceobj.name)
2726 attr_name = 'bridge-pvid'
2727 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
2728 if pvid:
2729 if running_pvid and running_pvid == pvid:
2730 ifaceobjcurr.update_config_with_status(attr_name,
2731 running_pvid, 0)
2732 else:
2733 ifaceobjcurr.update_config_with_status(attr_name,
2734 running_pvid, 1)
2735 elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
2736 ((ifaceobj.flags & iface.HAS_SIBLINGS) and
2737 (ifaceobj.flags & iface.OLDEST_SIBLING))):
2738 # if the interface has multiple iface sections,
2739 # we check the below only for the oldest sibling
2740 # or the last iface section
2741 pvid = self._get_bridge_pvid(bridgename, ifaceobj_getfunc)
2742 if pvid:
2743 if not running_pvid or running_pvid != pvid:
2744 ifaceobjcurr.status = ifaceStatus.ERROR
2745 ifaceobjcurr.status_str = 'bridge pvid error'
2746 elif not running_pvid or running_pvid != '1':
2747 ifaceobjcurr.status = ifaceStatus.ERROR
2748 ifaceobjcurr.status_str = 'bridge pvid error'
2749
2750 attr_name, vids = self.get_ifaceobj_bridge_vids(ifaceobj)
2751 if vids:
2752 vids = re.split(r'[\s\t]\s*', vids)
2753 if not running_vids or not self._compare_vids(vids, running_vids,
2754 running_pvid):
2755 ifaceobjcurr.update_config_with_status(attr_name,
2756 ' '.join(running_vids), 1)
2757 else:
2758 ifaceobjcurr.update_config_with_status(attr_name,
2759 ' '.join(vids), 0)
2760 elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
2761 ((ifaceobj.flags & iface.HAS_SIBLINGS) and
2762 (ifaceobj.flags & iface.OLDEST_SIBLING))):
2763 # if the interface has multiple iface sections,
2764 # we check the below only for the oldest sibling
2765 # or the last iface section
2766
2767 # check if it matches the bridge vids
2768 bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
2769 if (bridge_vids and (not running_vids or
2770 not self._compare_vids(bridge_vids, running_vids, running_pvid))):
2771 ifaceobjcurr.status = ifaceStatus.ERROR
2772 ifaceobjcurr.status_str = 'bridge vid error'
2773
2774 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
2775 ifaceobj_getfunc):
2776 if not self._is_bridge_port(ifaceobj):
2777 # Mark all bridge attributes as failed
2778 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
2779 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2780 'bridge-pathcosts', 'bridge-portprios',
2781 'bridge-portmcrouter',
2782 'bridge-learning',
2783 'bridge-portmcfl', 'bridge-unicast-flood',
2784 'bridge-multicast-flood',
2785 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2786 ], 1)
2787 return
2788 bridgename = self._get_bridge_name(ifaceobj)
2789 if not bridgename:
2790 self.logger.warn('%s: unable to determine bridge name'
2791 %ifaceobj.name)
2792 return
2793
2794 if self.ipcmd.bridge_is_vlan_aware(bridgename):
2795 self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
2796 ifaceobj_getfunc,
2797 bridgename)
2798 for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
2799 'bridge-portprios' : 'portprio',
2800 'bridge-portmcrouter' : 'portmcrouter',
2801 'bridge-portmcfl' : 'portmcfl',
2802 'bridge-learning' : 'learning',
2803 'bridge-unicast-flood' : 'unicast-flood',
2804 'bridge-multicast-flood' : 'multicast-flood',
2805 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2806 }.items():
2807 attrval = ifaceobj.get_attr_value_first(attr)
2808 if not attrval:
2809 continue
2810
2811 try:
2812 running_attrval = self.brctlcmd.get_bridgeport_attr(
2813 bridgename, ifaceobj.name, dstattr)
2814
2815 if dstattr == 'portmcfl':
2816 if not utils.is_binary_bool(attrval) and running_attrval:
2817 running_attrval = utils.get_yesno_boolean(
2818 utils.get_boolean_from_string(running_attrval))
2819 elif dstattr == 'portmcrouter':
2820 if self._ifla_brport_multicast_router_dict_to_int.get(attrval) == int(running_attrval):
2821 ifaceobjcurr.update_config_with_status(attr, attrval, 0)
2822 else:
2823 ifaceobjcurr.update_config_with_status(attr, attrval, 1)
2824 continue
2825 elif dstattr in ['learning',
2826 'unicast-flood',
2827 'multicast-flood',
2828 'arp-nd-suppress',
2829 ]:
2830 if not utils.is_binary_bool(attrval) and running_attrval:
2831 running_attrval = utils.get_onff_from_onezero(
2832 running_attrval)
2833
2834 if running_attrval != attrval:
2835 ifaceobjcurr.update_config_with_status(attr,
2836 running_attrval, 1)
2837 else:
2838 ifaceobjcurr.update_config_with_status(attr,
2839 running_attrval, 0)
2840 except Exception, e:
2841 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
2842
2843 self._query_check_l2protocol_tunnel_on_port(ifaceobj, ifaceobjcurr)
2844
2845 def _query_check_l2protocol_tunnel_on_port(self, ifaceobj, ifaceobjcurr):
2846 user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2847
2848 if user_config_l2protocol_tunnel:
2849 result = 0
2850 try:
2851 self._query_check_l2protocol_tunnel(ifaceobj.name, user_config_l2protocol_tunnel)
2852 except Exception as e:
2853 self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
2854 result = 1
2855 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
2856
2857 def _query_check_l2protocol_tunnel_on_bridge(self, ifaceobj, ifaceobjcurr, bridge_running_attrs):
2858 """
2859 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2860 We need to make sure that all ports comply with the mask given under the bridge
2861 """
2862 user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2863
2864 if user_config_l2protocol_tunnel:
2865 if '=' in user_config_l2protocol_tunnel:
2866 try:
2867 config_per_port_dict = self.parse_interface_list_value(user_config_l2protocol_tunnel)
2868 brport_list = config_per_port_dict.keys()
2869 except:
2870 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, 1)
2871 return
2872 else:
2873 config_per_port_dict = {}
2874 brport_list = bridge_running_attrs.get('ports', {}).keys()
2875 result = 1
2876 try:
2877 for brport_name in brport_list:
2878 self._query_check_l2protocol_tunnel(
2879 brport_name,
2880 config_per_port_dict.get(brport_name) if config_per_port_dict else user_config_l2protocol_tunnel
2881 )
2882 result = 0
2883 except Exception as e:
2884 self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
2885 result = 1
2886 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
2887
2888 def _query_check_l2protocol_tunnel(self, brport_name, user_config_l2protocol_tunnel):
2889 cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
2890 cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
2891
2892 for protocol in re.split(',|\s*', user_config_l2protocol_tunnel):
2893 callback = self.query_check_l2protocol_tunnel_callback.get(protocol)
2894
2895 if callable(callback):
2896 if not callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2897 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2898 % (brport_name, protocol, cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi))
2899
2900 def _query_running_bridge_l2protocol_tunnel(self, brport_name, brport_ifaceobj=None, bridge_ifaceobj=None):
2901 cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
2902 cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
2903 running_protocols = []
2904 for protocol_name, callback in self.query_check_l2protocol_tunnel_callback.items():
2905 if protocol_name == 'all' and callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2906 running_protocols = self.query_check_l2protocol_tunnel_callback.keys()
2907 running_protocols.remove('all')
2908 break
2909 elif callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2910 running_protocols.append(protocol_name)
2911 if running_protocols:
2912 if brport_ifaceobj:
2913 brport_ifaceobj.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols))
2914 elif bridge_ifaceobj:
2915 current_config = bridge_ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2916
2917 if current_config:
2918 bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config, brport_name, ','.join(running_protocols)))
2919 else:
2920 bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name, ','.join(running_protocols)))
2921
2922 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
2923 if self._is_bridge(ifaceobj):
2924 self._query_check_bridge(ifaceobj, ifaceobjcurr)
2925 else:
2926 self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
2927 ifaceobj_getfunc)
2928
2929 def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
2930 if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
2931 ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
2932 ifaceobjrunning.update_config_dict(self._query_running_attrs(
2933 ifaceobjrunning,
2934 ifaceobj_getfunc,
2935 bridge_vlan_aware=True))
2936 else:
2937 ifaceobjrunning.update_config_dict(self._query_running_attrs(
2938 ifaceobjrunning, None))
2939
2940 def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
2941 if self.systcl_get_net_bridge_stp_user_space() == '1':
2942 return
2943
2944 v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
2945 if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
2946 ifaceobjrunning.update_config('bridge-pathcosts', v)
2947
2948 v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
2949 if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
2950 ifaceobjrunning.update_config('bridge-portprios', v)
2951
2952 def _query_running_bridge_port(self, ifaceobjrunning,
2953 ifaceobj_getfunc=None):
2954
2955 bridgename = self.ipcmd.bridge_port_get_bridge_name(
2956 ifaceobjrunning.name)
2957 bridge_vids = None
2958 bridge_pvid = None
2959 if not bridgename:
2960 self.logger.warn('%s: unable to find bridgename'
2961 %ifaceobjrunning.name)
2962 return
2963
2964 if not self.ipcmd.bridge_is_vlan_aware(bridgename):
2965 try:
2966 self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, bridge_ifaceobj=ifaceobj_getfunc(bridgename)[0])
2967 except Exception as e:
2968 self.logger.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning.name, str(e)))
2969 return
2970
2971 self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, brport_ifaceobj=ifaceobjrunning)
2972
2973 (bridge_port_vids, bridge_port_pvid) = self._get_running_vids_n_pvid_str(
2974 ifaceobjrunning.name)
2975 if bridge_port_vids and bridge_port_pvid in bridge_port_vids:
2976 bridge_port_vids.remove(bridge_port_pvid)
2977
2978 bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
2979 if bridgeifaceobjlist:
2980 bridge_vids = bridgeifaceobjlist[0].get_attr_value('bridge-vids')
2981 bridge_pvid = bridgeifaceobjlist[0].get_attr_value_first('bridge-pvid')
2982
2983 if not bridge_port_vids and bridge_port_pvid:
2984 # must be an access port
2985 if bridge_port_pvid != '1':
2986 ifaceobjrunning.update_config('bridge-access',
2987 bridge_port_pvid)
2988 else:
2989 if bridge_port_vids:
2990 if (not bridge_vids or bridge_port_vids != bridge_vids):
2991 ifaceobjrunning.update_config('bridge-vids',
2992 ' '.join(bridge_port_vids))
2993 if bridge_port_pvid and bridge_port_pvid != '1':
2994 if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
2995 ifaceobjrunning.update_config('bridge-pvid',
2996 bridge_port_pvid)
2997
2998 v = utils.get_onff_from_onezero(
2999 self.brctlcmd.get_bridgeport_attr(bridgename,
3000 ifaceobjrunning.name,
3001 'learning'))
3002 if v and v != self.get_mod_subattr('bridge-learning', 'default'):
3003 ifaceobjrunning.update_config('bridge-learning', v)
3004
3005 v = utils.get_onff_from_onezero(
3006 self.brctlcmd.get_bridgeport_attr(bridgename,
3007 ifaceobjrunning.name,
3008 'unicast-flood'))
3009 if v and v != self.get_mod_subattr('bridge-unicast-flood', 'default'):
3010 ifaceobjrunning.update_config('bridge-unicast-flood', v)
3011
3012 v = utils.get_onff_from_onezero(
3013 self.brctlcmd.get_bridgeport_attr(bridgename,
3014 ifaceobjrunning.name,
3015 'multicast-flood'))
3016 if v and v != self.get_mod_subattr('bridge-multicast-flood', 'default'):
3017 ifaceobjrunning.update_config('bridge-multicast-flood', v)
3018
3019 v = utils.get_onff_from_onezero(
3020 self.brctlcmd.get_bridgeport_attr(bridgename,
3021 ifaceobjrunning.name,
3022 'arp-nd-suppress'))
3023 # Display running 'arp-nd-suppress' only on vxlan ports
3024 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3025 # otherwise, display on all bridge-ports
3026
3027 bportifaceobj = ifaceobj_getfunc(ifaceobjrunning.name)[0]
3028 if (v and
3029 v != self.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3030 (not self.arp_nd_suppress_only_on_vxlan or
3031 (self.arp_nd_suppress_only_on_vxlan and
3032 bportifaceobj.link_kind & ifaceLinkKind.VXLAN))):
3033 ifaceobjrunning.update_config('bridge-arp-nd-suppress', v)
3034
3035 self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
3036
3037 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
3038 try:
3039 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
3040 self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
3041 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
3042 self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
3043 except Exception as e:
3044 raise Exception('%s: %s' % (ifaceobjrunning.name, str(e)))
3045
3046 def _query(self, ifaceobj, **kwargs):
3047 """ add default policy attributes supported by the module """
3048 if (not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE) or
3049 ifaceobj.get_attr_value_first('bridge-stp')):
3050 return
3051 if self.default_stp_on:
3052 ifaceobj.update_config('bridge-stp', 'yes')
3053
3054 def _query_check_support_yesno_attrs(self, runningattrs, ifaceobj):
3055 for attrl in [['mcqifaddr', 'bridge-mcqifaddr'],
3056 ['mcquerier', 'bridge-mcquerier'],
3057 ['mcsnoop', 'bridge-mcsnoop']]:
3058 value = ifaceobj.get_attr_value_first(attrl[1])
3059 if value and not utils.is_binary_bool(value):
3060 if attrl[0] in runningattrs:
3061 bool = utils.get_boolean_from_string(runningattrs[attrl[0]])
3062 runningattrs[attrl[0]] = utils.get_yesno_boolean(bool)
3063
3064 self._query_check_mcrouter(ifaceobj, runningattrs)
3065 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'portmcfl', ifaceobj.get_attr_value_first('bridge-portmcfl'))
3066 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'learning', ifaceobj.get_attr_value_first('bridge-learning'))
3067 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'unicast-flood', ifaceobj.get_attr_value_first('bridge-unicast-flood'))
3068 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'multicast-flood', ifaceobj.get_attr_value_first('bridge-multicast-flood'))
3069 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'arp-nd-suppress', ifaceobj.get_attr_value_first('bridge-arp-nd-suppress'))
3070
3071 def _query_check_mcrouter(self, ifaceobj, running_attrs):
3072 """
3073 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3074 """
3075 if 'mcrouter' in running_attrs:
3076 value = ifaceobj.get_attr_value_first('bridge-mcrouter')
3077 if value:
3078 try:
3079 int(value)
3080 except:
3081 running_attrs['mcrouter'] = 'yes' if utils.get_boolean_from_string(running_attrs['mcrouter']) else 'no'
3082
3083 def _query_check_support_yesno_attr_port(self, runningattrs, ifaceobj, attr, attrval):
3084 if attrval:
3085 portlist = self.parse_port_list(ifaceobj.name, attrval)
3086 if portlist:
3087 to_convert = []
3088 for p in portlist:
3089 (port, val) = p.split('=')
3090 if not utils.is_binary_bool(val):
3091 to_convert.append(port)
3092 for port in to_convert:
3093 runningattrs['ports'][port][attr] = utils.get_yesno_boolean(
3094 utils.get_boolean_from_string(runningattrs['ports'][port][attr]))
3095
3096 _run_ops = {
3097 'pre-up': _up,
3098 'post-down': _down,
3099 'query-checkcurr': _query_check,
3100 'query-running': _query_running,
3101 'query': _query
3102 }
3103
3104 def get_ops(self):
3105 """ returns list of ops supported by this module """
3106 return self._run_ops.keys()
3107
3108 def _init_command_handlers(self):
3109 if not self.ipcmd:
3110 self.ipcmd = self.brctlcmd = LinkUtils()
3111
3112 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
3113 """ run bridge configuration on the interface object passed as
3114 argument. Can create bridge interfaces if they dont exist already
3115
3116 Args:
3117 **ifaceobj** (object): iface object
3118
3119 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3120 'query-running'
3121
3122 Kwargs:
3123 **query_ifaceobj** (object): query check ifaceobject. This is only
3124 valid when op is 'query-checkcurr'. It is an object same as
3125 ifaceobj, but contains running attribute values and its config
3126 status. The modules can use it to return queried running state
3127 of interfaces. status is success if the running state is same
3128 as user required state in ifaceobj. error otherwise.
3129 """
3130 op_handler = self._run_ops.get(operation)
3131 if not op_handler:
3132 return
3133 self._init_command_handlers()
3134
3135 if (not LinkUtils.bridge_utils_is_installed
3136 and (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
3137 and LinkUtils.bridge_utils_missing_warning):
3138 self.logger.warning('%s: missing - bridge operation may not work as expected. '
3139 'Please check if \'bridge-utils\' package is installed' % utils.brctl_cmd)
3140 LinkUtils.bridge_utils_missing_warning = False
3141
3142 if operation == 'query-checkcurr':
3143 op_handler(self, ifaceobj, query_ifaceobj,
3144 ifaceobj_getfunc=ifaceobj_getfunc)
3145 else:
3146 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)