3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from collections
import Counter
15 import ifupdown2
.ifupdown
.exceptions
as exceptions
16 import ifupdown2
.ifupdown
.policymanager
as policymanager
17 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
19 from ifupdown2
.nlmanager
.nlmanager
import Link
21 from ifupdown2
.ifupdown
.iface
import *
22 from ifupdown2
.ifupdown
.utils
import utils
23 from ifupdown2
.ifupdown
.netlink
import netlink
25 from ifupdown2
.ifupdownaddons
.cache
import *
26 from ifupdown2
.ifupdownaddons
.LinkUtils
import LinkUtils
27 from ifupdown2
.ifupdownaddons
.modulebase
import moduleBase
29 import ifupdown
.exceptions
as exceptions
30 import ifupdown
.policymanager
as policymanager
31 import ifupdown
.ifupdownflags
as ifupdownflags
33 from nlmanager
.nlmanager
import Link
35 from ifupdown
.iface
import *
36 from ifupdown
.utils
import utils
37 from ifupdown
.netlink
import netlink
39 from ifupdownaddons
.cache
import *
40 from ifupdownaddons
.LinkUtils
import LinkUtils
41 from ifupdownaddons
.modulebase
import moduleBase
46 PORT_PROCESSED_OVERRIDE
= 0x2
49 class bridge(moduleBase
):
50 """ ifupdown2 addon module to configure linux bridges """
52 _modinfo
= { 'mhelp' : 'Bridge configuration module. Supports both ' +
53 'vlan aware and non vlan aware bridges. For the vlan ' +
54 'aware bridge, the port specific attributes must be ' +
55 'specified under the port. And for vlan unaware bridge ' +
56 'port specific attributes must be specified under the ' +
60 {'help' : 'vlan aware bridge. Setting this ' +
61 'attribute to yes enables vlan filtering' +
63 'validvals' : ['yes', 'no'],
64 'example' : ['bridge-vlan-aware yes/no'],
68 {'help' : 'bridge ports',
71 'validvals': ['<interface-list>', 'none'],
72 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
73 'bridge-ports glob swp1-3.100',
74 'bridge-ports regex (swp[1|2|3].100)']},
76 {'help': 'bridge-stp yes/no',
77 'example' : ['bridge-stp no'],
78 'validvals' : ['yes', 'on', 'off', 'no'],
81 {'help': 'bridge priority',
82 'validrange' : ['0', '65535'],
83 'example' : ['bridge-bridgeprio 32768'],
86 {'help': 'bridge ageing',
87 'validrange' : ['0', '65535'],
88 'example' : ['bridge-ageing 300'],
91 { 'help' : 'bridge forward delay',
92 'validrange' : ['0', '255'],
93 'example' : ['bridge-fd 15'],
97 { 'help' : 'bridge garbage collection interval in secs',
98 'validrange' : ['0', '255'],
99 'example' : ['bridge-gcint 4'],
104 { 'help' : 'bridge set hello time',
105 'validrange' : ['0', '255'],
106 'example' : ['bridge-hello 2'],
109 { 'help' : 'bridge set maxage',
110 'validrange' : ['0', '255'],
111 'example' : ['bridge-maxage 20'],
114 { 'help' : 'bridge set port path costs',
115 'validvals': ['<interface-range-list>'],
116 'validrange' : ['0', '65535'],
117 'example' : ['under the port (for vlan aware bridge): bridge-pathcosts 100',
118 'under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100'],
121 { 'help' : 'bridge port prios',
122 'validvals': ['<interface-range-list>'],
123 'validrange' : ['0', '65535'],
124 'example' : ['under the port (for vlan aware bridge): bridge-portprios 32',
125 'under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32'],
128 { 'help' : 'set multicast last member count',
129 'validrange' : ['0', '255'],
130 'example' : ['bridge-mclmc 2'],
133 { 'help': 'Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes',
134 'validvals' : ['yes', 'no', '0', '1', '2'],
135 'example' : ['bridge-mcrouter 1'],
139 { 'help' : 'set multicast snooping',
140 'validvals' : ['yes', 'no', '0', '1'],
142 'example' : ['bridge-mcsnoop yes']},
144 { 'help' : 'set multicast startup query count',
145 'validrange' : ['0', '255'],
147 'example' : ['bridge-mcsqc 2']},
149 { 'help' : 'set multicast query to use ifaddr',
150 'validvals' : ['yes', 'no', '0', '1'],
152 'example' : ['bridge-mcqifaddr no']},
154 { 'help' : 'set multicast querier',
155 'validvals' : ['yes', 'no', '0', '1'],
157 'example' : ['bridge-mcquerier no']},
159 { 'help' : 'set hash elasticity',
160 'validrange' : ['0', '4096'],
162 'example' : ['bridge-hashel 4096']},
164 { 'help' : 'set hash max',
165 'validrange' : ['0', '4096'],
167 'example' : ['bridge-hashmax 4096']},
169 { 'help' : 'set multicast last member interval (in secs)',
170 'validrange' : ['0', '255'],
172 'example' : ['bridge-mclmi 1']},
174 { 'help' : 'set multicast membership interval (in secs)',
175 'validrange' : ['0', '255'],
177 'example' : ['bridge-mcmi 260']},
179 { 'help' : 'set multicast querier interval (in secs)',
180 'validrange' : ['0', '255'],
182 'example' : ['bridge-mcqpi 255']},
184 { 'help' : 'set multicast query interval (in secs)',
185 'validrange' : ['0', '255'],
187 'example' : ['bridge-mcqi 125']},
189 { 'help' : 'set multicast query response interval (in secs)',
190 'validrange' : ['0', '255'],
192 'example' : ['bridge-mcqri 10']},
194 { 'help' : 'set multicast startup query interval (in secs)',
195 'validrange' : ['0', '255'],
197 'example' : ['bridge-mcsqi 31']},
199 { 'help' : 'set per VLAN v4 multicast querier source address',
200 'validvals' : ['<number-ipv4-list>', ],
203 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
204 'bridge-portmcrouter':
206 'help': 'Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled',
207 'validvals': ['<interface-disabled-automatic-enabled>'],
209 'under the port (for vlan aware bridge): bridge-portmcrouter 0',
210 'under the port (for vlan aware bridge): bridge-portmcrouter 1',
211 'under the port (for vlan aware bridge): bridge-portmcrouter 2',
212 'under the port (for vlan aware bridge): bridge-portmcrouter disabled',
213 'under the port (for vlan aware bridge): bridge-portmcrouter automatic',
214 'under the port (for vlan aware bridge): bridge-portmcrouter enabled',
215 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2',
216 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled',
217 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1',
221 { 'help' : 'port multicast fast leave.',
222 'validvals': ['<interface-yes-no-0-1-list>'],
224 'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
225 'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
227 { 'help' : 'wait for a max of time secs for the' +
228 ' specified ports to become available,' +
229 'if no ports are specified then those' +
230 ' specified on bridge-ports will be' +
231 ' used here. Specifying no ports here ' +
232 'should not be used if we are using ' +
233 'regex or \"all\" on bridge_ports,' +
234 'as it wouldnt work.',
236 'validvals': ['<number-interface-list>'],
237 'example' : ['bridge-waitport 4 swp1 swp2']},
239 { 'help' : 'forces to time seconds the maximum time ' +
240 'that the Debian bridge setup scripts will ' +
241 'wait for the bridge ports to get to the ' +
242 'forwarding status, doesn\'t allow factional ' +
243 'part. If it is equal to 0 then no waiting' +
245 'validrange' : ['0', '255'],
247 'example' : ['bridge-maxwait 3']},
249 { 'help' : 'bridge port vids. Can be specified ' +
250 'under the bridge or under the port. ' +
251 'If specified under the bridge the ports ' +
252 'inherit it unless overridden by a ' +
253 'bridge-vids attribute under the port',
255 'validvals': ['<number-comma-range-list>'],
256 'example' : ['bridge-vids 4000',
257 'bridge-vids 2000 2200-3000'],
258 'aliases': ['bridge-trunk']},
260 { 'help' : 'bridge port pvid. Must be specified under' +
262 'validrange' : ['0', '4096'],
263 'example' : ['bridge-pvid 1']},
265 { 'help' : 'bridge port access vlan. Must be ' +
266 'specified under the bridge port',
267 'validrange' : ['1', '4094'],
268 'example' : ['bridge-access 300']},
269 'bridge-allow-untagged' :
270 { 'help' : 'indicate if the bridge port accepts ' +
271 'untagged packets or not. Must be ' +
272 'specified under the bridge port. ' +
273 'Default is \'yes\'',
274 'validvals' : ['yes', 'no'],
275 'example' : ['bridge-allow-untagged yes'],
278 { 'help' : 'bridge vlans',
280 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
281 'bridge-port-pvids' :
282 { 'help' : 'bridge port vlans',
284 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
286 { 'help' : 'bridge port learning flag',
287 'validvals': ['on', 'off', '<interface-on-off-list>'],
289 'example' : ['bridge-learning off']},
290 'bridge-igmp-version' :
291 { 'help' : 'mcast igmp version',
292 'validvals': ['2', '3'],
294 'example' : ['bridge-igmp-version 2']},
295 'bridge-mld-version':
296 { 'help' : 'mcast mld version',
297 'validvals': ['1', '2'],
299 'example' : ['bridge-mld-version 1']},
300 'bridge-unicast-flood' :
301 { 'help' : 'bridge port unicast flood flag',
302 'validvals': ['on', 'off', '<interface-on-off-list>'],
304 'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
305 'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
306 'bridge-multicast-flood' :
307 { 'help' : 'bridge port multicast flood flag',
308 'validvals': ['on', 'off', '<interface-on-off-list>'],
310 'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
311 'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
312 'bridge-vlan-protocol' :
313 { 'help' : 'bridge vlan protocol',
314 'default' : '802.1q',
315 'validvals': ['802.1q', '802.1ad'],
316 'example' : ['bridge-vlan-protocol 802.1q']},
317 'bridge-vlan-stats' :
318 { 'help' : 'bridge vlan stats',
320 'validvals': ['on', 'off'],
321 'example' : ['bridge-vlan-stats off']},
322 'bridge-arp-nd-suppress' :
323 { 'help' : 'bridge port arp nd suppress flag',
324 'validvals': ['on', 'off', '<interface-on-off-list>'],
326 'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
327 'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
329 { 'help' : 'bridge multicast stats',
331 'validvals': ['on', 'off'],
332 'example' : ['bridge-mcstats off']},
333 'bridge-l2protocol-tunnel': {
334 'help': 'layer 2 protocol tunneling',
335 'validvals': [ # XXX: lists all combinations, should move to
336 # a better representation
341 'cdp lacp lldp pvst',
356 'lacp lldp pvst stp',
368 '<interface-l2protocol-tunnel-list>'],
370 'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
371 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
372 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
373 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
374 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
379 # Netlink attributes not associated with ifupdown2
380 # attributes are left commented-out for a future use
381 # and kept in order :)
382 _ifla_br_attributes_map
= (
383 # Link.IFLA_BR_UNSPEC,
384 ('bridge-fd', Link
.IFLA_BR_FORWARD_DELAY
),
385 ('bridge-hello', Link
.IFLA_BR_HELLO_TIME
),
386 ('bridge-maxage', Link
.IFLA_BR_MAX_AGE
),
387 ('bridge-ageing', Link
.IFLA_BR_AGEING_TIME
),
388 ('bridge-stp', Link
.IFLA_BR_STP_STATE
),
389 ('bridge-bridgeprio', Link
.IFLA_BR_PRIORITY
),
390 ('bridge-vlan-aware', Link
.IFLA_BR_VLAN_FILTERING
),
391 ('bridge-vlan-protocol', Link
.IFLA_BR_VLAN_PROTOCOL
),
392 # Link.IFLA_BR_GROUP_FWD_MASK,
393 # Link.IFLA_BR_ROOT_ID,
394 # Link.IFLA_BR_BRIDGE_ID,
395 # Link.IFLA_BR_ROOT_PORT,
396 # (Link.IFLA_BR_ROOT_PATH_COST,,
397 # Link.IFLA_BR_TOPOLOGY_CHANGE,
398 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
399 # Link.IFLA_BR_HELLO_TIMER,
400 # Link.IFLA_BR_TCN_TIMER,
401 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
402 # Link.IFLA_BR_GC_TIMER,
403 # Link.IFLA_BR_GROUP_ADDR,
404 # Link.IFLA_BR_FDB_FLUSH,
405 ('bridge-mcrouter', Link
.IFLA_BR_MCAST_ROUTER
),
406 #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
407 ('bridge-mcqifaddr', Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
),
408 ('bridge-mcquerier', Link
.IFLA_BR_MCAST_QUERIER
),
409 ('bridge-hashel', Link
.IFLA_BR_MCAST_HASH_ELASTICITY
),
410 ('bridge-hashmax', Link
.IFLA_BR_MCAST_HASH_MAX
),
411 ('bridge-mclmc', Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
),
412 ('bridge-mcsqc', Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
),
413 ('bridge-mclmi', Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
),
414 ('bridge-mcmi', Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
),
415 ('bridge-mcqpi', Link
.IFLA_BR_MCAST_QUERIER_INTVL
),
416 ('bridge-mcqi', Link
.IFLA_BR_MCAST_QUERY_INTVL
),
417 ('bridge-mcqri', Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
),
418 ('bridge-mcsqi', Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
),
419 # Link.IFLA_BR_NF_CALL_IPTABLES,
420 # Link.IFLA_BR_NF_CALL_IP6TABLES,
421 # Link.IFLA_BR_NF_CALL_ARPTABLES,
422 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
424 # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
425 ('bridge-igmp-version', Link
.IFLA_BR_MCAST_IGMP_VERSION
, ),
426 ('bridge-mcstats', Link
.IFLA_BR_MCAST_STATS_ENABLED
),
427 ('bridge-mld-version', Link
.IFLA_BR_MCAST_MLD_VERSION
)
429 # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
430 # they are supported. It is done this way because this dictionary is used
431 # in a loop, but these attributes require additional work. Thus they are
432 # excluded from this loop without overhead.
434 # we are still using the old linkCache we need an easy way
435 # to use this cache with the new full-netlink approach
436 _ifla_br_attributes_old_cache_key_map
= dict(
438 (Link
.IFLA_BR_FORWARD_DELAY
, 'fd'),
439 (Link
.IFLA_BR_HELLO_TIME
, 'hello'),
440 (Link
.IFLA_BR_MAX_AGE
, 'maxage'),
441 (Link
.IFLA_BR_AGEING_TIME
, 'ageing'),
442 (Link
.IFLA_BR_STP_STATE
, 'stp'),
443 (Link
.IFLA_BR_PRIORITY
, 'bridgeprio'),
444 (Link
.IFLA_BR_VLAN_FILTERING
, 'vlan_filtering'),
445 (Link
.IFLA_BR_VLAN_PROTOCOL
, 'vlan-protocol'),
446 (Link
.IFLA_BR_MCAST_ROUTER
, 'mcrouter'),
447 (Link
.IFLA_BR_MCAST_SNOOPING
, 'mcsnoop'),
448 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, 'mcqifaddr'),
449 (Link
.IFLA_BR_MCAST_QUERIER
, 'mcquerier'),
450 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, 'hashel'),
451 (Link
.IFLA_BR_MCAST_HASH_MAX
, 'hashmax'),
452 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, 'mclmc'),
453 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, 'mcsqc'),
454 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, 'mclmi'),
455 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, 'mcmi'),
456 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, 'mcqpi'),
457 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, 'mcqi'),
458 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, 'mcqri'),
459 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, 'mcsqi'),
460 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, 'vlan-stats'),
461 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, 'mcstats'),
462 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, 'igmp-version'),
463 (Link
.IFLA_BR_MCAST_MLD_VERSION
, 'mld-version')
467 _ifla_br_attributes_translate_user_config_to_netlink_map
= dict(
469 # Link.IFLA_BR_UNSPEC,
470 (Link
.IFLA_BR_FORWARD_DELAY
, lambda x
: int(x
) * 100),
471 (Link
.IFLA_BR_HELLO_TIME
, lambda x
: int(x
) * 100),
472 (Link
.IFLA_BR_MAX_AGE
, lambda x
: int(x
) * 100),
473 (Link
.IFLA_BR_AGEING_TIME
, lambda x
: int(x
) * 100),
474 # Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
475 (Link
.IFLA_BR_PRIORITY
, int),
476 (Link
.IFLA_BR_VLAN_FILTERING
, utils
.get_boolean_from_string
),
477 (Link
.IFLA_BR_VLAN_PROTOCOL
, str),
478 # Link.IFLA_BR_GROUP_FWD_MASK,
479 # Link.IFLA_BR_ROOT_ID,
480 # Link.IFLA_BR_BRIDGE_ID,
481 # Link.IFLA_BR_ROOT_PORT,
482 # Link.IFLA_BR_ROOT_PATH_COST,
483 # Link.IFLA_BR_TOPOLOGY_CHANGE,
484 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
485 # Link.IFLA_BR_HELLO_TIMER,
486 # Link.IFLA_BR_TCN_TIMER,
487 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
488 # Link.IFLA_BR_GC_TIMER,
489 # Link.IFLA_BR_GROUP_ADDR,
490 # Link.IFLA_BR_FDB_FLUSH,
491 (Link
.IFLA_BR_MCAST_ROUTER
, utils
.get_int_from_boolean_and_string
),
492 (Link
.IFLA_BR_MCAST_SNOOPING
, utils
.get_boolean_from_string
),
493 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, utils
.get_boolean_from_string
),
494 (Link
.IFLA_BR_MCAST_QUERIER
, utils
.get_boolean_from_string
),
495 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, int),
496 (Link
.IFLA_BR_MCAST_HASH_MAX
, int),
497 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, int),
498 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, int),
499 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, lambda x
: int(x
) * 100),
500 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, lambda x
: int(x
) * 100),
501 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, lambda x
: int(x
) * 100),
502 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, lambda x
: int(x
) * 100),
503 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, lambda x
: int(x
) * 100),
504 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, lambda x
: int(x
) * 100),
505 # Link.IFLA_BR_NF_CALL_IPTABLES,
506 # Link.IFLA_BR_NF_CALL_IP6TABLES,
507 # Link.IFLA_BR_NF_CALL_ARPTABLES,
508 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
510 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, utils
.get_boolean_from_string
),
511 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, int),
512 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, utils
.get_boolean_from_string
),
513 (Link
.IFLA_BR_MCAST_MLD_VERSION
, int)
517 _ifla_brport_attributes_map
= (
518 # Link.IFLA_BRPORT_UNSPEC,
519 # Link.IFLA_BRPORT_STATE,
520 ('bridge-portprios', Link
.IFLA_BRPORT_PRIORITY
),
521 ('bridge-pathcosts', Link
.IFLA_BRPORT_COST
),
522 # Link.IFLA_BRPORT_MODE,
523 # Link.IFLA_BRPORT_GUARD,
524 # Link.IFLA_BRPORT_PROTECT,
525 ('bridge-portmcfl', Link
.IFLA_BRPORT_FAST_LEAVE
),
526 ('bridge-learning', Link
.IFLA_BRPORT_LEARNING
),
527 ('bridge-unicast-flood', Link
.IFLA_BRPORT_UNICAST_FLOOD
),
528 # Link.IFLA_BRPORT_PROXYARP,
529 # Link.IFLA_BRPORT_LEARNING_SYNC,
530 # Link.IFLA_BRPORT_PROXYARP_WIFI,
531 # Link.IFLA_BRPORT_ROOT_ID,
532 # Link.IFLA_BRPORT_BRIDGE_ID,
533 # Link.IFLA_BRPORT_DESIGNATED_PORT,
534 # Link.IFLA_BRPORT_DESIGNATED_COST,
535 # Link.IFLA_BRPORT_ID,
536 # Link.IFLA_BRPORT_NO,
537 # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
538 # Link.IFLA_BRPORT_CONFIG_PENDING,
539 # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
540 # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
541 # Link.IFLA_BRPORT_HOLD_TIMER,
542 # Link.IFLA_BRPORT_FLUSH,
543 ('bridge-portmcrouter', Link
.IFLA_BRPORT_MULTICAST_ROUTER
),
544 # Link.IFLA_BRPORT_PAD,
545 ('bridge-multicast-flood', Link
.IFLA_BRPORT_MCAST_FLOOD
),
546 # Link.IFLA_BRPORT_MCAST_TO_UCAST,
547 # Link.IFLA_BRPORT_VLAN_TUNNEL,
548 # Link.IFLA_BRPORT_BCAST_FLOOD
549 ('bridge-l2protocol-tunnel', Link
.IFLA_BRPORT_GROUP_FWD_MASK
),
550 # Link.IFLA_BRPORT_PEER_LINK,
551 # Link.IFLA_BRPORT_DUAL_LINK,
552 ('bridge-arp-nd-suppress', Link
.IFLA_BRPORT_ARP_SUPPRESS
),
555 _ifla_brport_multicast_router_dict_to_int
= {
566 # callable to translate <interface-yes-no-0-1-list> to netlink value
567 _ifla_brport_attributes_translate_user_config_to_netlink_map
= dict(
569 (Link
.IFLA_BRPORT_PRIORITY
, int),
570 (Link
.IFLA_BRPORT_COST
, int),
571 (Link
.IFLA_BRPORT_MULTICAST_ROUTER
, lambda x
: bridge
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(x
, 0)),
572 (Link
.IFLA_BRPORT_FAST_LEAVE
, utils
.get_boolean_from_string
),
573 (Link
.IFLA_BRPORT_LEARNING
, utils
.get_boolean_from_string
),
574 (Link
.IFLA_BRPORT_UNICAST_FLOOD
, utils
.get_boolean_from_string
),
575 (Link
.IFLA_BRPORT_MCAST_FLOOD
, utils
.get_boolean_from_string
),
576 (Link
.IFLA_BRPORT_GROUP_FWD_MASK
, lambda x
: x
),
577 (Link
.IFLA_BRPORT_ARP_SUPPRESS
, utils
.get_boolean_from_string
)
581 def __init__(self
, *args
, **kargs
):
582 moduleBase
.__init
__(self
, *args
, **kargs
)
584 self
.name
= self
.__class
__.__name
__
586 self
._running
_vidinfo
= {}
587 self
._running
_vidinfo
_valid
= False
588 self
._resv
_vlan
_range
= self
._get
_reserved
_vlan
_range
()
589 self
.logger
.debug('%s: using reserved vlan range %s' % (self
.__class
__.__name
__, str(self
._resv
_vlan
_range
)))
591 self
.default_stp_on
= utils
.get_boolean_from_string(
592 policymanager
.policymanager_api
.get_attr_default(
593 module_name
=self
.__class
__.__name
__,
598 self
.default_vlan_stats
= policymanager
.policymanager_api
.get_attr_default(
599 module_name
=self
.__class
__.__name
__,
600 attr
='bridge-vlan-stats'
603 self
.warn_on_untagged_bridge_absence
= utils
.get_boolean_from_string(
604 policymanager
.policymanager_api
.get_module_globals(
605 module_name
=self
.__class
__.__name
__,
606 attr
='warn_on_untagged_bridge_absence'
609 self
.logger
.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
610 % self
.warn_on_untagged_bridge_absence
)
612 self
._vxlan
_bridge
_default
_igmp
_snooping
= policymanager
.policymanager_api
.get_module_globals(
613 self
.__class
__.__name
__,
614 'vxlan_bridge_default_igmp_snooping'
616 self
.logger
.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
617 % self
._vxlan
_bridge
_default
_igmp
_snooping
)
619 self
.arp_nd_suppress_only_on_vxlan
= utils
.get_boolean_from_string(
620 policymanager
.policymanager_api
.get_module_globals(
621 module_name
=self
.__class
__.__name
__,
622 attr
='allow_arp_nd_suppress_only_on_vxlan'
625 self
.logger
.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self
.arp_nd_suppress_only_on_vxlan
)
628 self
.bridge_allow_multiple_vlans
= utils
.get_boolean_from_string(
629 self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
632 # Cumulus Linux specific variable. Failure probably means that
633 # ifupdown2 is running a a different system.
634 self
.bridge_allow_multiple_vlans
= True
635 self
.logger
.debug('bridge: init: multiple vlans allowed %s' % self
.bridge_allow_multiple_vlans
)
637 self
.bridge_mac_iface_list
= policymanager
.policymanager_api
.get_module_globals(self
.__class
__.__name
__, 'bridge_mac_iface') or []
638 self
.bridge_mac_iface
= None, None # ifname, mac
640 self
.bridge_set_static_mac_from_port
= utils
.get_boolean_from_string(
641 policymanager
.policymanager_api
.get_module_globals(
642 self
.__class
__.__name
__, 'bridge_set_static_mac_from_port'
646 self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
= utils
.get_boolean_from_string(
647 policymanager
.policymanager_api
.get_module_globals(
648 module_name
=self
.__class
__.__name
__,
649 attr
="vxlan_bridge_igmp_snooping_enable_port_mcrouter"
654 self
.l2protocol_tunnel_callback
= {
655 'all': self
._l2protocol
_tunnel
_set
_all
,
656 'stp': self
._l2protocol
_tunnel
_set
_stp
,
657 'cdp': self
._l2protocol
_tunnel
_set
_cdp
,
658 'pvst': self
._l2protocol
_tunnel
_set
_pvst
,
659 'lldp': self
._l2protocol
_tunnel
_set
_lldp
,
660 'lacp': self
._l2protocol
_tunnel
_set
_lacp
663 self
.query_check_l2protocol_tunnel_callback
= {
664 'all': self
._query
_check
_l2protocol
_tunnel
_all
,
665 'stp': self
._query
_check
_l2protocol
_tunnel
_stp
,
666 'cdp': self
._query
_check
_l2protocol
_tunnel
_cdp
,
667 'pvst': self
._query
_check
_l2protocol
_tunnel
_pvst
,
668 'lldp': self
._query
_check
_l2protocol
_tunnel
_lldp
,
669 'lacp': self
._query
_check
_l2protocol
_tunnel
_lacp
673 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
674 if not ifla_brport_group_maskhi
:
675 ifla_brport_group_maskhi
= 0x1
677 ifla_brport_group_maskhi |
= 0x1
678 return ifla_brport_group_mask
, ifla_brport_group_maskhi
681 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
682 if not ifla_brport_group_maskhi
:
683 ifla_brport_group_maskhi
= 0x2
685 ifla_brport_group_maskhi |
= 0x2
686 return ifla_brport_group_mask
, ifla_brport_group_maskhi
689 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
690 if not ifla_brport_group_mask
:
691 ifla_brport_group_mask
= 0x1
693 ifla_brport_group_mask |
= 0x1
694 return ifla_brport_group_mask
, ifla_brport_group_maskhi
697 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
698 if not ifla_brport_group_mask
:
699 ifla_brport_group_mask
= 0x4
701 ifla_brport_group_mask |
= 0x4
702 return ifla_brport_group_mask
, ifla_brport_group_maskhi
705 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
706 if not ifla_brport_group_mask
:
707 ifla_brport_group_mask
= 0x4000
709 ifla_brport_group_mask |
= 0x4000
710 return ifla_brport_group_mask
, ifla_brport_group_maskhi
713 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
714 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
715 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
718 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
719 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x1
722 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
723 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x2
726 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
727 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x1
730 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
731 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4000
734 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
735 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4
738 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
739 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
741 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
742 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
743 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
744 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
746 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
747 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
748 return retval
and c1
#and c2
750 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
752 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
754 for brport_name
in ifaceobj
.lowerifaces
:
755 for obj
in ifaceobj_getfunc(brport_name
) or []:
756 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
757 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
758 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
759 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
760 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
761 % (ifaceobj
.name
, brport_name
))
764 vlan_id
= sub_intf_vlan_id
767 def check_bridge_port_vid_attrs(self
, ifaceobj
):
768 if (ifaceobj
.get_attr_value('bridge-access') and
769 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
770 ifaceobj
.get_attr_value('bridge-pvid'))):
771 self
.logger
.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
772 'will be ignored' % ifaceobj
.name
)
776 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
777 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
778 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
782 for port_name
in ports
:
783 port_obj_l
= ifaceobj_getfunc(port_name
)
784 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
785 self
.logger
.error('%s: %s: vlan sub-interface is not '
786 'supported in a vlan-aware bridge'
787 % (ifaceobj
.name
, port_name
))
790 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
791 self
.arp_nd_suppress_only_on_vxlan
and
792 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
793 self
.log_error('\'bridge-arp-nd-suppress\' is not '
794 'supported on a non-vxlan port %s'
800 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
801 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
802 'device (%s) is part of vlan aware bridge (%s)'
803 % (ifaceobj
.name
, bridgename
), ifaceobj
)
805 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
806 if not ifaceobj_getfunc
:
808 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
809 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
810 if ifaceobj
.get_attr_value('bridge-access'):
812 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
813 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
814 if not ifaceobj_upper_list
:
816 ifaceobj_upper
= ifaceobj_upper_list
[0]
817 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
818 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
819 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
820 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
823 or not self
._compare
_vids
(bridge_vids
,
826 self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
,
832 def _is_bridge(ifaceobj
):
833 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
834 ifaceobj
.get_attr_value_first('bridge-ports') or
835 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
837 def _get_ifaceobj_bridge_ports(self
, ifaceobj
):
840 for brport
in ifaceobj
.get_attr_value('bridge-ports') or []:
842 bridge_ports
.extend(brport
.split())
844 return ' '.join(bridge_ports
)
846 def _is_bridge_port(self
, ifaceobj
):
847 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
851 def check_valid_bridge(self
, ifaceobj
, ifname
):
852 if LinkUtils
.link_exists_nodryrun(ifname
) and not LinkUtils
.is_bridge(ifname
):
853 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
857 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
858 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
860 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
861 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
862 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
863 # for special vlan aware bridges, we need to add another bit
864 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
865 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
866 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
867 ifaceobj
.role |
= ifaceRole
.MASTER
868 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
869 return self
.parse_port_list(ifaceobj
.name
,
870 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
873 def get_dependent_ifacenames_running(self
, ifaceobj
):
874 self
._init
_command
_handlers
()
875 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
877 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
879 def _get_bridge_port_list(self
, ifaceobj
):
881 # port list is also available in the previously
882 # parsed dependent list. Use that if available, instead
883 # of parsing port expr again
884 port_list
= ifaceobj
.lowerifaces
887 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
889 return self
.parse_port_list(ifaceobj
.name
, ports
)
893 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
894 # When enslaving bridge-ports we need to return the exact user
895 # configured bridge ports list (bridge will inherit the mac of the
897 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
898 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
900 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
901 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
902 if not waitport_value
: return
904 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
905 if not waitportvals
: return
907 waitporttime
= int(waitportvals
[0])
909 self
.log_warn('%s: invalid waitport value \'%s\''
910 %(ifaceobj
.name
, waitportvals
[0]))
912 if waitporttime
<= 0: return
914 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
916 except IndexError, e
:
917 # ignore error and use all bridge ports
918 waitportlist
= portlist
920 if not waitportlist
: return
921 self
.logger
.info('%s: waiting for ports %s to exist ...'
922 %(ifaceobj
.name
, str(waitportlist
)))
923 starttime
= time
.time()
924 while ((time
.time() - starttime
) < waitporttime
):
925 if all([False for p
in waitportlist
926 if not self
.ipcmd
.link_exists(p
)]):
930 self
.log_warn('%s: unable to process waitport: %s'
931 %(ifaceobj
.name
, str(e
)))
933 def _enable_disable_ipv6(self
, port
, enable
='1'):
935 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
937 self
.logger
.info(str(e
))
939 def handle_ipv6(self
, ports
, state
, ifaceobj
=None):
941 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
) and
942 not ifaceobj
.get_attr_value('address')):
943 self
._enable
_disable
_ipv
6(ifaceobj
.name
, state
)
945 self
._enable
_disable
_ipv
6(p
, state
)
947 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
948 """ pretty print bridge port add errors.
949 since the commands are batched and the kernel only returns error
950 codes, this function tries to interpret some error codes
951 and prints clearer errors """
953 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
954 # Cumulus Linux specific error checks
956 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
958 for bport
in bridgeports
:
959 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
961 if currvlanid
!= vlanid
:
962 self
.log_error('%s: ' %bridgeifaceobj
.name
+
963 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
967 except Exception as e
:
968 errstr
+= '\n%s' % str(e
)
969 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
971 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
972 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
973 runningbridgeports
= []
975 self
.ipcmd
.batch_start()
976 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
977 self
.ipcmd
.batch_start()
978 # Delete active ports not in the new port list
979 if not ifupdownflags
.flags
.PERFMODE
:
980 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
981 if runningbridgeports
:
982 for bport
in runningbridgeports
:
983 if not bridgeports
or bport
not in bridgeports
:
984 self
.ipcmd
.link_set(bport
, 'nomaster')
985 # set admin DOWN on all removed ports
986 # that don't have config outside bridge
987 if not ifaceobj_getfunc(bport
):
988 netlink
.link_set_updown(bport
, "down")
989 # enable ipv6 for ports that were removed
990 self
.handle_ipv6([bport
], '0')
992 runningbridgeports
= []
994 self
.ipcmd
.batch_commit()
998 newbridgeports
= Set(bridgeports
).difference(Set(runningbridgeports
))
999 newly_enslaved_ports
= []
1001 newbridgeports_ordered
= []
1002 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
1003 if br_port
in newbridgeports
:
1004 newbridgeports_ordered
.append(br_port
)
1006 for bridgeport
in newbridgeports_ordered
:
1008 if (not ifupdownflags
.flags
.DRYRUN
and
1009 not self
.ipcmd
.link_exists(bridgeport
)):
1010 self
.log_error('%s: bridge port %s does not exist'
1011 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
1014 hwaddress
= self
.ipcmd
.link_get_hwaddress(bridgeport
)
1015 if not self
._valid
_ethaddr
(hwaddress
):
1016 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
1017 bridgeport
) + 'invalid ether addr %s'
1020 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
1021 newly_enslaved_ports
.append(bridgeport
)
1022 self
.handle_ipv6([bridgeport
], '1')
1023 self
.ipcmd
.addr_flush(bridgeport
)
1027 self
.ipcmd
.batch_commit()
1028 self
.ipcmd
.batch_start()
1029 except Exception, e
:
1030 self
.logger
.error(str(e
))
1033 self
.ipcmd
.batch_commit()
1034 except Exception, e
:
1035 self
._pretty
_print
_add
_ports
_error
(str(e
), ifaceobj
,
1040 self
.log_error('bridge configuration failed (missing ports)')
1042 return newly_enslaved_ports
1044 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1045 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1046 if not maxwait
: return
1048 maxwait
= int(maxwait
)
1050 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1053 if not maxwait
: return
1054 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1057 starttime
= time
.time()
1058 while ((time
.time() - starttime
) < maxwait
):
1059 if all([False for p
in portlist
1060 if self
.read_file_oneline(
1061 '/sys/class/net/%s/brif/%s/state'
1062 %(ifaceobj
.name
, p
)) != '3']):
1065 except Exception, e
:
1066 self
.log_warn('%s: unable to process maxwait: %s'
1067 %(ifaceobj
.name
, str(e
)))
1069 def _ints_to_ranges(self
, ints
):
1070 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
1072 yield b
[0][1], b
[-1][1]
1074 def _ranges_to_ints(self
, rangelist
):
1075 """ returns expanded list of integers given set of string ranges
1076 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1080 for part
in rangelist
:
1082 a
, b
= part
.split('-')
1083 a
, b
= int(a
), int(b
)
1084 result
.extend(range(a
, b
+ 1))
1089 self
.logger
.warn('unable to parse vids \'%s\''
1090 %''.join(rangelist
))
1094 def _compress_into_ranges(self
, vids_ints
):
1095 return ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
1096 for start
, end
in self
._ints
_to
_ranges
(vids_ints
)]
1098 def _diff_vids(self
, vids1_ints
, vids2_ints
):
1099 return Set(vids2_ints
).difference(vids1_ints
), Set(vids1_ints
).difference(vids2_ints
)
1101 def _compare_vids(self
, vids1
, vids2
, pvid
=None):
1102 """ Returns true if the vids are same else return false """
1104 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
1105 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
1106 set_diff
= Set(vids1_ints
).symmetric_difference(vids2_ints
)
1107 if pvid
and int(pvid
) in set_diff
:
1108 set_diff
.remove(int(pvid
))
1114 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1116 # Sets old style igmp querier
1118 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1120 running_mcqv4src
= {}
1121 if not ifupdownflags
.flags
.PERFMODE
:
1122 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobj
.name
)
1124 srclist
= attrval
.split()
1129 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
1131 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1132 for v
in mcqs
.keys():
1133 self
.brctlcmd
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1134 elif not ifupdownflags
.flags
.PERFMODE
:
1135 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobj
.name
)
1136 if running_mcqv4src
:
1137 for v
in running_mcqv4src
.keys():
1138 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1140 def _get_running_vidinfo(self
):
1141 if self
._running
_vidinfo
_valid
:
1142 return self
._running
_vidinfo
1143 self
._running
_vidinfo
= {}
1145 # Removed check for PERFMODE. Need the get in all cases
1146 # including reboot, so that we can configure the pvid correctly.
1147 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all_json()
1148 self
._running
_vidinfo
_valid
= True
1149 return self
._running
_vidinfo
1151 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1153 # Supports old style vlan vid info format
1156 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1157 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1158 if not bridge_port_pvids
and not bridge_port_vids
:
1161 # Handle bridge vlan attrs
1163 if bridge_port_pvids
:
1164 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1166 self
.log_warn('%s: could not parse \'%s %s\''
1167 %(ifaceobj
.name
, 'bridge-port-pvids',
1172 (port
, pvid
) = p
.split('=')
1174 running_pvid
= self
._get
_running
_pvid
(port
)
1176 if running_pvid
== pvid
:
1179 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
1180 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
1181 except Exception, e
:
1182 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1183 %(ifaceobj
.name
, p
, str(e
)))
1186 if bridge_port_vids
:
1187 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1189 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1190 'bridge-port-vids', bridge_port_vids
))
1194 (port
, val
) = p
.split('=')
1195 vids
= val
.split(',')
1196 vids_int
= self
._ranges
_to
_ints
(vids
)
1197 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
1199 (vids_to_del
, vids_to_add
) = \
1200 self
._diff
_vids
(vids_int
, running_vids
)
1202 self
.ipcmd
.bridge_port_vids_del(port
,
1203 self
._compress
_into
_ranges
(vids_to_del
))
1205 self
.ipcmd
.bridge_port_vids_add(port
,
1206 self
._compress
_into
_ranges
(vids_to_add
))
1208 self
.ipcmd
.bridge_port_vids_add(port
, vids_int
)
1209 except Exception, e
:
1210 self
.log_warn('%s: failed to set vid `%s` (%s)'
1211 %(ifaceobj
.name
, p
, str(e
)))
1213 def _is_running_stp_state_on(self
, bridgename
):
1214 """ Returns True if running stp state is on, else False """
1216 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1218 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1219 return running_stp_state
and running_stp_state
!= '0'
1223 def _is_config_stp_state_on(self
, ifaceobj
):
1224 """ Returns true if user specified stp state is on, else False """
1226 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1228 return self
.default_stp_on
1229 return utils
.get_boolean_from_string(stp_attr
)
1231 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1232 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1233 if not mcsnoop
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1234 return self
._vxlan
_bridge
_default
_igmp
_snooping
1237 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1245 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1247 if not callable(translate_func
):
1251 user_config
= policymanager
.policymanager_api
.get_iface_default(
1252 module_name
=self
.__class
__.__name
__,
1257 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1258 if old_cache_key
and not link_just_created
:
1259 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1260 if not cached_value
or cached_value
== "None":
1261 # the link already exists but we don't have any value
1262 # cached for this attr, it probably means that the
1263 # capability is not available on this system (i.e old kernel)
1264 self
.logger
.debug('%s: ignoring %s %s: capability '
1265 'probably not supported on this system'
1266 % (ifname
, attr_name
, user_config
))
1268 # we need to convert the cache value to "netlink" format
1269 cached_value
= translate_func(cached_value
.lower())
1273 if not user_config
and not link_just_created
and cached_value
is not None:
1274 # there is no user configuration for this attribute
1275 # if the bridge existed before we need to check if
1276 # this attribute needs to be reset to default value
1277 default_value
= self
.get_attr_default_value(attr_name
)
1280 # the attribute has a default value, we need to convert it to
1281 # netlink format to compare it with the cache value
1282 default_value_nl
= translate_func(default_value
) # default_value.lower()
1284 if default_value_nl
!= cached_value
:
1285 # the running value difers from the default value
1286 # but the user didn't specify any config
1287 # resetting attribute to default
1288 ifla_info_data
[nl_attr
] = default_value_nl
1289 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1291 user_config_nl
= translate_func(user_config
) # user_config.lower()
1293 if user_config_nl
!= cached_value
:
1294 ifla_info_data
[nl_attr
] = user_config_nl
1296 if cached_value
is not None:
1297 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1299 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1300 except Exception as e
:
1301 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1303 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1304 ifla_info_data
= dict()
1305 ifname
= ifaceobj
.name
1307 self
.logger
.info('%s: apply bridge settings' % ifname
)
1309 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1310 self
.fill_ifla_info_data_with_ifla_br_attribute(
1311 ifla_info_data
=ifla_info_data
,
1312 link_just_created
=link_just_created
,
1315 attr_name
=attr_name
,
1316 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1320 self
.fill_ifla_info_data_with_ifla_br_attribute(
1321 ifla_info_data
=ifla_info_data
,
1322 link_just_created
=link_just_created
,
1324 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1325 attr_name
='bridge-mcsnoop',
1326 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1330 if bridge_vlan_aware
:
1331 self
.fill_ifla_info_data_with_ifla_br_attribute(
1332 ifla_info_data
=ifla_info_data
,
1333 link_just_created
=link_just_created
,
1335 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1336 attr_name
='bridge-vlan-stats',
1337 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1341 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1342 if not self
._is
_running
_stp
_state
_on
(ifname
):
1343 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1344 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1345 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1346 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1347 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1349 # If stp not specified and running stp state on, set it to off
1350 if self
._is
_running
_stp
_state
_on
(ifname
):
1351 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1352 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1353 except Exception as e
:
1354 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1357 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1359 def _check_vids(self
, ifaceobj
, vids
):
1364 va
, vb
= v
.split('-')
1365 va
, vb
= int(va
), int(vb
)
1366 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1369 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1370 except exceptions
.ReservedVlanException
as e
:
1373 self
.logger
.warn('%s: unable to parse vid \'%s\''
1374 %(ifaceobj
.name
, v
))
1377 def _get_running_pvid(self
, ifacename
):
1380 running_vidinfo
= self
._get
_running
_vidinfo
()
1381 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1382 v
= vinfo
.get('vlan')
1383 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1388 def _get_running_vids_n_pvid_str(self
, ifacename
):
1392 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1395 ret_vids
= self
._compress
_into
_ranges
(vids
)
1400 ret_pvid
= '%s' %pvid
1403 return (ret_vids
, ret_pvid
)
1405 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1407 """ This method is a combination of methods _apply_bridge_vids and
1408 _apply_bridge_port_pvids above. A combined function is
1409 found necessary to do the deletes first and the adds later
1410 because kernel does honor vid info flags during deletes.
1413 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1414 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1415 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1416 bportifaceobj
.upperifaces
[0])
1419 vids_int
= self
._ranges
_to
_ints
(vids
)
1421 pvid_int
= int(pvid
) if pvid
else 0
1423 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1424 %(bportifaceobj
.name
, pvid
))
1429 vids_to_add
= vids_int
1431 pvid_to_add
= pvid_int
1434 if not self
._check
_vids
(bportifaceobj
, vids
):
1437 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1440 if not running_vids
and not running_pvid
:
1441 # There cannot be a no running pvid.
1442 # It might just not be in our cache:
1443 # this can happen if at the time we were
1444 # creating the bridge vlan cache, the port
1445 # was not part of the bridge. And we need
1446 # to make sure both vids and pvid is not in
1447 # the cache, to declare that our cache may
1453 (vids_to_del
, vids_to_add
) = \
1454 self
._diff
_vids
(vids_to_add
, running_vids
)
1457 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1458 pvid_to_del
= running_pvid
1460 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1461 (pvid_to_del
not in vids_to_add
)):
1462 # kernel deletes dont take into account
1463 # bridge vid flags and its possible that
1464 # the pvid deletes we do end up deleting
1465 # the vids. Be proactive and add the pvid
1466 # to the vid add list if it is in the vids
1467 # and not already part of vids_to_add.
1468 # This helps with a small corner case:
1472 # - new change is going to move the state to
1475 vids_to_add
.add(pvid_to_del
)
1476 except exceptions
.ReservedVlanException
as e
:
1478 except Exception, e
:
1479 self
.log_error('%s: failed to process vids/pvids'
1480 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1481 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1482 bportifaceobj
, raise_error
=False)
1485 if pvid_to_add
in vids_to_del
:
1486 vids_to_del
.remove(pvid_to_add
)
1487 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1488 self
._compress
_into
_ranges
(
1489 vids_to_del
), isbridge
)
1490 except Exception, e
:
1491 self
.log_warn('%s: failed to del vid `%s` (%s)'
1492 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1496 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1498 except Exception, e
:
1499 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1500 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1504 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1505 self
._compress
_into
_ranges
(
1506 vids_to_add
), isbridge
)
1507 except Exception, e
:
1508 self
.log_error('%s: failed to set vid `%s` (%s)'
1509 %(bportifaceobj
.name
, str(vids_to_add
),
1510 str(e
)), bportifaceobj
, raise_error
=False)
1513 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1514 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1516 except Exception, e
:
1517 self
.log_error('%s: failed to set pvid `%s` (%s)'
1518 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1521 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1528 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1530 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1532 allow_untagged
= 'yes'
1533 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1535 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1537 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1539 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1541 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1543 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1548 vids_final
= bridge_vids
1550 if allow_untagged
== 'yes':
1552 pvid_final
= pvids
[0]
1554 pvid_final
= bridge_pvid
1560 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1563 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1566 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1567 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1568 # Old style bridge port vid info
1569 # skip new style setting on ports
1571 self
.logger
.info('%s: applying bridge configuration '
1572 %ifaceobj
.name
+ 'specific to ports')
1574 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1576 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1580 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1582 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1586 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1587 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1588 port_processed_override
= True
1590 port_processed_override
= False
1592 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1594 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1596 self
.ipcmd
.batch_start()
1597 for bport
in bridgeports
:
1598 # Use the brctlcmd bulk set method: first build a dictionary
1600 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1601 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1602 ' for port %s (missing port)' %bport
)
1604 self
.logger
.info('%s: processing bridge config for port %s'
1605 %(ifaceobj
.name
, bport
))
1606 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1607 if not bportifaceobjlist
:
1609 for bportifaceobj
in bportifaceobjlist
:
1610 # Dont process bridge port if it already has been processed
1611 # and there is no override on port_processed
1612 if (not port_processed_override
and
1613 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1614 bridgeFlags
.PORT_PROCESSED
)):
1617 # Add attributes specific to the vlan aware bridge
1618 if bridge_vlan_aware
:
1619 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1620 bportifaceobj
, bridge_vids
, bridge_pvid
)
1621 elif self
.warn_on_untagged_bridge_absence
:
1622 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1623 except exceptions
.ReservedVlanException
as e
:
1625 except Exception, e
:
1627 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1629 self
.ipcmd
.bridge_batch_commit()
1631 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1633 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1634 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1635 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1636 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1637 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1638 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1639 self
.warn_on_untagged_bridge_absence
= False
1641 def bridge_port_get_bridge_name(self
, ifaceobj
):
1642 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1644 # bridge port is not enslaved to a bridge we need to find
1645 # the bridge in it's upper ifaces then enslave it
1646 for u
in ifaceobj
.upperifaces
:
1647 if self
.ipcmd
.is_bridge(u
):
1650 # return should_enslave port, bridgename
1651 return False, bridgename
1653 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1654 if should_enslave_port
:
1655 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1656 self
.handle_ipv6([ifaceobj
.name
], '1')
1658 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1659 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1661 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1662 except Exception as e
:
1663 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1666 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1667 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1670 # bridge doesn't exist
1673 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1674 if vlan_aware_bridge
:
1675 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1678 should_enslave_port
)
1680 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1682 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1683 ifaceobj
=bridge_ifaceobj
,
1684 ifaceobj_getfunc
=ifaceobj_getfunc
,
1685 bridge_vlan_aware
=vlan_aware_bridge
)
1687 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1689 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1690 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1691 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1694 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1699 def parse_interface_list_value(user_config
):
1701 for entry
in user_config
.split():
1702 ifname
, value
= entry
.split('=')
1703 config
[ifname
] = value
1706 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1707 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1709 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1711 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1713 Checks are not performed in this function and must be verified
1714 before. This is done this way to avoid calling this method on
1715 non vlan & bridge port interfaces thus wasting a bit less time
1721 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1722 # if the user explicitly defined vxlan-learning we need to honor his config
1723 # and not sync vxlan-learning with bridge-learning
1725 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1727 # if BRIDGE_LEARNING is in the desired configuration
1728 # and differs from the running vxlan configuration
1729 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1731 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1732 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1733 % (bridge_name
, brport_name
, brport_learning
))
1735 elif brport_learning
is None and bridge_vlan_aware
:
1736 # is bridge-learning is not configured but the bridge is vlan-aware
1738 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1739 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1741 if default_value
!= running_value
:
1742 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1744 if not brport_vxlan_learning_config
:
1746 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1747 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1748 % (bridge_name
, brport_name
, default_value
))
1750 # if kind and ifla_info_data are set they will be added to the
1751 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1752 return kind
, ifla_info_data
1754 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1756 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1757 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1758 'is not supported on a non-vxlan port'
1759 % (ifaceobj
.name
, brport_name
))
1761 elif (bridge_vlan_aware
and
1762 (not self
.arp_nd_suppress_only_on_vxlan
or
1763 (self
.arp_nd_suppress_only_on_vxlan
and
1764 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1765 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1768 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1769 ifname
= ifaceobj
.name
1772 brports_ifla_info_slave_data
= dict()
1773 brport_ifaceobj_dict
= dict()
1775 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1779 for brport_name
in target_ports
:
1780 if brport_name
not in running_brports
:
1781 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1783 new_targets
.append(brport_name
)
1784 running_brports
= new_targets
1786 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1788 # If target_ports is specified we want to configure only this
1789 # sub-list of port we need to check if these ports are already
1790 # enslaved, if not they will be ignored.
1791 # If target_ports is not populated we will apply the brport
1792 # attributes on all running brport.
1794 for port
in running_brports
:
1795 brport_list
= ifaceobj_getfunc(port
)
1797 brport_ifaceobj_dict
[port
] = brport_list
[0]
1798 brports_ifla_info_slave_data
[port
] = dict()
1800 bridge_ports_learning
= {}
1802 # we iterate through all IFLA_BRPORT supported attributes
1803 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1804 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1805 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1807 if not translate_func
:
1808 # if no translation function is found,
1809 # we ignore this attribute and continue
1813 # user didn't specify any value for this attribute
1814 # looking at policy overrides
1815 br_config
= policymanager
.policymanager_api
.get_iface_default(
1816 module_name
=self
.__class
__.__name
__,
1822 #if bridge_vlan_aware:
1823 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1824 # 'should be configured under the ports'
1825 # % (ifname, attr_name, br_config))
1827 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1828 # brport_name: { attr: value }
1830 # bridge-portprios swp1=5 swp2=32
1831 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1832 if '=' in br_config
:
1834 br_config
= self
.parse_interface_list_value(br_config
)
1836 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1839 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1840 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1841 brport_name
= brport_ifaceobj
.name
1843 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1844 # if the port has just been enslaved, info_slave_data is not cached yet
1845 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1849 if not brport_config
:
1850 # if a brport attribute was specified under the bridge and not under the port
1851 # we assign the bridge value to the port. If an attribute is both defined under
1852 # the bridge and the brport we keep the value of the port and ignore the br val.
1853 if type(br_config
) == dict:
1854 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1855 # br_config is a dictionary, example:
1856 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1857 brport_config
= br_config
.get(brport_name
)
1859 brport_config
= br_config
1861 if not brport_config
:
1862 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1863 module_name
=self
.__class
__.__name
__,
1868 user_config
= brport_config
1870 # attribute specific work
1871 # This shouldn't be here but we don't really have a choice otherwise this
1872 # will require too much code duplication and will make the code very complex
1873 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1875 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1881 user_config
= arp_suppress
1884 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1885 # special handking for group_fwd_mask because Cisco proprietary
1886 # protocol needs to be set via a private netlink attribute
1887 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1888 brports_ifla_info_slave_data
,
1889 user_config
, cached_value
)
1893 # if not bridge_vlan_aware:
1894 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1895 # 'should be configured under the bridge'
1896 # % (ifname, brport_name,
1897 # attr_name, brport_config))
1900 user_config_nl
= translate_func(user_config
)
1901 # check config value against running value
1902 if user_config_nl
!= cached_value
:
1903 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1904 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1905 self
.logger
.debug('(cache %s)' % cached_value
)
1907 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1908 # for vxlan-learning sync purposes we need to save the user config for each brports.
1909 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1910 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1911 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1912 # the brport since it might go out of sync for X and Y reasons.
1913 bridge_ports_learning
[brport_name
] = user_config_nl
1915 elif cached_value
is not None:
1916 # no config found, do we need to reset to default?
1917 default
= self
.get_attr_default_value(attr_name
)
1919 default_netlink
= translate_func(default
)
1921 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1922 and not ifupdownflags
.flags
.PERFMODE
1923 and brport_name
not in newly_enslaved_ports
):
1925 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1926 if default_netlink
!= cached_value
:
1927 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1928 % (ifname
, brport_name
))
1930 bridge_ports_learning
[brport_name
] = default_netlink
1931 except Exception as e
:
1932 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1934 if default_netlink
!= cached_value
:
1935 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1936 % (ifname
, brport_name
, attr_name
, default
))
1937 self
.logger
.debug('(cache %s)' % cached_value
)
1938 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1940 # applying bridge port configuration via netlink
1941 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1943 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1945 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1946 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1947 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1948 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1949 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1953 brport_ifla_info_slave_data
,
1954 bridge_ports_learning
.get(brport_name
))
1956 if self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
1957 self
.get_bridge_mcsnoop_value(ifaceobj
)
1959 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
1960 # is on and mcsnoop is on, set 'bridge-portmcrouter 2'
1961 # on vxlan ports (if not set by the user)
1962 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
):
1963 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
1964 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
1969 if brport_ifla_info_slave_data
or ifla_info_data
:
1971 netlink
.link_add_set(ifname
=brport_name
,
1973 ifla_info_data
=ifla_info_data
,
1974 slave_kind
='bridge',
1975 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1976 except Exception as e
:
1977 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1979 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1980 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1981 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1983 except Exception as e
:
1984 self
.log_error(str(e
), ifaceobj
)
1986 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1988 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1989 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1990 field we need to have special handling for that.
1992 ifla_brport_group_fwd_mask
= 0
1993 ifla_brport_group_fwd_maskhi
= 0
1995 for group
in re
.split(',|\s*', user_config
):
1999 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2001 if not callable(callback
):
2002 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2004 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2006 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2007 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2009 log_mask_change
= True
2010 # if user specify bridge-l2protocol-tunnel stp cdp
2011 # we need to set both MASK and MASKHI but we only want to log once
2013 if cached_ifla_brport_group_fwd_mask
is None:
2014 cached_ifla_brport_group_fwd_mask
= 0
2015 if cached_ifla_brport_group_fwd_maskhi
is None:
2016 cached_ifla_brport_group_fwd_maskhi
= 0
2018 # if the cache value is None it means that the kernel doesn't support this attribute
2019 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2021 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2023 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2024 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2025 log_mask_change
= False
2026 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2028 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2030 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2031 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2032 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2034 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2035 ifname
= ifaceobj
.name
2037 if ifupdownflags
.flags
.PERFMODE
:
2038 link_just_created
= True
2041 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2042 link_just_created
= not link_exists
2045 netlink
.link_add_bridge(ifname
)
2047 self
.logger
.info('%s: bridge already exists' % ifname
)
2049 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2051 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2054 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2055 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2056 newly_enslaved_ports
=newly_enslaved_ports
)
2057 except Exception as e
:
2058 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2062 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2063 if not running_ports
:
2065 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2066 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2067 ifaceobj_getfunc
=ifaceobj_getfunc
,
2068 bridge_vlan_aware
=bridge_vlan_aware
)
2069 except exceptions
.ReservedVlanException
as e
:
2071 except Exception as e
:
2072 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2074 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2075 for p
in running_ports
:
2076 ifaceobj_list
= ifaceobj_getfunc(p
)
2077 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2078 netlink
.link_set_updown(p
, "down")
2081 netlink
.link_set_updown(p
, "up")
2082 except Exception, e
:
2083 self
.logger
.debug('%s: %s: link set up (%s)'
2084 % (ifaceobj
.name
, p
, str(e
)))
2088 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2089 except Exception as e
:
2090 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2092 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2093 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2094 return self
.bridge_mac_iface
2096 if self
.bridge_mac_iface_list
:
2097 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2099 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2100 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2104 for obj
in ifaceobj_list
:
2105 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2106 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2107 if iface_user_configured_hwaddress
:
2108 iface_mac
= iface_user_configured_hwaddress
2110 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2114 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2115 # if hwaddress attribute is not configured we use the running mac addr
2117 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2118 return self
.bridge_mac_iface
2119 elif self
.bridge_set_static_mac_from_port
:
2120 # no policy was provided, we need to get the first physdev or bond ports
2121 # and use its hwaddress to set the bridge mac
2122 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2123 # iterate through the bridge-port list
2124 for port_obj
in ifaceobj_getfunc(port
) or []:
2125 # check if the port is a physdev (link_kind is null) or a bon
2126 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2127 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2128 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2129 if iface_user_configured_hwaddress
:
2130 iface_mac
= iface_user_configured_hwaddress
.lower()
2131 # we need to "normalize" the user provided MAC so it can match with
2132 # what we have in the cache (data retrieved via a netlink dump by
2133 # nlmanager). nlmanager return all macs in lower-case
2135 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2138 self
.bridge_mac_iface
= (port
, iface_mac
)
2139 return self
.bridge_mac_iface
2143 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2144 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2145 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2147 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2149 We have a day one bridge mac changing problem with changing ports
2150 (basically bridge mac changes when the port it inherited the mac from
2153 We have discussed this problem many times before and tabled it.
2154 The issue has aggravated with vxlan bridge ports having auto-generated
2155 random macs...which change on every reboot.
2157 ifupdown2 extract from policy files an iface to select a mac from and
2158 configure it automatically.
2160 if ifaceobj
.get_attr_value('hwaddress'):
2161 # if the user configured a static hwaddress
2162 # there is no need to assign one
2165 ifname
= ifaceobj
.name
2166 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2167 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2168 %(ifname
, mac_intf
, bridge_mac
))
2171 # if an interface is configured with the following attribute:
2172 # hwaddress 08:00:27:42:42:4
2173 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2174 # from the kernel. The only way to counter that is to convert all mac to int
2175 # and compare the ints, it will increase perfs and be safer.
2176 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2177 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2178 if cached_value
and cached_value
== bridge_mac
:
2179 # the bridge mac is already set to the bridge_mac_intf's mac
2182 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2184 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2185 except Exception as e
:
2186 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2187 # log info this error because the user didn't explicitly configured this
2189 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2191 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2192 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2193 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2195 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2196 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2199 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2201 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2202 if ifaceobj_config_attr
in bridge_attributes
:
2203 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2204 % (ifaceobj
.name
, ifaceobj_config_attr
))
2206 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2207 if not self
._is
_bridge
(ifaceobj
):
2209 ifname
= ifaceobj
.name
2210 if not self
.ipcmd
.link_exists(ifname
):
2213 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2215 self
.handle_ipv6(running_ports
, '0')
2216 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2217 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2218 except Exception as e
:
2219 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2221 netlink
.link_del(ifname
)
2222 except Exception as e
:
2223 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2224 self
.logger
.error(str(e
))
2225 # netlink exception already contains the ifname
2227 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2230 running_bridge_port_vids
= ''
2233 running_vids
= self
._get
_runing
_vids
(p
)
2235 running_bridge_port_vids
+= ' %s=%s' %(p
,
2236 ','.join(running_vids
))
2239 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2241 running_bridge_port_pvid
= ''
2244 running_pvid
= self
._get
_runing
_pvid
(p
)
2246 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2250 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2252 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2253 if running_bridge_vids
:
2254 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2255 return running_attrs
2257 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2261 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2262 # so query the ports
2263 running_bridgeport_vids
= []
2264 running_bridgeport_pvids
= []
2265 for bport
in bridgeports
:
2266 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2268 running_bridgeport_vids
.append(' '.join(vids
))
2270 running_bridgeport_pvids
.append(pvid
)
2273 if running_bridgeport_vids
:
2274 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2275 if freq
== len(bridgeports
):
2276 running_attrs
['bridge-vids'] = vidval
2277 bridge_vids
= vidval
.split()
2280 if running_bridgeport_pvids
:
2281 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2282 if freq
== len(bridgeports
) and vidval
!= '1':
2283 running_attrs
['bridge-pvid'] = vidval
2284 bridge_pvid
= vidval
.split()[0]
2286 # Go through all bridge ports and find their vids
2287 for bport
in bridgeports
:
2288 bportifaceobj
= ifaceobj_getfunc(bport
)
2289 if not bportifaceobj
:
2293 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2294 if vids
and vids
!= bridge_vids
:
2296 if pvid
and pvid
!= bridge_pvid
:
2298 if bport_vids
and bport_pvid
in bport_vids
:
2299 bport_vids
.remove(bport_pvid
)
2300 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2301 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2302 bportifaceobj
[0].delete_config('bridge-pvid')
2303 bportifaceobj
[0].delete_config('bridge-vids')
2305 if bport_pvid
and bport_pvid
!= '1':
2306 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2308 # delete any stale bridge-vids under ports
2309 bportifaceobj
[0].delete_config('bridge-pvid')
2311 bportifaceobj
[0].replace_config('bridge-vids',
2312 ' '.join(bport_vids
))
2314 # delete any stale bridge-vids under ports
2315 bportifaceobj
[0].delete_config('bridge-vids')
2316 return running_attrs
2318 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2319 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobjrunning
.name
)
2320 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2322 mcq
= ' '.join(mcqs
)
2325 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2326 bridge_vlan_aware
=False):
2330 skip_kernel_stp_attrs
= 0
2333 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2335 except Exception as e
:
2336 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2338 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2339 if not tmpbridgeattrdict
:
2340 self
.logger
.warn('%s: unable to get bridge attrs'
2341 %ifaceobjrunning
.name
)
2342 return bridgeattrdict
2344 # Fill bridge_ports and bridge stp attributes first
2345 ports
= tmpbridgeattrdict
.get('ports')
2347 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2348 stp
= tmpbridgeattrdict
.get('stp', 'no')
2349 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2350 bridgeattrdict
['bridge-stp'] = [stp
]
2352 if stp
== 'yes' and userspace_stp
:
2353 skip_kernel_stp_attrs
= 1
2355 vlan_stats
= utils
.get_onff_from_onezero(
2356 tmpbridgeattrdict
.get('vlan-stats', None))
2358 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2359 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2361 bool2str
= {'0': 'no', '1': 'yes'}
2362 # pick all other attributes
2363 for k
,v
in tmpbridgeattrdict
.items():
2366 if k
== 'ports' or k
== 'stp':
2369 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2370 # only include igmp attributes if kernel stp is off
2372 attrname
= 'bridge-' + k
2373 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2374 if v
!= mod_default
:
2375 # convert '0|1' running values to 'no|yes'
2376 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2378 bridgeattrdict
[attrname
] = [v
]
2380 if bridge_vlan_aware
:
2383 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2387 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2390 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2393 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2395 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2397 if skip_kernel_stp_attrs
:
2398 return bridgeattrdict
2400 # Do this only for vlan-UNAWARE-bridge
2401 if ports
and not bridge_vlan_aware
:
2402 portconfig
= {'bridge-pathcosts' : '',
2403 'bridge-portprios' : '',
2404 'bridge-learning' : '',
2405 'bridge-unicast-flood' : '',
2406 'bridge-multicast-flood' : '',
2407 'bridge-arp-nd-suppress' : '',
2409 for p
, v
in ports
.items():
2410 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2411 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2413 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2415 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2416 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2418 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2420 v
= utils
.get_onff_from_onezero(
2421 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2424 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2425 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2427 v
= utils
.get_onff_from_onezero(
2428 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2429 p
, 'unicast-flood'))
2431 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2433 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2435 v
= utils
.get_onff_from_onezero(
2436 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2437 p
, 'multicast-flood'))
2439 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2441 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2443 v
= utils
.get_onff_from_onezero(
2444 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2445 p
, 'arp-nd-suppress'))
2447 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2449 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2451 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2454 return bridgeattrdict
2456 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2457 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2458 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2460 mcqs
= attrval
.split()
2462 mcqsout
= ' '.join(mcqs
)
2463 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2464 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2466 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2468 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2470 running_bridge_port_vids
= ''
2471 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2473 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2474 %(ifaceobj
.name
, attrval
))
2479 (port
, val
) = p
.split('=')
2480 vids
= val
.split(',')
2481 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2483 if not self
._compare
_vids
(vids
, running_vids
):
2485 running_bridge_port_vids
+= ' %s=%s' %(port
,
2486 ','.join(running_vids
))
2488 running_bridge_port_vids
+= ' %s' %p
2491 except Exception, e
:
2492 self
.log_warn('%s: failure checking vid %s (%s)'
2493 %(ifaceobj
.name
, p
, str(e
)))
2495 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2496 running_bridge_port_vids
, 1)
2498 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2501 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2503 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2505 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2506 %(ifaceobj
.name
, attrval
))
2508 running_bridge_port_pvids
= ''
2512 (port
, pvid
) = p
.split('=')
2513 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2514 if running_pvid
and running_pvid
== pvid
:
2515 running_bridge_port_pvids
+= ' %s' %p
2518 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2520 except Exception, e
:
2521 self
.log_warn('%s: failure checking pvid %s (%s)'
2522 %(ifaceobj
.name
, pvid
, str(e
)))
2524 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2525 running_bridge_port_pvids
, 1)
2527 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2528 running_bridge_port_pvids
, 0)
2530 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2532 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2534 def _query_check_snooping_wdefault(self
, ifaceobj
):
2535 if (ifupdownflags
.flags
.WITHDEFAULTS
2536 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2537 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2538 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2540 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2541 ifaceobj_getfunc
=None):
2542 if not self
._is
_bridge
(ifaceobj
):
2544 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2545 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2548 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2550 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2551 self
.get_mod_attrs())
2552 #Add default attributes if --with-defaults is set
2553 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2554 ifaceattrs
.append('bridge-stp')
2558 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2559 if not runningattrs
:
2560 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2563 except Exception, e
:
2564 self
.logger
.warn(str(e
))
2567 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2569 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2570 'bridge-port-pvids']
2572 diff
= Set(ifaceattrs
).difference(filterattrs
)
2574 if 'bridge-l2protocol-tunnel' in diff
:
2575 diff
.remove('bridge-l2protocol-tunnel')
2576 # bridge-l2protocol-tunnel requires separate handling
2578 if 'bridge-ports' in diff
:
2579 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2580 diff
.remove('bridge-ports')
2583 # get the corresponding ifaceobj attr
2584 v
= ifaceobj
.get_attr_value_first(k
)
2586 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2587 v
= 'on' if self
.default_stp_on
else 'off'
2590 rv
= runningattrs
.get(k
[7:])
2591 if k
== 'bridge-mcqv4src':
2593 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2594 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2596 if k
== 'bridge-vlan-aware':
2597 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2598 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2599 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2602 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2604 elif k
== 'bridge-stp':
2605 # special case stp compare because it may
2606 # contain more than one valid values
2607 stp_on_vals
= ['on', 'yes']
2608 stp_off_vals
= ['off', 'no']
2609 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2610 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2611 ifaceobjcurr
.update_config_with_status('bridge-stp',
2614 ifaceobjcurr
.update_config_with_status('bridge-stp',
2616 elif k
in ['bridge-pathcosts',
2618 'bridge-portmcrouter',
2621 'bridge-unicast-flood',
2622 'bridge-multicast-flood',
2623 'bridge-arp-nd-suppress',
2625 if k
== 'bridge-arp-nd-suppress':
2626 brctlcmdattrname
= k
[7:]
2628 brctlcmdattrname
= k
[7:].rstrip('s')
2629 # for port attributes, the attributes are in a list
2630 # <portname>=<portattrvalue>
2633 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2636 for vlistitem
in vlist
:
2638 (p
, v
) = vlistitem
.split('=')
2639 if k
in ['bridge-learning',
2640 'bridge-unicast-flood',
2641 'bridge-multicast-flood',
2642 'bridge-arp-nd-suppress',
2644 currv
= utils
.get_onoff_bool(
2645 self
.brctlcmd
.get_bridgeport_attr(
2649 currv
= self
.brctlcmd
.get_bridgeport_attr(
2653 currstr
+= ' %s=%s' %(p
, currv
)
2655 currstr
+= ' %s=%s' %(p
, 'None')
2657 if k
== 'bridge-portmcrouter':
2658 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2662 except Exception, e
:
2663 self
.log_warn(str(e
))
2665 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2666 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2667 rv
= utils
.get_onff_from_onezero(rv
)
2669 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2671 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2673 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2674 # bridge-pvid and bridge-vids on a bridge does
2675 # not correspond directly to a running config
2676 # on the bridge. They correspond to default
2677 # values for the bridge ports. And they are
2678 # already checked against running config of the
2679 # bridge port and reported against a bridge port.
2680 # So, ignore these attributes under the bridge.
2681 # Use '2' for ignore today. XXX: '2' will be
2682 # mapped to a defined value in subsequent patches.
2683 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2685 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2687 elif v
.upper() != rv
.upper():
2688 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2690 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2692 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2694 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2695 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2697 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2698 bridge_all_ports
= []
2699 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2700 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2702 if not running_port_list
and not bridge_all_ports
:
2705 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2708 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2709 # we want to display the same bridge-ports list as provided
2710 # in the interfaces file but if this list contains regexes or
2711 # globs, for now, we won't try to change it.
2712 if 'regex' in port_list
or 'glob' in port_list
:
2713 port_list
= running_port_list
2716 for i
in range(0, len(port_list
)):
2717 if port_list
[i
] in running_port_list
:
2718 ordered
.append(port_list
[i
])
2721 port_list
= running_port_list
2722 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2724 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2725 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2727 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2730 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2731 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2733 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2734 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2735 for ifaceobj
in ifaceobjs
:
2736 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2737 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2740 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2741 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2743 for ifaceobj
in ifaceobjs
:
2744 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2749 def _get_bridge_name(self
, ifaceobj
):
2750 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2752 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2753 ifaceobj_getfunc
, bridgename
):
2754 attr_name
= 'bridge-access'
2755 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2757 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2759 if (not running_pvid
or running_pvid
!= vid
or
2760 (running_vids
and running_vids
[0] != vid
)):
2761 ifaceobjcurr
.update_config_with_status(attr_name
,
2764 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2767 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2769 attr_name
= 'bridge-pvid'
2770 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2772 if running_pvid
and running_pvid
== pvid
:
2773 ifaceobjcurr
.update_config_with_status(attr_name
,
2776 ifaceobjcurr
.update_config_with_status(attr_name
,
2778 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2779 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2780 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2781 # if the interface has multiple iface sections,
2782 # we check the below only for the oldest sibling
2783 # or the last iface section
2784 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2786 if not running_pvid
or running_pvid
!= pvid
:
2787 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2788 ifaceobjcurr
.status_str
= 'bridge pvid error'
2789 elif not running_pvid
or running_pvid
!= '1':
2790 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2791 ifaceobjcurr
.status_str
= 'bridge pvid error'
2793 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2795 vids
= re
.split(r
'[\s\t]\s*', vids
)
2796 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2798 ifaceobjcurr
.update_config_with_status(attr_name
,
2799 ' '.join(running_vids
), 1)
2801 ifaceobjcurr
.update_config_with_status(attr_name
,
2803 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2804 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2805 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2806 # if the interface has multiple iface sections,
2807 # we check the below only for the oldest sibling
2808 # or the last iface section
2810 # check if it matches the bridge vids
2811 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2812 if (bridge_vids
and (not running_vids
or
2813 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2814 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2815 ifaceobjcurr
.status_str
= 'bridge vid error'
2817 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2819 if not self
._is
_bridge
_port
(ifaceobj
):
2820 # Mark all bridge attributes as failed
2821 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2822 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2823 'bridge-pathcosts', 'bridge-portprios',
2824 'bridge-portmcrouter',
2826 'bridge-portmcfl', 'bridge-unicast-flood',
2827 'bridge-multicast-flood',
2828 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2831 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2833 self
.logger
.warn('%s: unable to determine bridge name'
2837 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2838 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2841 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2842 'bridge-portprios' : 'portprio',
2843 'bridge-portmcrouter' : 'portmcrouter',
2844 'bridge-portmcfl' : 'portmcfl',
2845 'bridge-learning' : 'learning',
2846 'bridge-unicast-flood' : 'unicast-flood',
2847 'bridge-multicast-flood' : 'multicast-flood',
2848 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2850 attrval
= ifaceobj
.get_attr_value_first(attr
)
2855 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2856 bridgename
, ifaceobj
.name
, dstattr
)
2858 if dstattr
== 'portmcfl':
2859 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2860 running_attrval
= utils
.get_yesno_boolean(
2861 utils
.get_boolean_from_string(running_attrval
))
2862 elif dstattr
== 'portmcrouter':
2863 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2864 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2866 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2868 elif dstattr
in ['learning',
2873 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2874 running_attrval
= utils
.get_onff_from_onezero(
2877 if running_attrval
!= attrval
:
2878 ifaceobjcurr
.update_config_with_status(attr
,
2881 ifaceobjcurr
.update_config_with_status(attr
,
2883 except Exception, e
:
2884 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2886 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2888 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2889 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2891 if user_config_l2protocol_tunnel
:
2894 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2895 except Exception as e
:
2896 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2898 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2900 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2902 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2903 We need to make sure that all ports comply with the mask given under the bridge
2905 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2907 if user_config_l2protocol_tunnel
:
2908 if '=' in user_config_l2protocol_tunnel
:
2910 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2911 brport_list
= config_per_port_dict
.keys()
2913 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2916 config_per_port_dict
= {}
2917 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2920 for brport_name
in brport_list
:
2921 self
._query
_check
_l2protocol
_tunnel
(
2923 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2926 except Exception as e
:
2927 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2929 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2931 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2932 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2933 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2935 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2936 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2938 if callable(callback
):
2939 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2940 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2941 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2943 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2944 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2945 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2946 running_protocols
= []
2947 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2948 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2949 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2950 running_protocols
.remove('all')
2952 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2953 running_protocols
.append(protocol_name
)
2954 if running_protocols
:
2956 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2957 elif bridge_ifaceobj
:
2958 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2961 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2963 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2965 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2966 if self
._is
_bridge
(ifaceobj
):
2967 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
2969 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2972 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2973 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2974 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2975 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2978 bridge_vlan_aware
=True))
2980 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2981 ifaceobjrunning
, None))
2983 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2984 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2987 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2988 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2989 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2991 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2992 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
2993 ifaceobjrunning
.update_config('bridge-portprios', v
)
2995 def _query_running_bridge_port(self
, ifaceobjrunning
,
2996 ifaceobj_getfunc
=None):
2998 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
2999 ifaceobjrunning
.name
)
3003 self
.logger
.warn('%s: unable to find bridgename'
3004 %ifaceobjrunning
.name
)
3007 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
3009 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
3010 except Exception as e
:
3011 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
3014 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
3016 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3017 ifaceobjrunning
.name
)
3018 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3019 bridge_port_vids
.remove(bridge_port_pvid
)
3021 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3022 if bridgeifaceobjlist
:
3023 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3024 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3026 if not bridge_port_vids
and bridge_port_pvid
:
3027 # must be an access port
3028 if bridge_port_pvid
!= '1':
3029 ifaceobjrunning
.update_config('bridge-access',
3032 if bridge_port_vids
:
3033 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3034 ifaceobjrunning
.update_config('bridge-vids',
3035 ' '.join(bridge_port_vids
))
3036 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3037 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3038 ifaceobjrunning
.update_config('bridge-pvid',
3041 v
= utils
.get_onff_from_onezero(
3042 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3043 ifaceobjrunning
.name
,
3045 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3046 ifaceobjrunning
.update_config('bridge-learning', v
)
3048 v
= utils
.get_onff_from_onezero(
3049 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3050 ifaceobjrunning
.name
,
3052 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3053 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3055 v
= utils
.get_onff_from_onezero(
3056 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3057 ifaceobjrunning
.name
,
3059 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3060 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3062 v
= utils
.get_onff_from_onezero(
3063 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3064 ifaceobjrunning
.name
,
3066 # Display running 'arp-nd-suppress' only on vxlan ports
3067 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3068 # otherwise, display on all bridge-ports
3070 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3072 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3073 (not self
.arp_nd_suppress_only_on_vxlan
or
3074 (self
.arp_nd_suppress_only_on_vxlan
and
3075 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3076 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3078 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3080 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3082 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3083 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3084 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3085 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3086 except Exception as e
:
3087 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3089 def _query(self
, ifaceobj
, **kwargs
):
3090 """ add default policy attributes supported by the module """
3091 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3092 ifaceobj
.get_attr_value_first('bridge-stp')):
3094 if self
.default_stp_on
:
3095 ifaceobj
.update_config('bridge-stp', 'yes')
3097 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3098 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3099 ['mcquerier', 'bridge-mcquerier'],
3100 ['mcsnoop', 'bridge-mcsnoop']]:
3101 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3102 if value
and not utils
.is_binary_bool(value
):
3103 if attrl
[0] in runningattrs
:
3104 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3105 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3107 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3108 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3109 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3110 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3111 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3112 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3114 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3116 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3118 if 'mcrouter' in running_attrs
:
3119 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3124 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3126 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3128 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3132 (port
, val
) = p
.split('=')
3133 if not utils
.is_binary_bool(val
):
3134 to_convert
.append(port
)
3135 for port
in to_convert
:
3136 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3137 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3142 'query-checkcurr': _query_check
,
3143 'query-running': _query_running
,
3148 """ returns list of ops supported by this module """
3149 return self
._run
_ops
.keys()
3151 def _init_command_handlers(self
):
3153 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3155 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3156 """ run bridge configuration on the interface object passed as
3157 argument. Can create bridge interfaces if they dont exist already
3160 **ifaceobj** (object): iface object
3162 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3166 **query_ifaceobj** (object): query check ifaceobject. This is only
3167 valid when op is 'query-checkcurr'. It is an object same as
3168 ifaceobj, but contains running attribute values and its config
3169 status. The modules can use it to return queried running state
3170 of interfaces. status is success if the running state is same
3171 as user required state in ifaceobj. error otherwise.
3173 op_handler
= self
._run
_ops
.get(operation
)
3176 self
._init
_command
_handlers
()
3178 if (not LinkUtils
.bridge_utils_is_installed
3179 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3180 and LinkUtils
.bridge_utils_missing_warning
):
3181 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3182 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3183 LinkUtils
.bridge_utils_missing_warning
= False
3185 if operation
== 'query-checkcurr':
3186 op_handler(self
, ifaceobj
, query_ifaceobj
,
3187 ifaceobj_getfunc
=ifaceobj_getfunc
)
3189 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)