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