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 cached_bridge_mcsnoop
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', Link
.IFLA_BR_MCAST_SNOOPING
])
1958 if (self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
1959 self
.get_bridge_mcsnoop_value(ifaceobj
)
1960 )) or cached_bridge_mcsnoop
:
1961 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
1962 # is on and mcsnoop is on (or mcsnoop is already enabled on the
1963 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
1964 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
):
1965 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
1966 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
1971 if brport_ifla_info_slave_data
or ifla_info_data
:
1973 netlink
.link_add_set(ifname
=brport_name
,
1975 ifla_info_data
=ifla_info_data
,
1976 slave_kind
='bridge',
1977 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1978 except Exception as e
:
1979 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1981 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1982 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1983 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1985 except Exception as e
:
1986 self
.log_error(str(e
), ifaceobj
)
1988 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1990 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1991 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1992 field we need to have special handling for that.
1994 ifla_brport_group_fwd_mask
= 0
1995 ifla_brport_group_fwd_maskhi
= 0
1997 for group
in re
.split(',|\s*', user_config
):
2001 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2003 if not callable(callback
):
2004 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2006 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2008 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2009 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2011 log_mask_change
= True
2012 # if user specify bridge-l2protocol-tunnel stp cdp
2013 # we need to set both MASK and MASKHI but we only want to log once
2015 if cached_ifla_brport_group_fwd_mask
is None:
2016 cached_ifla_brport_group_fwd_mask
= 0
2017 if cached_ifla_brport_group_fwd_maskhi
is None:
2018 cached_ifla_brport_group_fwd_maskhi
= 0
2020 # if the cache value is None it means that the kernel doesn't support this attribute
2021 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2023 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2025 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2026 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2027 log_mask_change
= False
2028 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2030 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2032 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2033 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2034 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2036 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2037 ifname
= ifaceobj
.name
2039 if ifupdownflags
.flags
.PERFMODE
:
2040 link_just_created
= True
2043 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2044 link_just_created
= not link_exists
2047 netlink
.link_add_bridge(ifname
)
2049 self
.logger
.info('%s: bridge already exists' % ifname
)
2051 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2053 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2056 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2057 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2058 newly_enslaved_ports
=newly_enslaved_ports
)
2059 except Exception as e
:
2060 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2064 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2065 if not running_ports
:
2067 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2068 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2069 ifaceobj_getfunc
=ifaceobj_getfunc
,
2070 bridge_vlan_aware
=bridge_vlan_aware
)
2071 except exceptions
.ReservedVlanException
as e
:
2073 except Exception as e
:
2074 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2076 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2077 for p
in running_ports
:
2078 ifaceobj_list
= ifaceobj_getfunc(p
)
2079 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2080 netlink
.link_set_updown(p
, "down")
2083 netlink
.link_set_updown(p
, "up")
2084 except Exception, e
:
2085 self
.logger
.debug('%s: %s: link set up (%s)'
2086 % (ifaceobj
.name
, p
, str(e
)))
2090 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2091 except Exception as e
:
2092 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2094 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2095 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2096 return self
.bridge_mac_iface
2098 if self
.bridge_mac_iface_list
:
2099 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2101 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2102 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2106 for obj
in ifaceobj_list
:
2107 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2108 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2109 if iface_user_configured_hwaddress
:
2110 iface_mac
= iface_user_configured_hwaddress
2112 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2116 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2117 # if hwaddress attribute is not configured we use the running mac addr
2119 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2120 return self
.bridge_mac_iface
2121 elif self
.bridge_set_static_mac_from_port
:
2122 # no policy was provided, we need to get the first physdev or bond ports
2123 # and use its hwaddress to set the bridge mac
2124 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2125 # iterate through the bridge-port list
2126 for port_obj
in ifaceobj_getfunc(port
) or []:
2127 # check if the port is a physdev (link_kind is null) or a bon
2128 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2129 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2130 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2131 if iface_user_configured_hwaddress
:
2132 iface_mac
= iface_user_configured_hwaddress
.lower()
2133 # we need to "normalize" the user provided MAC so it can match with
2134 # what we have in the cache (data retrieved via a netlink dump by
2135 # nlmanager). nlmanager return all macs in lower-case
2137 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2140 self
.bridge_mac_iface
= (port
, iface_mac
)
2141 return self
.bridge_mac_iface
2145 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2146 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2147 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2149 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2151 We have a day one bridge mac changing problem with changing ports
2152 (basically bridge mac changes when the port it inherited the mac from
2155 We have discussed this problem many times before and tabled it.
2156 The issue has aggravated with vxlan bridge ports having auto-generated
2157 random macs...which change on every reboot.
2159 ifupdown2 extract from policy files an iface to select a mac from and
2160 configure it automatically.
2162 if ifaceobj
.get_attr_value('hwaddress'):
2163 # if the user configured a static hwaddress
2164 # there is no need to assign one
2167 ifname
= ifaceobj
.name
2168 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2169 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2170 %(ifname
, mac_intf
, bridge_mac
))
2173 # if an interface is configured with the following attribute:
2174 # hwaddress 08:00:27:42:42:4
2175 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2176 # from the kernel. The only way to counter that is to convert all mac to int
2177 # and compare the ints, it will increase perfs and be safer.
2178 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2179 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2180 if cached_value
and cached_value
== bridge_mac
:
2181 # the bridge mac is already set to the bridge_mac_intf's mac
2184 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2186 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2187 except Exception as e
:
2188 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2189 # log info this error because the user didn't explicitly configured this
2191 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2193 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2194 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2195 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2197 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2198 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2201 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2203 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2204 if ifaceobj_config_attr
in bridge_attributes
:
2205 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2206 % (ifaceobj
.name
, ifaceobj_config_attr
))
2208 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2209 if not self
._is
_bridge
(ifaceobj
):
2211 ifname
= ifaceobj
.name
2212 if not self
.ipcmd
.link_exists(ifname
):
2215 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2217 self
.handle_ipv6(running_ports
, '0')
2218 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2219 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2220 except Exception as e
:
2221 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2223 netlink
.link_del(ifname
)
2224 except Exception as e
:
2225 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2226 self
.logger
.error(str(e
))
2227 # netlink exception already contains the ifname
2229 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2232 running_bridge_port_vids
= ''
2235 running_vids
= self
._get
_runing
_vids
(p
)
2237 running_bridge_port_vids
+= ' %s=%s' %(p
,
2238 ','.join(running_vids
))
2241 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2243 running_bridge_port_pvid
= ''
2246 running_pvid
= self
._get
_runing
_pvid
(p
)
2248 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2252 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2254 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2255 if running_bridge_vids
:
2256 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2257 return running_attrs
2259 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2263 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2264 # so query the ports
2265 running_bridgeport_vids
= []
2266 running_bridgeport_pvids
= []
2267 for bport
in bridgeports
:
2268 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2270 running_bridgeport_vids
.append(' '.join(vids
))
2272 running_bridgeport_pvids
.append(pvid
)
2275 if running_bridgeport_vids
:
2276 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2277 if freq
== len(bridgeports
):
2278 running_attrs
['bridge-vids'] = vidval
2279 bridge_vids
= vidval
.split()
2282 if running_bridgeport_pvids
:
2283 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2284 if freq
== len(bridgeports
) and vidval
!= '1':
2285 running_attrs
['bridge-pvid'] = vidval
2286 bridge_pvid
= vidval
.split()[0]
2288 # Go through all bridge ports and find their vids
2289 for bport
in bridgeports
:
2290 bportifaceobj
= ifaceobj_getfunc(bport
)
2291 if not bportifaceobj
:
2295 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2296 if vids
and vids
!= bridge_vids
:
2298 if pvid
and pvid
!= bridge_pvid
:
2300 if bport_vids
and bport_pvid
in bport_vids
:
2301 bport_vids
.remove(bport_pvid
)
2302 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2303 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2304 bportifaceobj
[0].delete_config('bridge-pvid')
2305 bportifaceobj
[0].delete_config('bridge-vids')
2307 if bport_pvid
and bport_pvid
!= '1':
2308 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2310 # delete any stale bridge-vids under ports
2311 bportifaceobj
[0].delete_config('bridge-pvid')
2313 bportifaceobj
[0].replace_config('bridge-vids',
2314 ' '.join(bport_vids
))
2316 # delete any stale bridge-vids under ports
2317 bportifaceobj
[0].delete_config('bridge-vids')
2318 return running_attrs
2320 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2321 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobjrunning
.name
)
2322 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2324 mcq
= ' '.join(mcqs
)
2327 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2328 bridge_vlan_aware
=False):
2332 skip_kernel_stp_attrs
= 0
2335 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2337 except Exception as e
:
2338 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2340 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2341 if not tmpbridgeattrdict
:
2342 self
.logger
.warn('%s: unable to get bridge attrs'
2343 %ifaceobjrunning
.name
)
2344 return bridgeattrdict
2346 # Fill bridge_ports and bridge stp attributes first
2347 ports
= tmpbridgeattrdict
.get('ports')
2349 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2350 stp
= tmpbridgeattrdict
.get('stp', 'no')
2351 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2352 bridgeattrdict
['bridge-stp'] = [stp
]
2354 if stp
== 'yes' and userspace_stp
:
2355 skip_kernel_stp_attrs
= 1
2357 vlan_stats
= utils
.get_onff_from_onezero(
2358 tmpbridgeattrdict
.get('vlan-stats', None))
2360 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2361 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2363 bool2str
= {'0': 'no', '1': 'yes'}
2364 # pick all other attributes
2365 for k
,v
in tmpbridgeattrdict
.items():
2368 if k
== 'ports' or k
== 'stp':
2371 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2372 # only include igmp attributes if kernel stp is off
2374 attrname
= 'bridge-' + k
2375 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2376 if v
!= mod_default
:
2377 # convert '0|1' running values to 'no|yes'
2378 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2380 bridgeattrdict
[attrname
] = [v
]
2382 if bridge_vlan_aware
:
2385 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2389 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2392 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2395 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2397 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2399 if skip_kernel_stp_attrs
:
2400 return bridgeattrdict
2402 # Do this only for vlan-UNAWARE-bridge
2403 if ports
and not bridge_vlan_aware
:
2404 portconfig
= {'bridge-pathcosts' : '',
2405 'bridge-portprios' : '',
2406 'bridge-learning' : '',
2407 'bridge-unicast-flood' : '',
2408 'bridge-multicast-flood' : '',
2409 'bridge-arp-nd-suppress' : '',
2411 for p
, v
in ports
.items():
2412 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2413 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2415 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2417 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2418 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2420 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2422 v
= utils
.get_onff_from_onezero(
2423 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2426 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2427 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2429 v
= utils
.get_onff_from_onezero(
2430 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2431 p
, 'unicast-flood'))
2433 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2435 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2437 v
= utils
.get_onff_from_onezero(
2438 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2439 p
, 'multicast-flood'))
2441 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2443 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2445 v
= utils
.get_onff_from_onezero(
2446 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2447 p
, 'arp-nd-suppress'))
2449 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2451 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2453 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2456 return bridgeattrdict
2458 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2459 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2460 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2462 mcqs
= attrval
.split()
2464 mcqsout
= ' '.join(mcqs
)
2465 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2466 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2468 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2470 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2472 running_bridge_port_vids
= ''
2473 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2475 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2476 %(ifaceobj
.name
, attrval
))
2481 (port
, val
) = p
.split('=')
2482 vids
= val
.split(',')
2483 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2485 if not self
._compare
_vids
(vids
, running_vids
):
2487 running_bridge_port_vids
+= ' %s=%s' %(port
,
2488 ','.join(running_vids
))
2490 running_bridge_port_vids
+= ' %s' %p
2493 except Exception, e
:
2494 self
.log_warn('%s: failure checking vid %s (%s)'
2495 %(ifaceobj
.name
, p
, str(e
)))
2497 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2498 running_bridge_port_vids
, 1)
2500 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2503 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2505 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2507 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2508 %(ifaceobj
.name
, attrval
))
2510 running_bridge_port_pvids
= ''
2514 (port
, pvid
) = p
.split('=')
2515 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2516 if running_pvid
and running_pvid
== pvid
:
2517 running_bridge_port_pvids
+= ' %s' %p
2520 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2522 except Exception, e
:
2523 self
.log_warn('%s: failure checking pvid %s (%s)'
2524 %(ifaceobj
.name
, pvid
, str(e
)))
2526 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2527 running_bridge_port_pvids
, 1)
2529 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2530 running_bridge_port_pvids
, 0)
2532 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2534 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2536 def _query_check_snooping_wdefault(self
, ifaceobj
):
2537 if (ifupdownflags
.flags
.WITHDEFAULTS
2538 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2539 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2540 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2542 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2543 ifaceobj_getfunc
=None):
2544 if not self
._is
_bridge
(ifaceobj
):
2546 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2547 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2550 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2552 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2553 self
.get_mod_attrs())
2554 #Add default attributes if --with-defaults is set
2555 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2556 ifaceattrs
.append('bridge-stp')
2560 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2561 if not runningattrs
:
2562 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2565 except Exception, e
:
2566 self
.logger
.warn(str(e
))
2569 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2571 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2572 'bridge-port-pvids']
2574 diff
= Set(ifaceattrs
).difference(filterattrs
)
2576 if 'bridge-l2protocol-tunnel' in diff
:
2577 diff
.remove('bridge-l2protocol-tunnel')
2578 # bridge-l2protocol-tunnel requires separate handling
2580 if 'bridge-ports' in diff
:
2581 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2582 diff
.remove('bridge-ports')
2585 # get the corresponding ifaceobj attr
2586 v
= ifaceobj
.get_attr_value_first(k
)
2588 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2589 v
= 'on' if self
.default_stp_on
else 'off'
2592 rv
= runningattrs
.get(k
[7:])
2593 if k
== 'bridge-mcqv4src':
2595 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2596 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2598 if k
== 'bridge-vlan-aware':
2599 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2600 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2601 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2604 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2606 elif k
== 'bridge-stp':
2607 # special case stp compare because it may
2608 # contain more than one valid values
2609 stp_on_vals
= ['on', 'yes']
2610 stp_off_vals
= ['off', 'no']
2611 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2612 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2613 ifaceobjcurr
.update_config_with_status('bridge-stp',
2616 ifaceobjcurr
.update_config_with_status('bridge-stp',
2618 elif k
in ['bridge-pathcosts',
2620 'bridge-portmcrouter',
2623 'bridge-unicast-flood',
2624 'bridge-multicast-flood',
2625 'bridge-arp-nd-suppress',
2627 if k
== 'bridge-arp-nd-suppress':
2628 brctlcmdattrname
= k
[7:]
2630 brctlcmdattrname
= k
[7:].rstrip('s')
2631 # for port attributes, the attributes are in a list
2632 # <portname>=<portattrvalue>
2635 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2638 for vlistitem
in vlist
:
2640 (p
, v
) = vlistitem
.split('=')
2641 if k
in ['bridge-learning',
2642 'bridge-unicast-flood',
2643 'bridge-multicast-flood',
2644 'bridge-arp-nd-suppress',
2646 currv
= utils
.get_onoff_bool(
2647 self
.brctlcmd
.get_bridgeport_attr(
2651 currv
= self
.brctlcmd
.get_bridgeport_attr(
2655 currstr
+= ' %s=%s' %(p
, currv
)
2657 currstr
+= ' %s=%s' %(p
, 'None')
2659 if k
== 'bridge-portmcrouter':
2660 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2664 except Exception, e
:
2665 self
.log_warn(str(e
))
2667 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2668 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2669 rv
= utils
.get_onff_from_onezero(rv
)
2671 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2673 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2675 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2676 # bridge-pvid and bridge-vids on a bridge does
2677 # not correspond directly to a running config
2678 # on the bridge. They correspond to default
2679 # values for the bridge ports. And they are
2680 # already checked against running config of the
2681 # bridge port and reported against a bridge port.
2682 # So, ignore these attributes under the bridge.
2683 # Use '2' for ignore today. XXX: '2' will be
2684 # mapped to a defined value in subsequent patches.
2685 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2687 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2689 elif v
.upper() != rv
.upper():
2690 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2692 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2694 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2696 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2697 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2699 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2700 bridge_all_ports
= []
2701 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2702 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2704 if not running_port_list
and not bridge_all_ports
:
2707 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2710 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2711 # we want to display the same bridge-ports list as provided
2712 # in the interfaces file but if this list contains regexes or
2713 # globs, for now, we won't try to change it.
2714 if 'regex' in port_list
or 'glob' in port_list
:
2715 port_list
= running_port_list
2718 for i
in range(0, len(port_list
)):
2719 if port_list
[i
] in running_port_list
:
2720 ordered
.append(port_list
[i
])
2723 port_list
= running_port_list
2724 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2726 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2727 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2729 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2732 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2733 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2735 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2736 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2737 for ifaceobj
in ifaceobjs
:
2738 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2739 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2742 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2743 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2745 for ifaceobj
in ifaceobjs
:
2746 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2751 def _get_bridge_name(self
, ifaceobj
):
2752 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2754 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2755 ifaceobj_getfunc
, bridgename
):
2756 attr_name
= 'bridge-access'
2757 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2759 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2761 if (not running_pvid
or running_pvid
!= vid
or
2762 (running_vids
and running_vids
[0] != vid
)):
2763 ifaceobjcurr
.update_config_with_status(attr_name
,
2766 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2769 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2771 attr_name
= 'bridge-pvid'
2772 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2774 if running_pvid
and running_pvid
== pvid
:
2775 ifaceobjcurr
.update_config_with_status(attr_name
,
2778 ifaceobjcurr
.update_config_with_status(attr_name
,
2780 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2781 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2782 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2783 # if the interface has multiple iface sections,
2784 # we check the below only for the oldest sibling
2785 # or the last iface section
2786 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2788 if not running_pvid
or running_pvid
!= pvid
:
2789 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2790 ifaceobjcurr
.status_str
= 'bridge pvid error'
2791 elif not running_pvid
or running_pvid
!= '1':
2792 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2793 ifaceobjcurr
.status_str
= 'bridge pvid error'
2795 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2797 vids
= re
.split(r
'[\s\t]\s*', vids
)
2798 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2800 ifaceobjcurr
.update_config_with_status(attr_name
,
2801 ' '.join(running_vids
), 1)
2803 ifaceobjcurr
.update_config_with_status(attr_name
,
2805 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2806 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2807 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2808 # if the interface has multiple iface sections,
2809 # we check the below only for the oldest sibling
2810 # or the last iface section
2812 # check if it matches the bridge vids
2813 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2814 if (bridge_vids
and (not running_vids
or
2815 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2816 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2817 ifaceobjcurr
.status_str
= 'bridge vid error'
2819 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2821 if not self
._is
_bridge
_port
(ifaceobj
):
2822 # Mark all bridge attributes as failed
2823 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2824 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2825 'bridge-pathcosts', 'bridge-portprios',
2826 'bridge-portmcrouter',
2828 'bridge-portmcfl', 'bridge-unicast-flood',
2829 'bridge-multicast-flood',
2830 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2833 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2835 self
.logger
.warn('%s: unable to determine bridge name'
2839 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2840 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2843 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2844 'bridge-portprios' : 'portprio',
2845 'bridge-portmcrouter' : 'portmcrouter',
2846 'bridge-portmcfl' : 'portmcfl',
2847 'bridge-learning' : 'learning',
2848 'bridge-unicast-flood' : 'unicast-flood',
2849 'bridge-multicast-flood' : 'multicast-flood',
2850 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2852 attrval
= ifaceobj
.get_attr_value_first(attr
)
2857 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2858 bridgename
, ifaceobj
.name
, dstattr
)
2860 if dstattr
== 'portmcfl':
2861 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2862 running_attrval
= utils
.get_yesno_boolean(
2863 utils
.get_boolean_from_string(running_attrval
))
2864 elif dstattr
== 'portmcrouter':
2865 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2866 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2868 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2870 elif dstattr
in ['learning',
2875 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2876 running_attrval
= utils
.get_onff_from_onezero(
2879 if running_attrval
!= attrval
:
2880 ifaceobjcurr
.update_config_with_status(attr
,
2883 ifaceobjcurr
.update_config_with_status(attr
,
2885 except Exception, e
:
2886 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2888 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2890 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2891 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2893 if user_config_l2protocol_tunnel
:
2896 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2897 except Exception as e
:
2898 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2900 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2902 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2904 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2905 We need to make sure that all ports comply with the mask given under the bridge
2907 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2909 if user_config_l2protocol_tunnel
:
2910 if '=' in user_config_l2protocol_tunnel
:
2912 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2913 brport_list
= config_per_port_dict
.keys()
2915 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2918 config_per_port_dict
= {}
2919 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2922 for brport_name
in brport_list
:
2923 self
._query
_check
_l2protocol
_tunnel
(
2925 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2928 except Exception as e
:
2929 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2931 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2933 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2934 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2935 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2937 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2938 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2940 if callable(callback
):
2941 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2942 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2943 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2945 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2946 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2947 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2948 running_protocols
= []
2949 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2950 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2951 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2952 running_protocols
.remove('all')
2954 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2955 running_protocols
.append(protocol_name
)
2956 if running_protocols
:
2958 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2959 elif bridge_ifaceobj
:
2960 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2963 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2965 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2967 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2968 if self
._is
_bridge
(ifaceobj
):
2969 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
2971 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2974 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2975 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2976 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2977 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2980 bridge_vlan_aware
=True))
2982 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2983 ifaceobjrunning
, None))
2985 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2986 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2989 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2990 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2991 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2993 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2994 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
2995 ifaceobjrunning
.update_config('bridge-portprios', v
)
2997 def _query_running_bridge_port(self
, ifaceobjrunning
,
2998 ifaceobj_getfunc
=None):
3000 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
3001 ifaceobjrunning
.name
)
3005 self
.logger
.warn('%s: unable to find bridgename'
3006 %ifaceobjrunning
.name
)
3009 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
3011 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
3012 except Exception as e
:
3013 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
3016 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
3018 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3019 ifaceobjrunning
.name
)
3020 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3021 bridge_port_vids
.remove(bridge_port_pvid
)
3023 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3024 if bridgeifaceobjlist
:
3025 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3026 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3028 if not bridge_port_vids
and bridge_port_pvid
:
3029 # must be an access port
3030 if bridge_port_pvid
!= '1':
3031 ifaceobjrunning
.update_config('bridge-access',
3034 if bridge_port_vids
:
3035 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3036 ifaceobjrunning
.update_config('bridge-vids',
3037 ' '.join(bridge_port_vids
))
3038 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3039 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3040 ifaceobjrunning
.update_config('bridge-pvid',
3043 v
= utils
.get_onff_from_onezero(
3044 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3045 ifaceobjrunning
.name
,
3047 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3048 ifaceobjrunning
.update_config('bridge-learning', v
)
3050 v
= utils
.get_onff_from_onezero(
3051 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3052 ifaceobjrunning
.name
,
3054 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3055 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3057 v
= utils
.get_onff_from_onezero(
3058 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3059 ifaceobjrunning
.name
,
3061 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3062 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3064 v
= utils
.get_onff_from_onezero(
3065 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3066 ifaceobjrunning
.name
,
3068 # Display running 'arp-nd-suppress' only on vxlan ports
3069 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3070 # otherwise, display on all bridge-ports
3072 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3074 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3075 (not self
.arp_nd_suppress_only_on_vxlan
or
3076 (self
.arp_nd_suppress_only_on_vxlan
and
3077 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3078 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3080 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3082 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3084 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3085 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3086 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3087 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3088 except Exception as e
:
3089 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3091 def _query(self
, ifaceobj
, **kwargs
):
3092 """ add default policy attributes supported by the module """
3093 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3094 ifaceobj
.get_attr_value_first('bridge-stp')):
3096 if self
.default_stp_on
:
3097 ifaceobj
.update_config('bridge-stp', 'yes')
3099 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3100 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3101 ['mcquerier', 'bridge-mcquerier'],
3102 ['mcsnoop', 'bridge-mcsnoop']]:
3103 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3104 if value
and not utils
.is_binary_bool(value
):
3105 if attrl
[0] in runningattrs
:
3106 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3107 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3109 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3110 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3111 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3112 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3113 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3114 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3116 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3118 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3120 if 'mcrouter' in running_attrs
:
3121 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3126 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3128 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3130 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3134 (port
, val
) = p
.split('=')
3135 if not utils
.is_binary_bool(val
):
3136 to_convert
.append(port
)
3137 for port
in to_convert
:
3138 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3139 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3144 'query-checkcurr': _query_check
,
3145 'query-running': _query_running
,
3150 """ returns list of ops supported by this module """
3151 return self
._run
_ops
.keys()
3153 def _init_command_handlers(self
):
3155 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3157 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3158 """ run bridge configuration on the interface object passed as
3159 argument. Can create bridge interfaces if they dont exist already
3162 **ifaceobj** (object): iface object
3164 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3168 **query_ifaceobj** (object): query check ifaceobject. This is only
3169 valid when op is 'query-checkcurr'. It is an object same as
3170 ifaceobj, but contains running attribute values and its config
3171 status. The modules can use it to return queried running state
3172 of interfaces. status is success if the running state is same
3173 as user required state in ifaceobj. error otherwise.
3175 op_handler
= self
._run
_ops
.get(operation
)
3178 self
._init
_command
_handlers
()
3180 if (not LinkUtils
.bridge_utils_is_installed
3181 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3182 and LinkUtils
.bridge_utils_missing_warning
):
3183 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3184 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3185 LinkUtils
.bridge_utils_missing_warning
= False
3187 if operation
== 'query-checkcurr':
3188 op_handler(self
, ifaceobj
, query_ifaceobj
,
3189 ifaceobj_getfunc
=ifaceobj_getfunc
)
3191 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)