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