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