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