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