]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/bridge.py
addons: bridge: get default mcsnoop value when bridge_vxlan is not set
[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
1234 if mcsnoop:
1235 return mcsnoop
1236
1237 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN:
1238 if self._vxlan_bridge_default_igmp_snooping is not None:
1239 return self._vxlan_bridge_default_igmp_snooping
1240
1241 return self.get_attr_default_value("bridge-mcsnoop")
1242
1243 def fill_ifla_info_data_with_ifla_br_attribute(self,
1244 ifla_info_data,
1245 link_just_created,
1246 ifname,
1247 nl_attr,
1248 attr_name,
1249 user_config):
1250 try:
1251 translate_func = self._ifla_br_attributes_translate_user_config_to_netlink_map.get(nl_attr)
1252
1253 if not callable(translate_func):
1254 return
1255
1256 if not user_config:
1257 user_config = policymanager.policymanager_api.get_iface_default(
1258 module_name=self.__class__.__name__,
1259 ifname=ifname,
1260 attr=attr_name
1261 )
1262
1263 old_cache_key = self._ifla_br_attributes_old_cache_key_map.get(nl_attr)
1264 if old_cache_key and not link_just_created:
1265 cached_value = self.brctlcmd.link_cache_get([ifname, 'linkinfo', old_cache_key])
1266 if not cached_value or cached_value == "None":
1267 # the link already exists but we don't have any value
1268 # cached for this attr, it probably means that the
1269 # capability is not available on this system (i.e old kernel)
1270 self.logger.debug('%s: ignoring %s %s: capability '
1271 'probably not supported on this system'
1272 % (ifname, attr_name, user_config))
1273 return
1274 # we need to convert the cache value to "netlink" format
1275 cached_value = translate_func(cached_value.lower())
1276 else:
1277 cached_value = None
1278
1279 if not user_config and not link_just_created and cached_value is not None:
1280 # there is no user configuration for this attribute
1281 # if the bridge existed before we need to check if
1282 # this attribute needs to be reset to default value
1283 default_value = self.get_attr_default_value(attr_name)
1284
1285 if default_value:
1286 # the attribute has a default value, we need to convert it to
1287 # netlink format to compare it with the cache value
1288 default_value_nl = translate_func(default_value) # default_value.lower()
1289
1290 if default_value_nl != cached_value:
1291 # the running value difers from the default value
1292 # but the user didn't specify any config
1293 # resetting attribute to default
1294 ifla_info_data[nl_attr] = default_value_nl
1295 self.logger.info('%s: reset %s to default: %s' % (ifname, attr_name, default_value))
1296 elif user_config:
1297 user_config_nl = translate_func(user_config) # user_config.lower()
1298
1299 if user_config_nl != cached_value:
1300 ifla_info_data[nl_attr] = user_config_nl
1301
1302 if cached_value is not None:
1303 self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value))
1304 else:
1305 self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config))
1306 except Exception as e:
1307 self.logger.warning('%s: %s: %s' % (ifname, attr_name, str(e)))
1308
1309 def up_apply_bridge_settings(self, ifaceobj, link_just_created, bridge_vlan_aware):
1310 ifla_info_data = dict()
1311 ifname = ifaceobj.name
1312
1313 self.logger.info('%s: apply bridge settings' % ifname)
1314
1315 for attr_name, nl_attr in self._ifla_br_attributes_map:
1316 self.fill_ifla_info_data_with_ifla_br_attribute(
1317 ifla_info_data=ifla_info_data,
1318 link_just_created=link_just_created,
1319 ifname=ifname,
1320 nl_attr=nl_attr,
1321 attr_name=attr_name,
1322 user_config=ifaceobj.get_attr_value_first(attr_name)
1323 )
1324
1325 # bridge-mcsnoop
1326 self.fill_ifla_info_data_with_ifla_br_attribute(
1327 ifla_info_data=ifla_info_data,
1328 link_just_created=link_just_created,
1329 ifname=ifname,
1330 nl_attr=Link.IFLA_BR_MCAST_SNOOPING,
1331 attr_name='bridge-mcsnoop',
1332 user_config=self.get_bridge_mcsnoop_value(ifaceobj)
1333 )
1334
1335 # bridge-vlan-stats
1336 if bridge_vlan_aware:
1337 self.fill_ifla_info_data_with_ifla_br_attribute(
1338 ifla_info_data=ifla_info_data,
1339 link_just_created=link_just_created,
1340 ifname=ifname,
1341 nl_attr=Link.IFLA_BR_VLAN_STATS_ENABLED,
1342 attr_name='bridge-vlan-stats',
1343 user_config=ifaceobj.get_attr_value_first('bridge-vlan-stats') or self.default_vlan_stats
1344 )
1345
1346 try:
1347 if self._is_config_stp_state_on(ifaceobj):
1348 if not self._is_running_stp_state_on(ifname):
1349 ifla_info_data[Link.IFLA_BR_STP_STATE] = 1
1350 self.logger.info('%s: stp state reset, reapplying port settings' % ifname)
1351 ifaceobj.module_flags[ifaceobj.name] = \
1352 ifaceobj.module_flags.setdefault(self.name, 0) | \
1353 bridgeFlags.PORT_PROCESSED_OVERRIDE
1354 else:
1355 # If stp not specified and running stp state on, set it to off
1356 if self._is_running_stp_state_on(ifname):
1357 self.logger.info('%s: bridge-stp not specified but running: turning stp off')
1358 ifla_info_data[Link.IFLA_BR_STP_STATE] = 0
1359 except Exception as e:
1360 self.logger.warning('%s: bridge stp: %s' % (ifname, str(e)))
1361
1362 if ifla_info_data:
1363 netlink.link_add_set(ifname=ifname, kind='bridge', ifla_info_data=ifla_info_data, link_exists=True)
1364
1365 def _check_vids(self, ifaceobj, vids):
1366 ret = True
1367 for v in vids:
1368 try:
1369 if '-' in v:
1370 va, vb = v.split('-')
1371 va, vb = int(va), int(vb)
1372 self._handle_reserved_vlan(va, ifaceobj.name, end=vb)
1373 else:
1374 va = int(v)
1375 self._handle_reserved_vlan(va, ifaceobj.name)
1376 except exceptions.ReservedVlanException as e:
1377 raise e
1378 except Exception:
1379 self.logger.warn('%s: unable to parse vid \'%s\''
1380 %(ifaceobj.name, v))
1381 return ret
1382
1383 def _get_running_pvid(self, ifacename):
1384 pvid = 0
1385
1386 running_vidinfo = self._get_running_vidinfo()
1387 for vinfo in running_vidinfo.get(ifacename, {}):
1388 v = vinfo.get('vlan')
1389 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1390 if pvid:
1391 return pvid
1392 return pvid
1393
1394 def _get_running_vids_n_pvid_str(self, ifacename):
1395 vids = []
1396 pvid = None
1397
1398 (vids, pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(ifacename)
1399
1400 if vids:
1401 ret_vids = self._compress_into_ranges(vids)
1402 else:
1403 ret_vids = None
1404
1405 if pvid:
1406 ret_pvid = '%s' %pvid
1407 else:
1408 ret_pvid = None
1409 return (ret_vids, ret_pvid)
1410
1411 def _apply_bridge_vids_and_pvid(self, bportifaceobj, vids, pvid,
1412 isbridge):
1413 """ This method is a combination of methods _apply_bridge_vids and
1414 _apply_bridge_port_pvids above. A combined function is
1415 found necessary to do the deletes first and the adds later
1416 because kernel does honor vid info flags during deletes.
1417
1418 """
1419 if not isbridge and bportifaceobj.link_kind & ifaceLinkKind.VXLAN:
1420 if not vids or not pvid or len(vids) > 1 or vids[0] != pvid:
1421 self._error_vxlan_in_vlan_aware_br(bportifaceobj,
1422 bportifaceobj.upperifaces[0])
1423 return
1424
1425 vids_int = self._ranges_to_ints(vids)
1426 try:
1427 pvid_int = int(pvid) if pvid else 0
1428 except Exception:
1429 self.logger.warn('%s: unable to parse pvid \'%s\''
1430 %(bportifaceobj.name, pvid))
1431 pvid_int = 0
1432 pass
1433
1434 vids_to_del = []
1435 vids_to_add = vids_int
1436 pvid_to_del = None
1437 pvid_to_add = pvid_int
1438
1439 try:
1440 if not self._check_vids(bportifaceobj, vids):
1441 return
1442
1443 (running_vids, running_pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(
1444 bportifaceobj.name)
1445
1446 if not running_vids and not running_pvid:
1447 # There cannot be a no running pvid.
1448 # It might just not be in our cache:
1449 # this can happen if at the time we were
1450 # creating the bridge vlan cache, the port
1451 # was not part of the bridge. And we need
1452 # to make sure both vids and pvid is not in
1453 # the cache, to declare that our cache may
1454 # be stale.
1455 running_pvid = 1
1456 running_vids = [1]
1457
1458 if running_vids:
1459 (vids_to_del, vids_to_add) = \
1460 self._diff_vids(vids_to_add, running_vids)
1461
1462 if running_pvid:
1463 if running_pvid != pvid_int and running_pvid != 0:
1464 pvid_to_del = running_pvid
1465
1466 if (pvid_to_del and (pvid_to_del in vids_int) and
1467 (pvid_to_del not in vids_to_add)):
1468 # kernel deletes dont take into account
1469 # bridge vid flags and its possible that
1470 # the pvid deletes we do end up deleting
1471 # the vids. Be proactive and add the pvid
1472 # to the vid add list if it is in the vids
1473 # and not already part of vids_to_add.
1474 # This helps with a small corner case:
1475 # - running
1476 # pvid 100
1477 # vid 101 102
1478 # - new change is going to move the state to
1479 # pvid 101
1480 # vid 100 102
1481 vids_to_add.add(pvid_to_del)
1482 except exceptions.ReservedVlanException as e:
1483 raise e
1484 except Exception, e:
1485 self.log_error('%s: failed to process vids/pvids'
1486 %bportifaceobj.name + ' vids = %s' %str(vids) +
1487 'pvid = %s ' %pvid + '(%s)' %str(e),
1488 bportifaceobj, raise_error=False)
1489 try:
1490 if vids_to_del:
1491 if pvid_to_add in vids_to_del:
1492 vids_to_del.remove(pvid_to_add)
1493 self.ipcmd.bridge_vids_del(bportifaceobj.name,
1494 self._compress_into_ranges(
1495 vids_to_del), isbridge)
1496 except Exception, e:
1497 self.log_warn('%s: failed to del vid `%s` (%s)'
1498 %(bportifaceobj.name, str(vids_to_del), str(e)))
1499
1500 try:
1501 if pvid_to_del:
1502 self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
1503 pvid_to_del)
1504 except Exception, e:
1505 self.log_warn('%s: failed to del pvid `%s` (%s)'
1506 %(bportifaceobj.name, pvid_to_del, str(e)))
1507
1508 try:
1509 if vids_to_add:
1510 self.ipcmd.bridge_vids_add(bportifaceobj.name,
1511 self._compress_into_ranges(
1512 vids_to_add), isbridge)
1513 except Exception, e:
1514 self.log_error('%s: failed to set vid `%s` (%s)'
1515 %(bportifaceobj.name, str(vids_to_add),
1516 str(e)), bportifaceobj, raise_error=False)
1517
1518 try:
1519 if pvid_to_add and pvid_to_add != running_pvid:
1520 self.ipcmd.bridge_port_pvid_add(bportifaceobj.name,
1521 pvid_to_add)
1522 except Exception, e:
1523 self.log_error('%s: failed to set pvid `%s` (%s)'
1524 %(bportifaceobj.name, pvid_to_add, str(e)),
1525 bportifaceobj)
1526
1527 def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
1528 bridge_vids=None,
1529 bridge_pvid=None):
1530 vids = None
1531 pvids = None
1532 vids_final = []
1533 pvid_final = None
1534 bport_access = bportifaceobj.get_attr_value_first('bridge-access')
1535 if bport_access:
1536 vids = re.split(r'[\s\t]\s*', bport_access)
1537 pvids = vids
1538 allow_untagged = 'yes'
1539 self.check_bridge_port_vid_attrs(bportifaceobj)
1540 else:
1541 allow_untagged = bportifaceobj.get_attr_value_first('bridge-allow-untagged') or 'yes'
1542
1543 bport_vids = self.get_ifaceobj_bridge_vids_value(bportifaceobj)
1544 if bport_vids:
1545 vids = re.split(r'[\s\t,]\s*', bport_vids)
1546
1547 bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
1548 if bport_pvids:
1549 pvids = re.split(r'[\s\t]\s*', bport_pvids)
1550
1551 if vids:
1552 vids_final = vids
1553 elif bridge_vids:
1554 vids_final = bridge_vids
1555
1556 if allow_untagged == 'yes':
1557 if pvids:
1558 pvid_final = pvids[0]
1559 elif bridge_pvid:
1560 pvid_final = bridge_pvid
1561 else:
1562 pvid_final = '1'
1563 else:
1564 pvid_final = None
1565
1566 self._apply_bridge_vids_and_pvid(bportifaceobj, vids_final,
1567 pvid_final, False)
1568
1569 def _apply_bridge_port_settings_all(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware):
1570 err = False
1571
1572 if (ifaceobj.get_attr_value_first('bridge-port-vids') and
1573 ifaceobj.get_attr_value_first('bridge-port-pvids')):
1574 # Old style bridge port vid info
1575 # skip new style setting on ports
1576 return
1577 self.logger.info('%s: applying bridge configuration '
1578 %ifaceobj.name + 'specific to ports')
1579
1580 bridge_vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
1581 if bridge_vids:
1582 bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
1583 else:
1584 bridge_vids = None
1585
1586 bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
1587 if bridge_pvid:
1588 bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)[0]
1589 else:
1590 bridge_pvid = None
1591
1592 if (ifaceobj.module_flags.get(self.name, 0x0) &
1593 bridgeFlags.PORT_PROCESSED_OVERRIDE):
1594 port_processed_override = True
1595 else:
1596 port_processed_override = False
1597
1598 bridgeports = self._get_bridge_port_list(ifaceobj)
1599 if not bridgeports:
1600 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
1601 return
1602 self.ipcmd.batch_start()
1603 for bport in bridgeports:
1604 # Use the brctlcmd bulk set method: first build a dictionary
1605 # and then call set
1606 if not self.ipcmd.bridge_port_exists(ifaceobj.name, bport):
1607 self.logger.info('%s: skipping bridge config' %ifaceobj.name +
1608 ' for port %s (missing port)' %bport)
1609 continue
1610 self.logger.info('%s: processing bridge config for port %s'
1611 %(ifaceobj.name, bport))
1612 bportifaceobjlist = ifaceobj_getfunc(bport)
1613 if not bportifaceobjlist:
1614 continue
1615 for bportifaceobj in bportifaceobjlist:
1616 # Dont process bridge port if it already has been processed
1617 # and there is no override on port_processed
1618 if (not port_processed_override and
1619 (bportifaceobj.module_flags.get(self.name,0x0) &
1620 bridgeFlags.PORT_PROCESSED)):
1621 continue
1622 try:
1623 # Add attributes specific to the vlan aware bridge
1624 if bridge_vlan_aware:
1625 self._apply_bridge_vlan_aware_port_settings_all(
1626 bportifaceobj, bridge_vids, bridge_pvid)
1627 elif self.warn_on_untagged_bridge_absence:
1628 self._check_untagged_bridge(ifaceobj.name, bportifaceobj, ifaceobj_getfunc)
1629 except exceptions.ReservedVlanException as e:
1630 raise e
1631 except Exception, e:
1632 err = True
1633 self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
1634 pass
1635 self.ipcmd.bridge_batch_commit()
1636 if err:
1637 raise Exception('%s: errors applying port settings' %ifaceobj.name)
1638
1639 def _check_untagged_bridge(self, bridgename, bridgeportifaceobj, ifaceobj_getfunc):
1640 if bridgeportifaceobj.link_kind & ifaceLinkKind.VLAN:
1641 lower_ifaceobj_list = ifaceobj_getfunc(bridgeportifaceobj.lowerifaces[0])
1642 if lower_ifaceobj_list and lower_ifaceobj_list[0] and \
1643 not lower_ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
1644 self.logger.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename)
1645 self.warn_on_untagged_bridge_absence = False
1646
1647 def bridge_port_get_bridge_name(self, ifaceobj):
1648 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
1649 if not bridgename:
1650 # bridge port is not enslaved to a bridge we need to find
1651 # the bridge in it's upper ifaces then enslave it
1652 for u in ifaceobj.upperifaces:
1653 if self.ipcmd.is_bridge(u):
1654 return True, u
1655 return False, None
1656 # return should_enslave port, bridgename
1657 return False, bridgename
1658
1659 def up_bridge_port_vlan_aware_bridge(self, ifaceobj, ifaceobj_getfunc, bridge_name, should_enslave_port):
1660 if should_enslave_port:
1661 netlink.link_set_master(ifaceobj.name, bridge_name)
1662 self.handle_ipv6([ifaceobj.name], '1')
1663
1664 bridge_vids = self._get_bridge_vids(bridge_name, ifaceobj_getfunc)
1665 bridge_pvid = self._get_bridge_pvid(bridge_name, ifaceobj_getfunc)
1666 try:
1667 self._apply_bridge_vlan_aware_port_settings_all(ifaceobj, bridge_vids, bridge_pvid)
1668 except Exception as e:
1669 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
1670 return
1671
1672 def up_bridge_port(self, ifaceobj, ifaceobj_getfunc):
1673 should_enslave_port, bridge_name = self.bridge_port_get_bridge_name(ifaceobj)
1674
1675 if not bridge_name:
1676 # bridge doesn't exist
1677 return
1678
1679 vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridge_name)
1680 if vlan_aware_bridge:
1681 self.up_bridge_port_vlan_aware_bridge(ifaceobj,
1682 ifaceobj_getfunc,
1683 bridge_name,
1684 should_enslave_port)
1685
1686 bridge_ifaceobj = ifaceobj_getfunc(bridge_name)[0]
1687
1688 self.up_apply_brports_attributes(target_ports=[ifaceobj.name],
1689 ifaceobj=bridge_ifaceobj,
1690 ifaceobj_getfunc=ifaceobj_getfunc,
1691 bridge_vlan_aware=vlan_aware_bridge)
1692
1693 ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED
1694
1695 def up_check_bridge_vlan_aware(self, ifaceobj, ifaceobj_getfunc, link_exists):
1696 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
1697 if not self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc):
1698 return False
1699 if link_exists:
1700 ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED_OVERRIDE
1701 return True
1702 return False
1703
1704 @staticmethod
1705 def parse_interface_list_value(user_config):
1706 config = dict()
1707 for entry in user_config.split():
1708 ifname, value = entry.split('=')
1709 config[ifname] = value
1710 return config
1711
1712 def sync_bridge_learning_to_vxlan_brport(self, bridge_name, bridge_vlan_aware, brport_ifaceobj,
1713 brport_name, brport_ifla_info_slave_data, brport_learning):
1714 """
1715 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1716 and
1717 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1718
1719 Checks are not performed in this function and must be verified
1720 before. This is done this way to avoid calling this method on
1721 non vlan & bridge port interfaces thus wasting a bit less time
1722 """
1723
1724 kind = None
1725 ifla_info_data = {}
1726
1727 brport_vxlan_learning_config = brport_ifaceobj.get_attr_value_first('vxlan-learning')
1728 # if the user explicitly defined vxlan-learning we need to honor his config
1729 # and not sync vxlan-learning with bridge-learning
1730
1731 brport_vxlan_learning = self.ipcmd.get_vxlandev_learning(brport_name)
1732
1733 # if BRIDGE_LEARNING is in the desired configuration
1734 # and differs from the running vxlan configuration
1735 if brport_learning is not None and brport_learning != brport_vxlan_learning and not brport_vxlan_learning_config:
1736 kind = 'vxlan'
1737 ifla_info_data = {Link.IFLA_VXLAN_LEARNING: brport_learning}
1738 self.logger.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1739 % (bridge_name, brport_name, brport_learning))
1740
1741 elif brport_learning is None and bridge_vlan_aware:
1742 # is bridge-learning is not configured but the bridge is vlan-aware
1743
1744 running_value = self.ipcmd.get_brport_learning_bool(brport_name)
1745 default_value = utils.get_boolean_from_string(self.get_mod_subattr('bridge-learning', 'default'))
1746
1747 if default_value != running_value:
1748 brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING] = default_value
1749
1750 if not brport_vxlan_learning_config:
1751 kind = 'vxlan'
1752 ifla_info_data = {Link.IFLA_VXLAN_LEARNING: default_value}
1753 self.logger.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1754 % (bridge_name, brport_name, default_value))
1755
1756 # if kind and ifla_info_data are set they will be added to the
1757 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1758 return kind, ifla_info_data
1759
1760 def check_vxlan_brport_arp_suppress(self, ifaceobj, bridge_vlan_aware, brport_ifaceobj, brport_name, user_config):
1761 if user_config:
1762 if self.arp_nd_suppress_only_on_vxlan and not brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
1763 self.logger.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1764 'is not supported on a non-vxlan port'
1765 % (ifaceobj.name, brport_name))
1766 raise Exception()
1767 elif (bridge_vlan_aware and
1768 (not self.arp_nd_suppress_only_on_vxlan or
1769 (self.arp_nd_suppress_only_on_vxlan and
1770 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN))):
1771 return self.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1772 return None
1773
1774 def up_apply_brports_attributes(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware, target_ports=[], newly_enslaved_ports=[]):
1775 ifname = ifaceobj.name
1776
1777 try:
1778 brports_ifla_info_slave_data = dict()
1779 brport_ifaceobj_dict = dict()
1780
1781 running_brports = self.brctlcmd.get_bridge_ports(ifname)
1782
1783 if target_ports:
1784 new_targets = []
1785 for brport_name in target_ports:
1786 if brport_name not in running_brports:
1787 self.logger.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name, ifname))
1788 else:
1789 new_targets.append(brport_name)
1790 running_brports = new_targets
1791
1792 self.logger.info('%s: applying bridge port configuration: %s' % (ifname, running_brports))
1793
1794 # If target_ports is specified we want to configure only this
1795 # sub-list of port we need to check if these ports are already
1796 # enslaved, if not they will be ignored.
1797 # If target_ports is not populated we will apply the brport
1798 # attributes on all running brport.
1799
1800 for port in running_brports:
1801 brport_list = ifaceobj_getfunc(port)
1802 if brport_list:
1803 brport_ifaceobj_dict[port] = brport_list[0]
1804 brports_ifla_info_slave_data[port] = dict()
1805
1806 bridge_ports_learning = {}
1807
1808 # we iterate through all IFLA_BRPORT supported attributes
1809 for attr_name, nl_attr in self._ifla_brport_attributes_map:
1810 br_config = ifaceobj.get_attr_value_first(attr_name)
1811 translate_func = self._ifla_brport_attributes_translate_user_config_to_netlink_map.get(nl_attr)
1812
1813 if not translate_func:
1814 # if no translation function is found,
1815 # we ignore this attribute and continue
1816 continue
1817
1818 if not br_config:
1819 # user didn't specify any value for this attribute
1820 # looking at policy overrides
1821 br_config = policymanager.policymanager_api.get_iface_default(
1822 module_name=self.__class__.__name__,
1823 ifname=ifname,
1824 attr=attr_name
1825 )
1826
1827 if br_config:
1828 #if bridge_vlan_aware:
1829 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1830 # 'should be configured under the ports'
1831 # % (ifname, attr_name, br_config))
1832
1833 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1834 # brport_name: { attr: value }
1835 # example:
1836 # bridge-portprios swp1=5 swp2=32
1837 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1838 if '=' in br_config:
1839 try:
1840 br_config = self.parse_interface_list_value(br_config)
1841 except:
1842 self.log_error('error while parsing \'%s %s\'' % (attr_name, br_config))
1843 continue
1844
1845 for brport_ifaceobj in brport_ifaceobj_dict.values():
1846 brport_config = brport_ifaceobj.get_attr_value_first(attr_name)
1847 brport_name = brport_ifaceobj.name
1848
1849 if not ifupdownflags.flags.PERFMODE and brport_name not in newly_enslaved_ports:
1850 # if the port has just been enslaved, info_slave_data is not cached yet
1851 cached_value = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', nl_attr])
1852 else:
1853 cached_value = None
1854
1855 if not brport_config:
1856 # if a brport attribute was specified under the bridge and not under the port
1857 # we assign the bridge value to the port. If an attribute is both defined under
1858 # the bridge and the brport we keep the value of the port and ignore the br val.
1859 if type(br_config) == dict:
1860 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1861 # br_config is a dictionary, example:
1862 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1863 brport_config = br_config.get(brport_name)
1864 else:
1865 brport_config = br_config
1866
1867 if not brport_config:
1868 brport_config = policymanager.policymanager_api.get_iface_default(
1869 module_name=self.__class__.__name__,
1870 ifname=brport_name,
1871 attr=attr_name
1872 )
1873
1874 user_config = brport_config
1875
1876 # attribute specific work
1877 # This shouldn't be here but we don't really have a choice otherwise this
1878 # will require too much code duplication and will make the code very complex
1879 if nl_attr == Link.IFLA_BRPORT_ARP_SUPPRESS:
1880 try:
1881 arp_suppress = self.check_vxlan_brport_arp_suppress(ifaceobj,
1882 bridge_vlan_aware,
1883 brport_ifaceobj,
1884 brport_name,
1885 user_config)
1886 if arp_suppress:
1887 user_config = arp_suppress
1888 except:
1889 continue
1890 elif nl_attr == Link.IFLA_BRPORT_GROUP_FWD_MASK:
1891 # special handking for group_fwd_mask because Cisco proprietary
1892 # protocol needs to be set via a private netlink attribute
1893 self.ifla_brport_group_fwd_mask(ifname, brport_name,
1894 brports_ifla_info_slave_data,
1895 user_config, cached_value)
1896 continue
1897
1898 #if brport_config:
1899 # if not bridge_vlan_aware:
1900 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1901 # 'should be configured under the bridge'
1902 # % (ifname, brport_name,
1903 # attr_name, brport_config))
1904
1905 if user_config:
1906 user_config_nl = translate_func(user_config)
1907 # check config value against running value
1908 if user_config_nl != cached_value:
1909 brports_ifla_info_slave_data[brport_name][nl_attr] = user_config_nl
1910 self.logger.info('%s: %s: set %s %s' % (ifname, brport_name, attr_name, user_config))
1911 self.logger.debug('(cache %s)' % cached_value)
1912
1913 if nl_attr == Link.IFLA_BRPORT_LEARNING:
1914 # for vxlan-learning sync purposes we need to save the user config for each brports.
1915 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1916 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1917 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1918 # the brport since it might go out of sync for X and Y reasons.
1919 bridge_ports_learning[brport_name] = user_config_nl
1920
1921 elif cached_value is not None:
1922 # no config found, do we need to reset to default?
1923 default = self.get_attr_default_value(attr_name)
1924 if default:
1925 default_netlink = translate_func(default)
1926
1927 if (nl_attr == Link.IFLA_BRPORT_LEARNING
1928 and not ifupdownflags.flags.PERFMODE
1929 and brport_name not in newly_enslaved_ports):
1930 try:
1931 if self.ipcmd.get_brport_peer_link(brport_name):
1932 if default_netlink != cached_value:
1933 self.logger.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1934 % (ifname, brport_name))
1935 continue
1936 bridge_ports_learning[brport_name] = default_netlink
1937 except Exception as e:
1938 self.logger.debug('%s: %s: peerlink check: %s' % (ifname, brport_name, str(e)))
1939
1940 if default_netlink != cached_value:
1941 self.logger.info('%s: %s: %s: no configuration detected, resetting to default %s'
1942 % (ifname, brport_name, attr_name, default))
1943 self.logger.debug('(cache %s)' % cached_value)
1944 brports_ifla_info_slave_data[brport_name][nl_attr] = default_netlink
1945
1946 # applying bridge port configuration via netlink
1947 for brport_name, brport_ifla_info_slave_data in brports_ifla_info_slave_data.items():
1948
1949 brport_ifaceobj = brport_ifaceobj_dict.get(brport_name)
1950 if (brport_ifaceobj
1951 and brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1952 and brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
1953 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1954 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1955 kind, ifla_info_data = self.sync_bridge_learning_to_vxlan_brport(ifaceobj.name,
1956 bridge_vlan_aware,
1957 brport_ifaceobj,
1958 brport_name,
1959 brport_ifla_info_slave_data,
1960 bridge_ports_learning.get(brport_name))
1961
1962 cached_bridge_mcsnoop = self.brctlcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BR_MCAST_SNOOPING])
1963
1964 if (self.vxlan_bridge_igmp_snooping_enable_port_mcrouter and utils.get_boolean_from_string(
1965 self.get_bridge_mcsnoop_value(ifaceobj)
1966 )) or cached_bridge_mcsnoop:
1967 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
1968 # is on and mcsnoop is on (or mcsnoop is already enabled on the
1969 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
1970 if not brport_ifla_info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER):
1971 brport_ifla_info_slave_data[Link.IFLA_BRPORT_MULTICAST_ROUTER] = 2
1972 self.logger.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname, brport_name))
1973 else:
1974 kind = None
1975 ifla_info_data = {}
1976
1977 if brport_ifla_info_slave_data or ifla_info_data:
1978 try:
1979 netlink.link_add_set(ifname=brport_name,
1980 kind=kind,
1981 ifla_info_data=ifla_info_data,
1982 slave_kind='bridge',
1983 ifla_info_slave_data=brport_ifla_info_slave_data)
1984 except Exception as e:
1985 self.logger.warning('%s: %s: %s' % (ifname, brport_name, str(e)))
1986
1987 self._set_bridge_vidinfo_compat(ifaceobj)
1988 self._set_bridge_mcqv4src_compat(ifaceobj)
1989 self._process_bridge_maxwait(ifaceobj, self._get_bridge_port_list(ifaceobj))
1990
1991 except Exception as e:
1992 self.log_error(str(e), ifaceobj)
1993
1994 def ifla_brport_group_fwd_mask(self, ifname, brport_name, brports_ifla_info_slave_data, user_config, cached_ifla_brport_group_fwd_mask):
1995 """
1996 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1997 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1998 field we need to have special handling for that.
1999 """
2000 ifla_brport_group_fwd_mask = 0
2001 ifla_brport_group_fwd_maskhi = 0
2002 if user_config:
2003 for group in re.split(',|\s*', user_config):
2004 if not group:
2005 continue
2006
2007 callback = self.l2protocol_tunnel_callback.get(group)
2008
2009 if not callable(callback):
2010 self.logger.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname, brport_name, group))
2011 else:
2012 ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi = callback(ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi)
2013
2014 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2015 cached_ifla_brport_group_fwd_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
2016
2017 log_mask_change = True
2018 # if user specify bridge-l2protocol-tunnel stp cdp
2019 # we need to set both MASK and MASKHI but we only want to log once
2020
2021 if cached_ifla_brport_group_fwd_mask is None:
2022 cached_ifla_brport_group_fwd_mask = 0
2023 if cached_ifla_brport_group_fwd_maskhi is None:
2024 cached_ifla_brport_group_fwd_maskhi = 0
2025
2026 # if the cache value is None it means that the kernel doesn't support this attribute
2027 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2028
2029 if ifla_brport_group_fwd_mask != cached_ifla_brport_group_fwd_mask:
2030 if log_mask_change:
2031 self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
2032 self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask)
2033 log_mask_change = False
2034 brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASK] = ifla_brport_group_fwd_mask
2035
2036 if ifla_brport_group_fwd_maskhi != cached_ifla_brport_group_fwd_maskhi:
2037 if log_mask_change:
2038 self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
2039 self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi)
2040 brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASKHI] = ifla_brport_group_fwd_maskhi
2041
2042 def up_bridge(self, ifaceobj, ifaceobj_getfunc):
2043 ifname = ifaceobj.name
2044
2045 if ifupdownflags.flags.PERFMODE:
2046 link_just_created = True
2047 link_exists = False
2048 else:
2049 link_exists = self.ipcmd.link_exists(ifaceobj.name)
2050 link_just_created = not link_exists
2051
2052 if not link_exists:
2053 netlink.link_add_bridge(ifname)
2054 else:
2055 self.logger.info('%s: bridge already exists' % ifname)
2056
2057 bridge_vlan_aware = self.up_check_bridge_vlan_aware(ifaceobj, ifaceobj_getfunc, not link_just_created)
2058
2059 self.up_apply_bridge_settings(ifaceobj, link_just_created, bridge_vlan_aware)
2060
2061 try:
2062 newly_enslaved_ports = self._add_ports(ifaceobj, ifaceobj_getfunc)
2063 self.up_apply_brports_attributes(ifaceobj, ifaceobj_getfunc, bridge_vlan_aware,
2064 newly_enslaved_ports=newly_enslaved_ports)
2065 except Exception as e:
2066 self.logger.warning('%s: apply bridge ports settings: %s' % (ifname, str(e)))
2067
2068 running_ports = ''
2069 try:
2070 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
2071 if not running_ports:
2072 return
2073 self.handle_ipv6([], '1', ifaceobj=ifaceobj)
2074 self._apply_bridge_port_settings_all(ifaceobj,
2075 ifaceobj_getfunc=ifaceobj_getfunc,
2076 bridge_vlan_aware=bridge_vlan_aware)
2077 except exceptions.ReservedVlanException as e:
2078 raise e
2079 except Exception as e:
2080 self.logger.warning('%s: apply bridge settings: %s' % (ifname, str(e)))
2081 finally:
2082 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
2083 for p in running_ports:
2084 ifaceobj_list = ifaceobj_getfunc(p)
2085 if (ifaceobj_list and ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN):
2086 netlink.link_set_updown(p, "down")
2087 continue
2088 try:
2089 netlink.link_set_updown(p, "up")
2090 except Exception, e:
2091 self.logger.debug('%s: %s: link set up (%s)'
2092 % (ifaceobj.name, p, str(e)))
2093 pass
2094
2095 try:
2096 self._up_bridge_mac(ifaceobj, ifaceobj_getfunc)
2097 except Exception as e:
2098 self.logger.warning('%s: setting bridge mac address: %s' % (ifaceobj.name, str(e)))
2099
2100 def _get_bridge_mac(self, ifaceobj, ifname, ifaceobj_getfunc):
2101 if self.bridge_mac_iface and self.bridge_mac_iface[0] and self.bridge_mac_iface[1]:
2102 return self.bridge_mac_iface
2103
2104 if self.bridge_mac_iface_list:
2105 self.logger.debug('bridge mac iface list: %s' % self.bridge_mac_iface_list)
2106
2107 for bridge_mac_intf in self.bridge_mac_iface_list:
2108 ifaceobj_list = ifaceobj_getfunc(bridge_mac_intf)
2109 iface_mac = None
2110
2111 if ifaceobj_list:
2112 for obj in ifaceobj_list:
2113 iface_user_configured_hwaddress = utils.strip_hwaddress(obj.get_attr_value_first('hwaddress'))
2114 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2115 if iface_user_configured_hwaddress:
2116 iface_mac = iface_user_configured_hwaddress
2117
2118 if not iface_mac and not self.ipcmd.link_exists(bridge_mac_intf):
2119 continue
2120
2121 if not iface_mac:
2122 iface_mac = self.ipcmd.cache_get('link', [bridge_mac_intf, 'hwaddress'])
2123 # if hwaddress attribute is not configured we use the running mac addr
2124
2125 self.bridge_mac_iface = (bridge_mac_intf, iface_mac)
2126 return self.bridge_mac_iface
2127 elif self.bridge_set_static_mac_from_port:
2128 # no policy was provided, we need to get the first physdev or bond ports
2129 # and use its hwaddress to set the bridge mac
2130 for port in self._get_bridge_port_list_user_ordered(ifaceobj) or []:
2131 # iterate through the bridge-port list
2132 for port_obj in ifaceobj_getfunc(port) or []:
2133 # check if the port is a physdev (link_kind is null) or a bon
2134 if port_obj.link_kind != ifaceLinkKind.VXLAN:
2135 iface_user_configured_hwaddress = utils.strip_hwaddress(port_obj.get_attr_value_first('hwaddress'))
2136 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2137 if iface_user_configured_hwaddress:
2138 iface_mac = iface_user_configured_hwaddress.lower()
2139 # we need to "normalize" the user provided MAC so it can match with
2140 # what we have in the cache (data retrieved via a netlink dump by
2141 # nlmanager). nlmanager return all macs in lower-case
2142 else:
2143 iface_mac = self.ipcmd.link_get_hwaddress(port)
2144
2145 if iface_mac:
2146 self.bridge_mac_iface = (port, iface_mac)
2147 return self.bridge_mac_iface
2148
2149 return None, None
2150
2151 def _add_bridge_mac_to_fdb(self, ifaceobj, bridge_mac):
2152 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE and bridge_mac and ifaceobj.get_attr_value('address'):
2153 self.ipcmd.bridge_fdb_add(ifaceobj.name, bridge_mac, vlan=None, bridge=True, remote=None)
2154
2155 def _up_bridge_mac(self, ifaceobj, ifaceobj_getfunc):
2156 """
2157 We have a day one bridge mac changing problem with changing ports
2158 (basically bridge mac changes when the port it inherited the mac from
2159 gets de-enslaved).
2160
2161 We have discussed this problem many times before and tabled it.
2162 The issue has aggravated with vxlan bridge ports having auto-generated
2163 random macs...which change on every reboot.
2164
2165 ifupdown2 extract from policy files an iface to select a mac from and
2166 configure it automatically.
2167 """
2168 if ifaceobj.get_attr_value('hwaddress'):
2169 # if the user configured a static hwaddress
2170 # there is no need to assign one
2171 return
2172
2173 ifname = ifaceobj.name
2174 mac_intf, bridge_mac = self._get_bridge_mac(ifaceobj, ifname, ifaceobj_getfunc)
2175 self.logger.debug("%s: _get_bridge_mac returned (%s, %s)"
2176 %(ifname, mac_intf, bridge_mac))
2177
2178 if bridge_mac:
2179 # if an interface is configured with the following attribute:
2180 # hwaddress 08:00:27:42:42:4
2181 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2182 # from the kernel. The only way to counter that is to convert all mac to int
2183 # and compare the ints, it will increase perfs and be safer.
2184 cached_value = self.ipcmd.cache_get('link', [ifname, 'hwaddress'])
2185 self.logger.debug('%s: cached hwaddress value: %s' % (ifname, cached_value))
2186 if cached_value and cached_value == bridge_mac:
2187 # the bridge mac is already set to the bridge_mac_intf's mac
2188 return
2189
2190 self.logger.info('%s: setting bridge mac to port %s mac' % (ifname, mac_intf))
2191 try:
2192 self.ipcmd.link_set(ifname, 'address', value=bridge_mac, force=True)
2193 except Exception as e:
2194 self.logger.info('%s: %s' % (ifname, str(e)))
2195 # log info this error because the user didn't explicitly configured this
2196 else:
2197 self._add_bridge_mac_to_fdb(ifaceobj, self.ipcmd.link_get_hwaddress(ifname))
2198
2199 def _up(self, ifaceobj, ifaceobj_getfunc=None):
2200 if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
2201 self.up_bridge_port(ifaceobj, ifaceobj_getfunc)
2202
2203 elif ifaceobj.link_kind & ifaceLinkKind.BRIDGE:
2204 self.up_bridge(ifaceobj, ifaceobj_getfunc)
2205
2206 else:
2207 bridge_attributes = self._modinfo.get('attrs', {}).keys()
2208
2209 for ifaceobj_config_attr in ifaceobj.config.keys():
2210 if ifaceobj_config_attr in bridge_attributes:
2211 self.logger.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2212 % (ifaceobj.name, ifaceobj_config_attr))
2213
2214 def _down(self, ifaceobj, ifaceobj_getfunc=None):
2215 if not self._is_bridge(ifaceobj):
2216 return
2217 ifname = ifaceobj.name
2218 if not self.ipcmd.link_exists(ifname):
2219 return
2220 try:
2221 running_ports = self.brctlcmd.get_bridge_ports(ifname)
2222 if running_ports:
2223 self.handle_ipv6(running_ports, '0')
2224 if ifaceobj.link_type != ifaceLinkType.LINK_NA:
2225 map(lambda p: netlink.link_set_updown(p, 'down'), running_ports)
2226 except Exception as e:
2227 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
2228 try:
2229 netlink.link_del(ifname)
2230 except Exception as e:
2231 ifaceobj.set_status(ifaceStatus.ERROR)
2232 self.logger.error(str(e))
2233 # netlink exception already contains the ifname
2234
2235 def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
2236 running_attrs = {}
2237 if ports:
2238 running_bridge_port_vids = ''
2239 for p in ports:
2240 try:
2241 running_vids = self._get_runing_vids(p)
2242 if running_vids:
2243 running_bridge_port_vids += ' %s=%s' %(p,
2244 ','.join(running_vids))
2245 except Exception:
2246 pass
2247 running_attrs['bridge-port-vids'] = running_bridge_port_vids
2248
2249 running_bridge_port_pvid = ''
2250 for p in ports:
2251 try:
2252 running_pvid = self._get_runing_pvid(p)
2253 if running_pvid:
2254 running_bridge_port_pvid += ' %s=%s' %(p,
2255 running_pvid)
2256 except Exception:
2257 pass
2258 running_attrs['bridge-port-pvids'] = running_bridge_port_pvid
2259
2260 running_bridge_vids = self.ipcmd.bridge_vlan_get_vids(ifaceobjrunning.name)
2261 if running_bridge_vids:
2262 running_attrs['bridge-vids'] = ','.join(self._compress_into_ranges(running_bridge_vids))
2263 return running_attrs
2264
2265 def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
2266 bridgeports=None):
2267 running_attrs = {}
2268
2269 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2270 # so query the ports
2271 running_bridgeport_vids = []
2272 running_bridgeport_pvids = []
2273 for bport in bridgeports:
2274 (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
2275 if vids:
2276 running_bridgeport_vids.append(' '.join(vids))
2277 if pvid:
2278 running_bridgeport_pvids.append(pvid)
2279
2280 bridge_vids = None
2281 if running_bridgeport_vids:
2282 (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
2283 if freq == len(bridgeports):
2284 running_attrs['bridge-vids'] = vidval
2285 bridge_vids = vidval.split()
2286
2287 bridge_pvid = None
2288 if running_bridgeport_pvids:
2289 (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
2290 if freq == len(bridgeports) and vidval != '1':
2291 running_attrs['bridge-pvid'] = vidval
2292 bridge_pvid = vidval.split()[0]
2293
2294 # Go through all bridge ports and find their vids
2295 for bport in bridgeports:
2296 bportifaceobj = ifaceobj_getfunc(bport)
2297 if not bportifaceobj:
2298 continue
2299 bport_vids = []
2300 bport_pvid = None
2301 (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
2302 if vids and vids != bridge_vids:
2303 bport_vids = vids
2304 if pvid and pvid != bridge_pvid:
2305 bport_pvid = pvid
2306 if bport_vids and bport_pvid in bport_vids:
2307 bport_vids.remove(bport_pvid)
2308 if (not bport_vids and bport_pvid and bport_pvid != '1'):
2309 bportifaceobj[0].replace_config('bridge-access', bport_pvid)
2310 bportifaceobj[0].delete_config('bridge-pvid')
2311 bportifaceobj[0].delete_config('bridge-vids')
2312 else:
2313 if bport_pvid and bport_pvid != '1':
2314 bportifaceobj[0].replace_config('bridge-pvid', bport_pvid)
2315 else:
2316 # delete any stale bridge-vids under ports
2317 bportifaceobj[0].delete_config('bridge-pvid')
2318 if bport_vids:
2319 bportifaceobj[0].replace_config('bridge-vids',
2320 ' '.join(bport_vids))
2321 else:
2322 # delete any stale bridge-vids under ports
2323 bportifaceobj[0].delete_config('bridge-vids')
2324 return running_attrs
2325
2326 def _query_running_mcqv4src(self, ifaceobjrunning):
2327 running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobjrunning.name)
2328 mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
2329 mcqs.sort()
2330 mcq = ' '.join(mcqs)
2331 return mcq
2332
2333 def _query_running_attrs(self, ifaceobjrunning, ifaceobj_getfunc,
2334 bridge_vlan_aware=False):
2335 bridgeattrdict = {}
2336 userspace_stp = 0
2337 ports = None
2338 skip_kernel_stp_attrs = 0
2339
2340 try:
2341 if self.systcl_get_net_bridge_stp_user_space() == '1':
2342 userspace_stp = 1
2343 except Exception as e:
2344 self.logger.info('%s: %s' % (ifaceobjrunning.name, str(e)))
2345
2346 tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
2347 if not tmpbridgeattrdict:
2348 self.logger.warn('%s: unable to get bridge attrs'
2349 %ifaceobjrunning.name)
2350 return bridgeattrdict
2351
2352 # Fill bridge_ports and bridge stp attributes first
2353 ports = tmpbridgeattrdict.get('ports')
2354 if ports:
2355 bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
2356 stp = tmpbridgeattrdict.get('stp', 'no')
2357 if stp != self.get_mod_subattr('bridge-stp', 'default'):
2358 bridgeattrdict['bridge-stp'] = [stp]
2359
2360 if stp == 'yes' and userspace_stp:
2361 skip_kernel_stp_attrs = 1
2362
2363 vlan_stats = utils.get_onff_from_onezero(
2364 tmpbridgeattrdict.get('vlan-stats', None))
2365 if (vlan_stats and
2366 vlan_stats != self.get_mod_subattr('bridge-vlan-stats', 'default')):
2367 bridgeattrdict['bridge-vlan-stats'] = [vlan_stats]
2368
2369 bool2str = {'0': 'no', '1': 'yes'}
2370 # pick all other attributes
2371 for k,v in tmpbridgeattrdict.items():
2372 if not v:
2373 continue
2374 if k == 'ports' or k == 'stp':
2375 continue
2376
2377 if skip_kernel_stp_attrs and k[:2] != 'mc':
2378 # only include igmp attributes if kernel stp is off
2379 continue
2380 attrname = 'bridge-' + k
2381 mod_default = self.get_mod_subattr(attrname, 'default')
2382 if v != mod_default:
2383 # convert '0|1' running values to 'no|yes'
2384 if v in bool2str.keys() and bool2str[v] == mod_default:
2385 continue
2386 bridgeattrdict[attrname] = [v]
2387
2388 if bridge_vlan_aware:
2389 if not ports:
2390 ports = {}
2391 bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
2392 ifaceobj_getfunc,
2393 ports.keys())
2394 else:
2395 bridgevidinfo = self._query_running_vidinfo_compat(ifaceobjrunning,
2396 ports)
2397 if bridgevidinfo:
2398 bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
2399 if v})
2400
2401 mcq = self._query_running_mcqv4src(ifaceobjrunning)
2402 if mcq:
2403 bridgeattrdict['bridge-mcqv4src'] = [mcq]
2404
2405 if skip_kernel_stp_attrs:
2406 return bridgeattrdict
2407
2408 # Do this only for vlan-UNAWARE-bridge
2409 if ports and not bridge_vlan_aware:
2410 portconfig = {'bridge-pathcosts' : '',
2411 'bridge-portprios' : '',
2412 'bridge-learning' : '',
2413 'bridge-unicast-flood' : '',
2414 'bridge-multicast-flood' : '',
2415 'bridge-arp-nd-suppress' : '',
2416 }
2417 for p, v in ports.items():
2418 v = self.brctlcmd.bridge_get_pathcost(ifaceobjrunning.name, p)
2419 if v and v != self.get_mod_subattr('bridge-pathcosts',
2420 'default'):
2421 portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
2422
2423 v = self.brctlcmd.bridge_get_portprio(ifaceobjrunning.name, p)
2424 if v and v != self.get_mod_subattr('bridge-portprios',
2425 'default'):
2426 portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
2427
2428 v = utils.get_onff_from_onezero(
2429 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2430 p, 'learning'))
2431 if (v and
2432 v != self.get_mod_subattr('bridge-learning', 'default')):
2433 portconfig['bridge-learning'] += ' %s=%s' %(p, v)
2434
2435 v = utils.get_onff_from_onezero(
2436 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2437 p, 'unicast-flood'))
2438 if (v and
2439 v != self.get_mod_subattr('bridge-unicast-flood',
2440 'default')):
2441 portconfig['bridge-unicast-flood'] += ' %s=%s' %(p, v)
2442
2443 v = utils.get_onff_from_onezero(
2444 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2445 p, 'multicast-flood'))
2446 if (v and
2447 v != self.get_mod_subattr('bridge-multicast-flood',
2448 'default')):
2449 portconfig['bridge-multicast-flood'] += ' %s=%s' %(p, v)
2450
2451 v = utils.get_onff_from_onezero(
2452 self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
2453 p, 'arp-nd-suppress'))
2454 if (v and
2455 v != self.get_mod_subattr('bridge-arp-nd-suppress',
2456 'default')):
2457 portconfig['bridge-arp-nd-suppress'] += ' %s=%s' %(p, v)
2458
2459 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
2460 if v})
2461
2462 return bridgeattrdict
2463
2464 def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
2465 running_mcqs = self._query_running_mcqv4src(ifaceobj)
2466 attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
2467 if attrval:
2468 mcqs = attrval.split()
2469 mcqs.sort()
2470 mcqsout = ' '.join(mcqs)
2471 ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
2472 running_mcqs, 1 if running_mcqs != mcqsout else 0)
2473
2474 def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
2475 err = 0
2476 attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
2477 if attrval:
2478 running_bridge_port_vids = ''
2479 portlist = self.parse_port_list(ifaceobj.name, attrval)
2480 if not portlist:
2481 self.log_warn('%s: could not parse \'bridge-port-vids %s\''
2482 %(ifaceobj.name, attrval))
2483 return
2484 err = 0
2485 for p in portlist:
2486 try:
2487 (port, val) = p.split('=')
2488 vids = val.split(',')
2489 running_vids = self.ipcmd.bridge_vlan_get_vids(port)
2490 if running_vids:
2491 if not self._compare_vids(vids, running_vids):
2492 err += 1
2493 running_bridge_port_vids += ' %s=%s' %(port,
2494 ','.join(running_vids))
2495 else:
2496 running_bridge_port_vids += ' %s' %p
2497 else:
2498 err += 1
2499 except Exception, e:
2500 self.log_warn('%s: failure checking vid %s (%s)'
2501 %(ifaceobj.name, p, str(e)))
2502 if err:
2503 ifaceobjcurr.update_config_with_status('bridge-port-vids',
2504 running_bridge_port_vids, 1)
2505 else:
2506 ifaceobjcurr.update_config_with_status('bridge-port-vids',
2507 attrval, 0)
2508
2509 attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
2510 if attrval:
2511 portlist = self.parse_port_list(ifaceobj.name, attrval)
2512 if not portlist:
2513 self.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2514 %(ifaceobj.name, attrval))
2515 return
2516 running_bridge_port_pvids = ''
2517 err = 0
2518 for p in portlist:
2519 try:
2520 (port, pvid) = p.split('=')
2521 running_pvid = self.ipcmd.bridge_vlan_get_vids(port)
2522 if running_pvid and running_pvid == pvid:
2523 running_bridge_port_pvids += ' %s' %p
2524 else:
2525 err += 1
2526 running_bridge_port_pvids += ' %s=%s' %(port,
2527 running_pvid)
2528 except Exception, e:
2529 self.log_warn('%s: failure checking pvid %s (%s)'
2530 %(ifaceobj.name, pvid, str(e)))
2531 if err:
2532 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
2533 running_bridge_port_pvids, 1)
2534 else:
2535 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
2536 running_bridge_port_pvids, 0)
2537
2538 vids = self.get_ifaceobj_bridge_vids(ifaceobj)
2539 if vids[1]:
2540 ifaceobjcurr.update_config_with_status(vids[0], vids[1], -1)
2541
2542 def _query_check_snooping_wdefault(self, ifaceobj):
2543 if (ifupdownflags.flags.WITHDEFAULTS
2544 and not self._vxlan_bridge_default_igmp_snooping
2545 and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN):
2546 ifaceobj.replace_config('bridge-mcsnoop', 'no')
2547
2548 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
2549 ifaceobj_getfunc=None):
2550 if not self._is_bridge(ifaceobj):
2551 return
2552 if not self.brctlcmd.bridge_exists(ifaceobj.name):
2553 self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
2554 return
2555
2556 self._query_check_snooping_wdefault(ifaceobj)
2557
2558 ifaceattrs = self.dict_key_subset(ifaceobj.config,
2559 self.get_mod_attrs())
2560 #Add default attributes if --with-defaults is set
2561 if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in ifaceattrs:
2562 ifaceattrs.append('bridge-stp')
2563 if not ifaceattrs:
2564 return
2565 try:
2566 runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
2567 if not runningattrs:
2568 self.logger.debug('%s: bridge: unable to get bridge attrs'
2569 %ifaceobj.name)
2570 runningattrs = {}
2571 except Exception, e:
2572 self.logger.warn(str(e))
2573 runningattrs = {}
2574
2575 self._query_check_support_yesno_attrs(runningattrs, ifaceobj)
2576
2577 filterattrs = ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2578 'bridge-port-pvids']
2579
2580 diff = Set(ifaceattrs).difference(filterattrs)
2581
2582 if 'bridge-l2protocol-tunnel' in diff:
2583 diff.remove('bridge-l2protocol-tunnel')
2584 # bridge-l2protocol-tunnel requires separate handling
2585
2586 if 'bridge-ports' in diff:
2587 self.query_check_bridge_ports(ifaceobj, ifaceobjcurr, runningattrs.get('ports', {}).keys(), ifaceobj_getfunc)
2588 diff.remove('bridge-ports')
2589
2590 for k in diff:
2591 # get the corresponding ifaceobj attr
2592 v = ifaceobj.get_attr_value_first(k)
2593 if not v:
2594 if ifupdownflags.flags.WITHDEFAULTS and k == 'bridge-stp':
2595 v = 'on' if self.default_stp_on else 'off'
2596 else:
2597 continue
2598 rv = runningattrs.get(k[7:])
2599 if k == 'bridge-mcqv4src':
2600 continue
2601 if k == 'bridge-maxwait' or k == 'bridge-waitport':
2602 ifaceobjcurr.update_config_with_status(k, v, 0)
2603 continue
2604 if k == 'bridge-vlan-aware':
2605 rv = self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)
2606 if (rv and v == 'yes') or (not rv and v == 'no'):
2607 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
2608 v, 0)
2609 else:
2610 ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
2611 v, 1)
2612 elif k == 'bridge-stp':
2613 # special case stp compare because it may
2614 # contain more than one valid values
2615 stp_on_vals = ['on', 'yes']
2616 stp_off_vals = ['off', 'no']
2617 if ((v in stp_on_vals and rv in stp_on_vals) or
2618 (v in stp_off_vals and rv in stp_off_vals)):
2619 ifaceobjcurr.update_config_with_status('bridge-stp',
2620 rv, 0)
2621 else:
2622 ifaceobjcurr.update_config_with_status('bridge-stp',
2623 rv, 1)
2624 elif k in ['bridge-pathcosts',
2625 'bridge-portprios',
2626 'bridge-portmcrouter',
2627 'bridge-portmcfl',
2628 'bridge-learning',
2629 'bridge-unicast-flood',
2630 'bridge-multicast-flood',
2631 'bridge-arp-nd-suppress',
2632 ]:
2633 if k == 'bridge-arp-nd-suppress':
2634 brctlcmdattrname = k[7:]
2635 else:
2636 brctlcmdattrname = k[7:].rstrip('s')
2637 # for port attributes, the attributes are in a list
2638 # <portname>=<portattrvalue>
2639 status = 0
2640 currstr = ''
2641 vlist = self.parse_port_list(ifaceobj.name, v)
2642 if not vlist:
2643 continue
2644 for vlistitem in vlist:
2645 try:
2646 (p, v) = vlistitem.split('=')
2647 if k in ['bridge-learning',
2648 'bridge-unicast-flood',
2649 'bridge-multicast-flood',
2650 'bridge-arp-nd-suppress',
2651 ]:
2652 currv = utils.get_onoff_bool(
2653 self.brctlcmd.get_bridgeport_attr(
2654 ifaceobj.name, p,
2655 brctlcmdattrname))
2656 else:
2657 currv = self.brctlcmd.get_bridgeport_attr(
2658 ifaceobj.name, p,
2659 brctlcmdattrname)
2660 if currv:
2661 currstr += ' %s=%s' %(p, currv)
2662 else:
2663 currstr += ' %s=%s' %(p, 'None')
2664
2665 if k == 'bridge-portmcrouter':
2666 if self._ifla_brport_multicast_router_dict_to_int.get(v) != int(currv):
2667 status = 1
2668 elif currv != v:
2669 status = 1
2670 except Exception, e:
2671 self.log_warn(str(e))
2672 pass
2673 ifaceobjcurr.update_config_with_status(k, currstr, status)
2674 elif k == 'bridge-vlan-stats' or k == 'bridge-mcstats':
2675 rv = utils.get_onff_from_onezero(rv)
2676 if v != rv:
2677 ifaceobjcurr.update_config_with_status(k, rv, 1)
2678 else:
2679 ifaceobjcurr.update_config_with_status(k, rv, 0)
2680 elif not rv:
2681 if k == 'bridge-pvid' or k == 'bridge-vids' or k == 'bridge-trunk' or k == 'bridge-allow-untagged':
2682 # bridge-pvid and bridge-vids on a bridge does
2683 # not correspond directly to a running config
2684 # on the bridge. They correspond to default
2685 # values for the bridge ports. And they are
2686 # already checked against running config of the
2687 # bridge port and reported against a bridge port.
2688 # So, ignore these attributes under the bridge.
2689 # Use '2' for ignore today. XXX: '2' will be
2690 # mapped to a defined value in subsequent patches.
2691 ifaceobjcurr.update_config_with_status(k, v, 2)
2692 else:
2693 ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
2694 continue
2695 elif v.upper() != rv.upper():
2696 ifaceobjcurr.update_config_with_status(k, rv, 1)
2697 else:
2698 ifaceobjcurr.update_config_with_status(k, rv, 0)
2699
2700 self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
2701
2702 self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
2703 self._query_check_l2protocol_tunnel_on_bridge(ifaceobj, ifaceobjcurr, runningattrs)
2704
2705 def query_check_bridge_ports(self, ifaceobj, ifaceobjcurr, running_port_list, ifaceobj_getfunc):
2706 bridge_all_ports = []
2707 for obj in ifaceobj_getfunc(ifaceobj.name) or []:
2708 bridge_all_ports.extend(self._get_bridge_port_list(obj) or [])
2709
2710 if not running_port_list and not bridge_all_ports:
2711 return
2712
2713 ports_list_status = 0 if not set(running_port_list).symmetric_difference(bridge_all_ports) else 1
2714
2715 try:
2716 port_list = self._get_ifaceobj_bridge_ports(ifaceobj).split()
2717 # we want to display the same bridge-ports list as provided
2718 # in the interfaces file but if this list contains regexes or
2719 # globs, for now, we won't try to change it.
2720 if 'regex' in port_list or 'glob' in port_list:
2721 port_list = running_port_list
2722 else:
2723 ordered = []
2724 for i in range(0, len(port_list)):
2725 if port_list[i] in running_port_list:
2726 ordered.append(port_list[i])
2727 port_list = ordered
2728 except:
2729 port_list = running_port_list
2730 ifaceobjcurr.update_config_with_status('bridge-ports', (' '.join(port_list) if port_list else ''), ports_list_status)
2731
2732 def get_ifaceobj_bridge_vids(self, ifaceobj):
2733 vids = ('bridge-vids', ifaceobj.get_attr_value_first('bridge-vids'))
2734 if not vids[1]:
2735 vids = ('bridge-trunk', ifaceobj.get_attr_value_first('bridge-trunk'))
2736 return vids
2737
2738 def get_ifaceobj_bridge_vids_value(self, ifaceobj):
2739 return self.get_ifaceobj_bridge_vids(ifaceobj)[1]
2740
2741 def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
2742 ifaceobjs = ifaceobj_getfunc(bridgename)
2743 for ifaceobj in ifaceobjs:
2744 vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
2745 if vids: return re.split(r'[\s\t,]\s*', vids)
2746 return None
2747
2748 def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
2749 ifaceobjs = ifaceobj_getfunc(bridgename)
2750 pvid = None
2751 for ifaceobj in ifaceobjs:
2752 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
2753 if pvid:
2754 break
2755 return pvid
2756
2757 def _get_bridge_name(self, ifaceobj):
2758 return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
2759
2760 def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
2761 ifaceobj_getfunc, bridgename):
2762 attr_name = 'bridge-access'
2763 vid = ifaceobj.get_attr_value_first(attr_name)
2764 if vid:
2765 (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
2766 ifaceobj.name)
2767 if (not running_pvid or running_pvid != vid or
2768 (running_vids and running_vids[0] != vid)):
2769 ifaceobjcurr.update_config_with_status(attr_name,
2770 running_pvid, 1)
2771 else:
2772 ifaceobjcurr.update_config_with_status(attr_name, vid, 0)
2773 return
2774
2775 (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
2776 ifaceobj.name)
2777 attr_name = 'bridge-pvid'
2778 pvid = ifaceobj.get_attr_value_first('bridge-pvid')
2779 if pvid:
2780 if running_pvid and running_pvid == pvid:
2781 ifaceobjcurr.update_config_with_status(attr_name,
2782 running_pvid, 0)
2783 else:
2784 ifaceobjcurr.update_config_with_status(attr_name,
2785 running_pvid, 1)
2786 elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
2787 ((ifaceobj.flags & iface.HAS_SIBLINGS) and
2788 (ifaceobj.flags & iface.OLDEST_SIBLING))):
2789 # if the interface has multiple iface sections,
2790 # we check the below only for the oldest sibling
2791 # or the last iface section
2792 pvid = self._get_bridge_pvid(bridgename, ifaceobj_getfunc)
2793 if pvid:
2794 if not running_pvid or running_pvid != pvid:
2795 ifaceobjcurr.status = ifaceStatus.ERROR
2796 ifaceobjcurr.status_str = 'bridge pvid error'
2797 elif not running_pvid or running_pvid != '1':
2798 ifaceobjcurr.status = ifaceStatus.ERROR
2799 ifaceobjcurr.status_str = 'bridge pvid error'
2800
2801 attr_name, vids = self.get_ifaceobj_bridge_vids(ifaceobj)
2802 if vids:
2803 vids = re.split(r'[\s\t]\s*', vids)
2804 if not running_vids or not self._compare_vids(vids, running_vids,
2805 running_pvid):
2806 ifaceobjcurr.update_config_with_status(attr_name,
2807 ' '.join(running_vids), 1)
2808 else:
2809 ifaceobjcurr.update_config_with_status(attr_name,
2810 ' '.join(vids), 0)
2811 elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
2812 ((ifaceobj.flags & iface.HAS_SIBLINGS) and
2813 (ifaceobj.flags & iface.OLDEST_SIBLING))):
2814 # if the interface has multiple iface sections,
2815 # we check the below only for the oldest sibling
2816 # or the last iface section
2817
2818 # check if it matches the bridge vids
2819 bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
2820 if (bridge_vids and (not running_vids or
2821 not self._compare_vids(bridge_vids, running_vids, running_pvid))):
2822 ifaceobjcurr.status = ifaceStatus.ERROR
2823 ifaceobjcurr.status_str = 'bridge vid error'
2824
2825 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
2826 ifaceobj_getfunc):
2827 if not self._is_bridge_port(ifaceobj):
2828 # Mark all bridge attributes as failed
2829 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
2830 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2831 'bridge-pathcosts', 'bridge-portprios',
2832 'bridge-portmcrouter',
2833 'bridge-learning',
2834 'bridge-portmcfl', 'bridge-unicast-flood',
2835 'bridge-multicast-flood',
2836 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2837 ], 1)
2838 return
2839 bridgename = self._get_bridge_name(ifaceobj)
2840 if not bridgename:
2841 self.logger.warn('%s: unable to determine bridge name'
2842 %ifaceobj.name)
2843 return
2844
2845 if self.ipcmd.bridge_is_vlan_aware(bridgename):
2846 self._query_check_bridge_port_vidinfo(ifaceobj, ifaceobjcurr,
2847 ifaceobj_getfunc,
2848 bridgename)
2849 for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
2850 'bridge-portprios' : 'portprio',
2851 'bridge-portmcrouter' : 'portmcrouter',
2852 'bridge-portmcfl' : 'portmcfl',
2853 'bridge-learning' : 'learning',
2854 'bridge-unicast-flood' : 'unicast-flood',
2855 'bridge-multicast-flood' : 'multicast-flood',
2856 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2857 }.items():
2858 attrval = ifaceobj.get_attr_value_first(attr)
2859 if not attrval:
2860 continue
2861
2862 try:
2863 running_attrval = self.brctlcmd.get_bridgeport_attr(
2864 bridgename, ifaceobj.name, dstattr)
2865
2866 if dstattr == 'portmcfl':
2867 if not utils.is_binary_bool(attrval) and running_attrval:
2868 running_attrval = utils.get_yesno_boolean(
2869 utils.get_boolean_from_string(running_attrval))
2870 elif dstattr == 'portmcrouter':
2871 if self._ifla_brport_multicast_router_dict_to_int.get(attrval) == int(running_attrval):
2872 ifaceobjcurr.update_config_with_status(attr, attrval, 0)
2873 else:
2874 ifaceobjcurr.update_config_with_status(attr, attrval, 1)
2875 continue
2876 elif dstattr in ['learning',
2877 'unicast-flood',
2878 'multicast-flood',
2879 'arp-nd-suppress',
2880 ]:
2881 if not utils.is_binary_bool(attrval) and running_attrval:
2882 running_attrval = utils.get_onff_from_onezero(
2883 running_attrval)
2884
2885 if running_attrval != attrval:
2886 ifaceobjcurr.update_config_with_status(attr,
2887 running_attrval, 1)
2888 else:
2889 ifaceobjcurr.update_config_with_status(attr,
2890 running_attrval, 0)
2891 except Exception, e:
2892 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
2893
2894 self._query_check_l2protocol_tunnel_on_port(ifaceobj, ifaceobjcurr)
2895
2896 def _query_check_l2protocol_tunnel_on_port(self, ifaceobj, ifaceobjcurr):
2897 user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2898
2899 if user_config_l2protocol_tunnel:
2900 result = 0
2901 try:
2902 self._query_check_l2protocol_tunnel(ifaceobj.name, user_config_l2protocol_tunnel)
2903 except Exception as e:
2904 self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
2905 result = 1
2906 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
2907
2908 def _query_check_l2protocol_tunnel_on_bridge(self, ifaceobj, ifaceobjcurr, bridge_running_attrs):
2909 """
2910 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2911 We need to make sure that all ports comply with the mask given under the bridge
2912 """
2913 user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2914
2915 if user_config_l2protocol_tunnel:
2916 if '=' in user_config_l2protocol_tunnel:
2917 try:
2918 config_per_port_dict = self.parse_interface_list_value(user_config_l2protocol_tunnel)
2919 brport_list = config_per_port_dict.keys()
2920 except:
2921 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, 1)
2922 return
2923 else:
2924 config_per_port_dict = {}
2925 brport_list = bridge_running_attrs.get('ports', {}).keys()
2926 result = 1
2927 try:
2928 for brport_name in brport_list:
2929 self._query_check_l2protocol_tunnel(
2930 brport_name,
2931 config_per_port_dict.get(brport_name) if config_per_port_dict else user_config_l2protocol_tunnel
2932 )
2933 result = 0
2934 except Exception as e:
2935 self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
2936 result = 1
2937 ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
2938
2939 def _query_check_l2protocol_tunnel(self, brport_name, user_config_l2protocol_tunnel):
2940 cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
2941 cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
2942
2943 for protocol in re.split(',|\s*', user_config_l2protocol_tunnel):
2944 callback = self.query_check_l2protocol_tunnel_callback.get(protocol)
2945
2946 if callable(callback):
2947 if not callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2948 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2949 % (brport_name, protocol, cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi))
2950
2951 def _query_running_bridge_l2protocol_tunnel(self, brport_name, brport_ifaceobj=None, bridge_ifaceobj=None):
2952 cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
2953 cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
2954 running_protocols = []
2955 for protocol_name, callback in self.query_check_l2protocol_tunnel_callback.items():
2956 if protocol_name == 'all' and callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2957 running_protocols = self.query_check_l2protocol_tunnel_callback.keys()
2958 running_protocols.remove('all')
2959 break
2960 elif callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
2961 running_protocols.append(protocol_name)
2962 if running_protocols:
2963 if brport_ifaceobj:
2964 brport_ifaceobj.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols))
2965 elif bridge_ifaceobj:
2966 current_config = bridge_ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
2967
2968 if current_config:
2969 bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config, brport_name, ','.join(running_protocols)))
2970 else:
2971 bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name, ','.join(running_protocols)))
2972
2973 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
2974 if self._is_bridge(ifaceobj):
2975 self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
2976 else:
2977 self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
2978 ifaceobj_getfunc)
2979
2980 def _query_running_bridge(self, ifaceobjrunning, ifaceobj_getfunc):
2981 if self.ipcmd.bridge_is_vlan_aware(ifaceobjrunning.name):
2982 ifaceobjrunning.update_config('bridge-vlan-aware', 'yes')
2983 ifaceobjrunning.update_config_dict(self._query_running_attrs(
2984 ifaceobjrunning,
2985 ifaceobj_getfunc,
2986 bridge_vlan_aware=True))
2987 else:
2988 ifaceobjrunning.update_config_dict(self._query_running_attrs(
2989 ifaceobjrunning, None))
2990
2991 def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
2992 if self.systcl_get_net_bridge_stp_user_space() == '1':
2993 return
2994
2995 v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
2996 if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
2997 ifaceobjrunning.update_config('bridge-pathcosts', v)
2998
2999 v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
3000 if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
3001 ifaceobjrunning.update_config('bridge-portprios', v)
3002
3003 def _query_running_bridge_port(self, ifaceobjrunning,
3004 ifaceobj_getfunc=None):
3005
3006 bridgename = self.ipcmd.bridge_port_get_bridge_name(
3007 ifaceobjrunning.name)
3008 bridge_vids = None
3009 bridge_pvid = None
3010 if not bridgename:
3011 self.logger.warn('%s: unable to find bridgename'
3012 %ifaceobjrunning.name)
3013 return
3014
3015 if not self.ipcmd.bridge_is_vlan_aware(bridgename):
3016 try:
3017 self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, bridge_ifaceobj=ifaceobj_getfunc(bridgename)[0])
3018 except Exception as e:
3019 self.logger.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning.name, str(e)))
3020 return
3021
3022 self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, brport_ifaceobj=ifaceobjrunning)
3023
3024 (bridge_port_vids, bridge_port_pvid) = self._get_running_vids_n_pvid_str(
3025 ifaceobjrunning.name)
3026 if bridge_port_vids and bridge_port_pvid in bridge_port_vids:
3027 bridge_port_vids.remove(bridge_port_pvid)
3028
3029 bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
3030 if bridgeifaceobjlist:
3031 bridge_vids = bridgeifaceobjlist[0].get_attr_value('bridge-vids')
3032 bridge_pvid = bridgeifaceobjlist[0].get_attr_value_first('bridge-pvid')
3033
3034 if not bridge_port_vids and bridge_port_pvid:
3035 # must be an access port
3036 if bridge_port_pvid != '1':
3037 ifaceobjrunning.update_config('bridge-access',
3038 bridge_port_pvid)
3039 else:
3040 if bridge_port_vids:
3041 if (not bridge_vids or bridge_port_vids != bridge_vids):
3042 ifaceobjrunning.update_config('bridge-vids',
3043 ' '.join(bridge_port_vids))
3044 if bridge_port_pvid and bridge_port_pvid != '1':
3045 if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
3046 ifaceobjrunning.update_config('bridge-pvid',
3047 bridge_port_pvid)
3048
3049 v = utils.get_onff_from_onezero(
3050 self.brctlcmd.get_bridgeport_attr(bridgename,
3051 ifaceobjrunning.name,
3052 'learning'))
3053 if v and v != self.get_mod_subattr('bridge-learning', 'default'):
3054 ifaceobjrunning.update_config('bridge-learning', v)
3055
3056 v = utils.get_onff_from_onezero(
3057 self.brctlcmd.get_bridgeport_attr(bridgename,
3058 ifaceobjrunning.name,
3059 'unicast-flood'))
3060 if v and v != self.get_mod_subattr('bridge-unicast-flood', 'default'):
3061 ifaceobjrunning.update_config('bridge-unicast-flood', v)
3062
3063 v = utils.get_onff_from_onezero(
3064 self.brctlcmd.get_bridgeport_attr(bridgename,
3065 ifaceobjrunning.name,
3066 'multicast-flood'))
3067 if v and v != self.get_mod_subattr('bridge-multicast-flood', 'default'):
3068 ifaceobjrunning.update_config('bridge-multicast-flood', v)
3069
3070 v = utils.get_onff_from_onezero(
3071 self.brctlcmd.get_bridgeport_attr(bridgename,
3072 ifaceobjrunning.name,
3073 'arp-nd-suppress'))
3074 # Display running 'arp-nd-suppress' only on vxlan ports
3075 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3076 # otherwise, display on all bridge-ports
3077
3078 bportifaceobj = ifaceobj_getfunc(ifaceobjrunning.name)[0]
3079 if (v and
3080 v != self.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3081 (not self.arp_nd_suppress_only_on_vxlan or
3082 (self.arp_nd_suppress_only_on_vxlan and
3083 bportifaceobj.link_kind & ifaceLinkKind.VXLAN))):
3084 ifaceobjrunning.update_config('bridge-arp-nd-suppress', v)
3085
3086 self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
3087
3088 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
3089 try:
3090 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
3091 self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
3092 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
3093 self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
3094 except Exception as e:
3095 raise Exception('%s: %s' % (ifaceobjrunning.name, str(e)))
3096
3097 def _query(self, ifaceobj, **kwargs):
3098 """ add default policy attributes supported by the module """
3099 if (not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE) or
3100 ifaceobj.get_attr_value_first('bridge-stp')):
3101 return
3102 if self.default_stp_on:
3103 ifaceobj.update_config('bridge-stp', 'yes')
3104
3105 def _query_check_support_yesno_attrs(self, runningattrs, ifaceobj):
3106 for attrl in [['mcqifaddr', 'bridge-mcqifaddr'],
3107 ['mcquerier', 'bridge-mcquerier'],
3108 ['mcsnoop', 'bridge-mcsnoop']]:
3109 value = ifaceobj.get_attr_value_first(attrl[1])
3110 if value and not utils.is_binary_bool(value):
3111 if attrl[0] in runningattrs:
3112 bool = utils.get_boolean_from_string(runningattrs[attrl[0]])
3113 runningattrs[attrl[0]] = utils.get_yesno_boolean(bool)
3114
3115 self._query_check_mcrouter(ifaceobj, runningattrs)
3116 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'portmcfl', ifaceobj.get_attr_value_first('bridge-portmcfl'))
3117 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'learning', ifaceobj.get_attr_value_first('bridge-learning'))
3118 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'unicast-flood', ifaceobj.get_attr_value_first('bridge-unicast-flood'))
3119 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'multicast-flood', ifaceobj.get_attr_value_first('bridge-multicast-flood'))
3120 self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'arp-nd-suppress', ifaceobj.get_attr_value_first('bridge-arp-nd-suppress'))
3121
3122 def _query_check_mcrouter(self, ifaceobj, running_attrs):
3123 """
3124 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3125 """
3126 if 'mcrouter' in running_attrs:
3127 value = ifaceobj.get_attr_value_first('bridge-mcrouter')
3128 if value:
3129 try:
3130 int(value)
3131 except:
3132 running_attrs['mcrouter'] = 'yes' if utils.get_boolean_from_string(running_attrs['mcrouter']) else 'no'
3133
3134 def _query_check_support_yesno_attr_port(self, runningattrs, ifaceobj, attr, attrval):
3135 if attrval:
3136 portlist = self.parse_port_list(ifaceobj.name, attrval)
3137 if portlist:
3138 to_convert = []
3139 for p in portlist:
3140 (port, val) = p.split('=')
3141 if not utils.is_binary_bool(val):
3142 to_convert.append(port)
3143 for port in to_convert:
3144 runningattrs['ports'][port][attr] = utils.get_yesno_boolean(
3145 utils.get_boolean_from_string(runningattrs['ports'][port][attr]))
3146
3147 _run_ops = {
3148 'pre-up': _up,
3149 'post-down': _down,
3150 'query-checkcurr': _query_check,
3151 'query-running': _query_running,
3152 'query': _query
3153 }
3154
3155 def get_ops(self):
3156 """ returns list of ops supported by this module """
3157 return self._run_ops.keys()
3158
3159 def _init_command_handlers(self):
3160 if not self.ipcmd:
3161 self.ipcmd = self.brctlcmd = LinkUtils()
3162
3163 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
3164 """ run bridge configuration on the interface object passed as
3165 argument. Can create bridge interfaces if they dont exist already
3166
3167 Args:
3168 **ifaceobj** (object): iface object
3169
3170 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3171 'query-running'
3172
3173 Kwargs:
3174 **query_ifaceobj** (object): query check ifaceobject. This is only
3175 valid when op is 'query-checkcurr'. It is an object same as
3176 ifaceobj, but contains running attribute values and its config
3177 status. The modules can use it to return queried running state
3178 of interfaces. status is success if the running state is same
3179 as user required state in ifaceobj. error otherwise.
3180 """
3181 op_handler = self._run_ops.get(operation)
3182 if not op_handler:
3183 return
3184 self._init_command_handlers()
3185
3186 if (not LinkUtils.bridge_utils_is_installed
3187 and (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
3188 and LinkUtils.bridge_utils_missing_warning):
3189 self.logger.warning('%s: missing - bridge operation may not work as expected. '
3190 'Please check if \'bridge-utils\' package is installed' % utils.brctl_cmd)
3191 LinkUtils.bridge_utils_missing_warning = False
3192
3193 if operation == 'query-checkcurr':
3194 op_handler(self, ifaceobj, query_ifaceobj,
3195 ifaceobj_getfunc=ifaceobj_getfunc)
3196 else:
3197 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)