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