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')
1237 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1238 if self
._vxlan
_bridge
_default
_igmp
_snooping
is not None:
1239 return self
._vxlan
_bridge
_default
_igmp
_snooping
1241 return self
.get_attr_default_value("bridge-mcsnoop")
1243 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1251 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1253 if not callable(translate_func
):
1257 user_config
= policymanager
.policymanager_api
.get_iface_default(
1258 module_name
=self
.__class
__.__name
__,
1263 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1264 if old_cache_key
and not link_just_created
:
1265 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1266 if not cached_value
or cached_value
== "None":
1267 # the link already exists but we don't have any value
1268 # cached for this attr, it probably means that the
1269 # capability is not available on this system (i.e old kernel)
1270 self
.logger
.debug('%s: ignoring %s %s: capability '
1271 'probably not supported on this system'
1272 % (ifname
, attr_name
, user_config
))
1274 # we need to convert the cache value to "netlink" format
1275 cached_value
= translate_func(cached_value
.lower())
1279 if not user_config
and not link_just_created
and cached_value
is not None:
1280 # there is no user configuration for this attribute
1281 # if the bridge existed before we need to check if
1282 # this attribute needs to be reset to default value
1283 default_value
= self
.get_attr_default_value(attr_name
)
1286 # the attribute has a default value, we need to convert it to
1287 # netlink format to compare it with the cache value
1288 default_value_nl
= translate_func(default_value
) # default_value.lower()
1290 if default_value_nl
!= cached_value
:
1291 # the running value difers from the default value
1292 # but the user didn't specify any config
1293 # resetting attribute to default
1294 ifla_info_data
[nl_attr
] = default_value_nl
1295 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1297 user_config_nl
= translate_func(user_config
) # user_config.lower()
1299 if user_config_nl
!= cached_value
:
1300 ifla_info_data
[nl_attr
] = user_config_nl
1302 if cached_value
is not None:
1303 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1305 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1306 except Exception as e
:
1307 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1309 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1310 ifla_info_data
= dict()
1311 ifname
= ifaceobj
.name
1313 self
.logger
.info('%s: apply bridge settings' % ifname
)
1315 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1316 self
.fill_ifla_info_data_with_ifla_br_attribute(
1317 ifla_info_data
=ifla_info_data
,
1318 link_just_created
=link_just_created
,
1321 attr_name
=attr_name
,
1322 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1326 self
.fill_ifla_info_data_with_ifla_br_attribute(
1327 ifla_info_data
=ifla_info_data
,
1328 link_just_created
=link_just_created
,
1330 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1331 attr_name
='bridge-mcsnoop',
1332 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1336 if bridge_vlan_aware
:
1337 self
.fill_ifla_info_data_with_ifla_br_attribute(
1338 ifla_info_data
=ifla_info_data
,
1339 link_just_created
=link_just_created
,
1341 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1342 attr_name
='bridge-vlan-stats',
1343 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1347 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1348 if not self
._is
_running
_stp
_state
_on
(ifname
):
1349 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1350 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1351 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1352 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1353 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1355 # If stp not specified and running stp state on, set it to off
1356 if self
._is
_running
_stp
_state
_on
(ifname
):
1357 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1358 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1359 except Exception as e
:
1360 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1363 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1365 def _check_vids(self
, ifaceobj
, vids
):
1370 va
, vb
= v
.split('-')
1371 va
, vb
= int(va
), int(vb
)
1372 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1375 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1376 except exceptions
.ReservedVlanException
as e
:
1379 self
.logger
.warn('%s: unable to parse vid \'%s\''
1380 %(ifaceobj
.name
, v
))
1383 def _get_running_pvid(self
, ifacename
):
1386 running_vidinfo
= self
._get
_running
_vidinfo
()
1387 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1388 v
= vinfo
.get('vlan')
1389 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1394 def _get_running_vids_n_pvid_str(self
, ifacename
):
1398 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1401 ret_vids
= self
._compress
_into
_ranges
(vids
)
1406 ret_pvid
= '%s' %pvid
1409 return (ret_vids
, ret_pvid
)
1411 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1413 """ This method is a combination of methods _apply_bridge_vids and
1414 _apply_bridge_port_pvids above. A combined function is
1415 found necessary to do the deletes first and the adds later
1416 because kernel does honor vid info flags during deletes.
1419 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1420 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1421 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1422 bportifaceobj
.upperifaces
[0])
1425 vids_int
= self
._ranges
_to
_ints
(vids
)
1427 pvid_int
= int(pvid
) if pvid
else 0
1429 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1430 %(bportifaceobj
.name
, pvid
))
1435 vids_to_add
= vids_int
1437 pvid_to_add
= pvid_int
1440 if not self
._check
_vids
(bportifaceobj
, vids
):
1443 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1446 if not running_vids
and not running_pvid
:
1447 # There cannot be a no running pvid.
1448 # It might just not be in our cache:
1449 # this can happen if at the time we were
1450 # creating the bridge vlan cache, the port
1451 # was not part of the bridge. And we need
1452 # to make sure both vids and pvid is not in
1453 # the cache, to declare that our cache may
1459 (vids_to_del
, vids_to_add
) = \
1460 self
._diff
_vids
(vids_to_add
, running_vids
)
1463 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1464 pvid_to_del
= running_pvid
1466 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1467 (pvid_to_del
not in vids_to_add
)):
1468 # kernel deletes dont take into account
1469 # bridge vid flags and its possible that
1470 # the pvid deletes we do end up deleting
1471 # the vids. Be proactive and add the pvid
1472 # to the vid add list if it is in the vids
1473 # and not already part of vids_to_add.
1474 # This helps with a small corner case:
1478 # - new change is going to move the state to
1481 vids_to_add
.add(pvid_to_del
)
1482 except exceptions
.ReservedVlanException
as e
:
1484 except Exception, e
:
1485 self
.log_error('%s: failed to process vids/pvids'
1486 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1487 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1488 bportifaceobj
, raise_error
=False)
1491 if pvid_to_add
in vids_to_del
:
1492 vids_to_del
.remove(pvid_to_add
)
1493 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1494 self
._compress
_into
_ranges
(
1495 vids_to_del
), isbridge
)
1496 except Exception, e
:
1497 self
.log_warn('%s: failed to del vid `%s` (%s)'
1498 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1502 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1504 except Exception, e
:
1505 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1506 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1510 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1511 self
._compress
_into
_ranges
(
1512 vids_to_add
), isbridge
)
1513 except Exception, e
:
1514 self
.log_error('%s: failed to set vid `%s` (%s)'
1515 %(bportifaceobj
.name
, str(vids_to_add
),
1516 str(e
)), bportifaceobj
, raise_error
=False)
1519 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1520 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1522 except Exception, e
:
1523 self
.log_error('%s: failed to set pvid `%s` (%s)'
1524 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1527 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1534 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1536 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1538 allow_untagged
= 'yes'
1539 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1541 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1543 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1545 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1547 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1549 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1554 vids_final
= bridge_vids
1556 if allow_untagged
== 'yes':
1558 pvid_final
= pvids
[0]
1560 pvid_final
= bridge_pvid
1566 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1569 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1572 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1573 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1574 # Old style bridge port vid info
1575 # skip new style setting on ports
1577 self
.logger
.info('%s: applying bridge configuration '
1578 %ifaceobj
.name
+ 'specific to ports')
1580 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1582 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1586 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1588 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1592 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1593 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1594 port_processed_override
= True
1596 port_processed_override
= False
1598 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1600 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1602 self
.ipcmd
.batch_start()
1603 for bport
in bridgeports
:
1604 # Use the brctlcmd bulk set method: first build a dictionary
1606 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1607 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1608 ' for port %s (missing port)' %bport
)
1610 self
.logger
.info('%s: processing bridge config for port %s'
1611 %(ifaceobj
.name
, bport
))
1612 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1613 if not bportifaceobjlist
:
1615 for bportifaceobj
in bportifaceobjlist
:
1616 # Dont process bridge port if it already has been processed
1617 # and there is no override on port_processed
1618 if (not port_processed_override
and
1619 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1620 bridgeFlags
.PORT_PROCESSED
)):
1623 # Add attributes specific to the vlan aware bridge
1624 if bridge_vlan_aware
:
1625 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1626 bportifaceobj
, bridge_vids
, bridge_pvid
)
1627 elif self
.warn_on_untagged_bridge_absence
:
1628 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1629 except exceptions
.ReservedVlanException
as e
:
1631 except Exception, e
:
1633 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1635 self
.ipcmd
.bridge_batch_commit()
1637 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1639 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1640 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1641 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1642 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1643 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1644 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1645 self
.warn_on_untagged_bridge_absence
= False
1647 def bridge_port_get_bridge_name(self
, ifaceobj
):
1648 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1650 # bridge port is not enslaved to a bridge we need to find
1651 # the bridge in it's upper ifaces then enslave it
1652 for u
in ifaceobj
.upperifaces
:
1653 if self
.ipcmd
.is_bridge(u
):
1656 # return should_enslave port, bridgename
1657 return False, bridgename
1659 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1660 if should_enslave_port
:
1661 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1662 self
.handle_ipv6([ifaceobj
.name
], '1')
1664 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1665 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1667 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1668 except Exception as e
:
1669 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1672 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1673 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1676 # bridge doesn't exist
1679 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1680 if vlan_aware_bridge
:
1681 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1684 should_enslave_port
)
1686 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1688 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1689 ifaceobj
=bridge_ifaceobj
,
1690 ifaceobj_getfunc
=ifaceobj_getfunc
,
1691 bridge_vlan_aware
=vlan_aware_bridge
)
1693 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1695 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1696 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1697 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1700 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1705 def parse_interface_list_value(user_config
):
1707 for entry
in user_config
.split():
1708 ifname
, value
= entry
.split('=')
1709 config
[ifname
] = value
1712 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1713 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1715 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1717 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1719 Checks are not performed in this function and must be verified
1720 before. This is done this way to avoid calling this method on
1721 non vlan & bridge port interfaces thus wasting a bit less time
1727 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1728 # if the user explicitly defined vxlan-learning we need to honor his config
1729 # and not sync vxlan-learning with bridge-learning
1731 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1733 # if BRIDGE_LEARNING is in the desired configuration
1734 # and differs from the running vxlan configuration
1735 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1737 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1738 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1739 % (bridge_name
, brport_name
, brport_learning
))
1741 elif brport_learning
is None and bridge_vlan_aware
:
1742 # is bridge-learning is not configured but the bridge is vlan-aware
1744 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1745 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1747 if default_value
!= running_value
:
1748 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1750 if not brport_vxlan_learning_config
:
1752 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1753 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1754 % (bridge_name
, brport_name
, default_value
))
1756 # if kind and ifla_info_data are set they will be added to the
1757 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1758 return kind
, ifla_info_data
1760 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1762 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1763 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1764 'is not supported on a non-vxlan port'
1765 % (ifaceobj
.name
, brport_name
))
1767 elif (bridge_vlan_aware
and
1768 (not self
.arp_nd_suppress_only_on_vxlan
or
1769 (self
.arp_nd_suppress_only_on_vxlan
and
1770 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1771 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1774 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1775 ifname
= ifaceobj
.name
1778 brports_ifla_info_slave_data
= dict()
1779 brport_ifaceobj_dict
= dict()
1781 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1785 for brport_name
in target_ports
:
1786 if brport_name
not in running_brports
:
1787 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1789 new_targets
.append(brport_name
)
1790 running_brports
= new_targets
1792 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1794 # If target_ports is specified we want to configure only this
1795 # sub-list of port we need to check if these ports are already
1796 # enslaved, if not they will be ignored.
1797 # If target_ports is not populated we will apply the brport
1798 # attributes on all running brport.
1800 for port
in running_brports
:
1801 brport_list
= ifaceobj_getfunc(port
)
1803 brport_ifaceobj_dict
[port
] = brport_list
[0]
1804 brports_ifla_info_slave_data
[port
] = dict()
1806 bridge_ports_learning
= {}
1808 # we iterate through all IFLA_BRPORT supported attributes
1809 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1810 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1811 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1813 if not translate_func
:
1814 # if no translation function is found,
1815 # we ignore this attribute and continue
1819 # user didn't specify any value for this attribute
1820 # looking at policy overrides
1821 br_config
= policymanager
.policymanager_api
.get_iface_default(
1822 module_name
=self
.__class
__.__name
__,
1828 #if bridge_vlan_aware:
1829 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1830 # 'should be configured under the ports'
1831 # % (ifname, attr_name, br_config))
1833 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1834 # brport_name: { attr: value }
1836 # bridge-portprios swp1=5 swp2=32
1837 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1838 if '=' in br_config
:
1840 br_config
= self
.parse_interface_list_value(br_config
)
1842 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1845 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1846 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1847 brport_name
= brport_ifaceobj
.name
1849 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1850 # if the port has just been enslaved, info_slave_data is not cached yet
1851 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1855 if not brport_config
:
1856 # if a brport attribute was specified under the bridge and not under the port
1857 # we assign the bridge value to the port. If an attribute is both defined under
1858 # the bridge and the brport we keep the value of the port and ignore the br val.
1859 if type(br_config
) == dict:
1860 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1861 # br_config is a dictionary, example:
1862 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1863 brport_config
= br_config
.get(brport_name
)
1865 brport_config
= br_config
1867 if not brport_config
:
1868 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1869 module_name
=self
.__class
__.__name
__,
1874 user_config
= brport_config
1876 # attribute specific work
1877 # This shouldn't be here but we don't really have a choice otherwise this
1878 # will require too much code duplication and will make the code very complex
1879 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1881 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1887 user_config
= arp_suppress
1890 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1891 # special handking for group_fwd_mask because Cisco proprietary
1892 # protocol needs to be set via a private netlink attribute
1893 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1894 brports_ifla_info_slave_data
,
1895 user_config
, cached_value
)
1899 # if not bridge_vlan_aware:
1900 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1901 # 'should be configured under the bridge'
1902 # % (ifname, brport_name,
1903 # attr_name, brport_config))
1906 user_config_nl
= translate_func(user_config
)
1907 # check config value against running value
1908 if user_config_nl
!= cached_value
:
1909 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1910 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1911 self
.logger
.debug('(cache %s)' % cached_value
)
1913 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1914 # for vxlan-learning sync purposes we need to save the user config for each brports.
1915 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1916 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1917 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1918 # the brport since it might go out of sync for X and Y reasons.
1919 bridge_ports_learning
[brport_name
] = user_config_nl
1921 elif cached_value
is not None:
1922 # no config found, do we need to reset to default?
1923 default
= self
.get_attr_default_value(attr_name
)
1925 default_netlink
= translate_func(default
)
1927 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1928 and not ifupdownflags
.flags
.PERFMODE
1929 and brport_name
not in newly_enslaved_ports
):
1931 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1932 if default_netlink
!= cached_value
:
1933 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1934 % (ifname
, brport_name
))
1936 bridge_ports_learning
[brport_name
] = default_netlink
1937 except Exception as e
:
1938 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1940 if default_netlink
!= cached_value
:
1941 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1942 % (ifname
, brport_name
, attr_name
, default
))
1943 self
.logger
.debug('(cache %s)' % cached_value
)
1944 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1946 # applying bridge port configuration via netlink
1947 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1949 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1951 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1952 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1953 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1954 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1955 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1959 brport_ifla_info_slave_data
,
1960 bridge_ports_learning
.get(brport_name
))
1962 cached_bridge_mcsnoop
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', Link
.IFLA_BR_MCAST_SNOOPING
])
1964 if (self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
1965 self
.get_bridge_mcsnoop_value(ifaceobj
)
1966 )) or cached_bridge_mcsnoop
:
1967 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
1968 # is on and mcsnoop is on (or mcsnoop is already enabled on the
1969 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
1970 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
):
1971 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
1972 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
1977 if brport_ifla_info_slave_data
or ifla_info_data
:
1979 netlink
.link_add_set(ifname
=brport_name
,
1981 ifla_info_data
=ifla_info_data
,
1982 slave_kind
='bridge',
1983 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1984 except Exception as e
:
1985 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1987 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1988 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1989 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1991 except Exception as e
:
1992 self
.log_error(str(e
), ifaceobj
)
1994 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1996 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1997 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1998 field we need to have special handling for that.
2000 ifla_brport_group_fwd_mask
= 0
2001 ifla_brport_group_fwd_maskhi
= 0
2003 for group
in re
.split(',|\s*', user_config
):
2007 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2009 if not callable(callback
):
2010 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2012 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2014 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2015 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2017 log_mask_change
= True
2018 # if user specify bridge-l2protocol-tunnel stp cdp
2019 # we need to set both MASK and MASKHI but we only want to log once
2021 if cached_ifla_brport_group_fwd_mask
is None:
2022 cached_ifla_brport_group_fwd_mask
= 0
2023 if cached_ifla_brport_group_fwd_maskhi
is None:
2024 cached_ifla_brport_group_fwd_maskhi
= 0
2026 # if the cache value is None it means that the kernel doesn't support this attribute
2027 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2029 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2031 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2032 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2033 log_mask_change
= False
2034 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2036 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2038 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2039 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2040 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2042 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2043 ifname
= ifaceobj
.name
2045 if ifupdownflags
.flags
.PERFMODE
:
2046 link_just_created
= True
2049 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2050 link_just_created
= not link_exists
2053 netlink
.link_add_bridge(ifname
)
2055 self
.logger
.info('%s: bridge already exists' % ifname
)
2057 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2059 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2062 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2063 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2064 newly_enslaved_ports
=newly_enslaved_ports
)
2065 except Exception as e
:
2066 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2070 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2071 if not running_ports
:
2073 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2074 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2075 ifaceobj_getfunc
=ifaceobj_getfunc
,
2076 bridge_vlan_aware
=bridge_vlan_aware
)
2077 except exceptions
.ReservedVlanException
as e
:
2079 except Exception as e
:
2080 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2082 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2083 for p
in running_ports
:
2084 ifaceobj_list
= ifaceobj_getfunc(p
)
2085 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2086 netlink
.link_set_updown(p
, "down")
2089 netlink
.link_set_updown(p
, "up")
2090 except Exception, e
:
2091 self
.logger
.debug('%s: %s: link set up (%s)'
2092 % (ifaceobj
.name
, p
, str(e
)))
2096 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2097 except Exception as e
:
2098 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2100 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2101 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2102 return self
.bridge_mac_iface
2104 if self
.bridge_mac_iface_list
:
2105 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2107 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2108 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2112 for obj
in ifaceobj_list
:
2113 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2114 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2115 if iface_user_configured_hwaddress
:
2116 iface_mac
= iface_user_configured_hwaddress
2118 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2122 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2123 # if hwaddress attribute is not configured we use the running mac addr
2125 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2126 return self
.bridge_mac_iface
2127 elif self
.bridge_set_static_mac_from_port
:
2128 # no policy was provided, we need to get the first physdev or bond ports
2129 # and use its hwaddress to set the bridge mac
2130 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2131 # iterate through the bridge-port list
2132 for port_obj
in ifaceobj_getfunc(port
) or []:
2133 # check if the port is a physdev (link_kind is null) or a bon
2134 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2135 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2136 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2137 if iface_user_configured_hwaddress
:
2138 iface_mac
= iface_user_configured_hwaddress
.lower()
2139 # we need to "normalize" the user provided MAC so it can match with
2140 # what we have in the cache (data retrieved via a netlink dump by
2141 # nlmanager). nlmanager return all macs in lower-case
2143 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2146 self
.bridge_mac_iface
= (port
, iface_mac
)
2147 return self
.bridge_mac_iface
2151 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2152 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2153 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2155 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2157 We have a day one bridge mac changing problem with changing ports
2158 (basically bridge mac changes when the port it inherited the mac from
2161 We have discussed this problem many times before and tabled it.
2162 The issue has aggravated with vxlan bridge ports having auto-generated
2163 random macs...which change on every reboot.
2165 ifupdown2 extract from policy files an iface to select a mac from and
2166 configure it automatically.
2168 if ifaceobj
.get_attr_value('hwaddress'):
2169 # if the user configured a static hwaddress
2170 # there is no need to assign one
2173 ifname
= ifaceobj
.name
2174 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2175 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2176 %(ifname
, mac_intf
, bridge_mac
))
2179 # if an interface is configured with the following attribute:
2180 # hwaddress 08:00:27:42:42:4
2181 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2182 # from the kernel. The only way to counter that is to convert all mac to int
2183 # and compare the ints, it will increase perfs and be safer.
2184 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2185 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2186 if cached_value
and cached_value
== bridge_mac
:
2187 # the bridge mac is already set to the bridge_mac_intf's mac
2190 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2192 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2193 except Exception as e
:
2194 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2195 # log info this error because the user didn't explicitly configured this
2197 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2199 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2200 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2201 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2203 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2204 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2207 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2209 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2210 if ifaceobj_config_attr
in bridge_attributes
:
2211 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2212 % (ifaceobj
.name
, ifaceobj_config_attr
))
2214 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2215 if not self
._is
_bridge
(ifaceobj
):
2217 ifname
= ifaceobj
.name
2218 if not self
.ipcmd
.link_exists(ifname
):
2221 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2223 self
.handle_ipv6(running_ports
, '0')
2224 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2225 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2226 except Exception as e
:
2227 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2229 netlink
.link_del(ifname
)
2230 except Exception as e
:
2231 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2232 self
.logger
.error(str(e
))
2233 # netlink exception already contains the ifname
2235 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2238 running_bridge_port_vids
= ''
2241 running_vids
= self
._get
_runing
_vids
(p
)
2243 running_bridge_port_vids
+= ' %s=%s' %(p
,
2244 ','.join(running_vids
))
2247 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2249 running_bridge_port_pvid
= ''
2252 running_pvid
= self
._get
_runing
_pvid
(p
)
2254 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2258 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2260 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2261 if running_bridge_vids
:
2262 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2263 return running_attrs
2265 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2269 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2270 # so query the ports
2271 running_bridgeport_vids
= []
2272 running_bridgeport_pvids
= []
2273 for bport
in bridgeports
:
2274 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2276 running_bridgeport_vids
.append(' '.join(vids
))
2278 running_bridgeport_pvids
.append(pvid
)
2281 if running_bridgeport_vids
:
2282 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2283 if freq
== len(bridgeports
):
2284 running_attrs
['bridge-vids'] = vidval
2285 bridge_vids
= vidval
.split()
2288 if running_bridgeport_pvids
:
2289 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2290 if freq
== len(bridgeports
) and vidval
!= '1':
2291 running_attrs
['bridge-pvid'] = vidval
2292 bridge_pvid
= vidval
.split()[0]
2294 # Go through all bridge ports and find their vids
2295 for bport
in bridgeports
:
2296 bportifaceobj
= ifaceobj_getfunc(bport
)
2297 if not bportifaceobj
:
2301 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2302 if vids
and vids
!= bridge_vids
:
2304 if pvid
and pvid
!= bridge_pvid
:
2306 if bport_vids
and bport_pvid
in bport_vids
:
2307 bport_vids
.remove(bport_pvid
)
2308 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2309 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2310 bportifaceobj
[0].delete_config('bridge-pvid')
2311 bportifaceobj
[0].delete_config('bridge-vids')
2313 if bport_pvid
and bport_pvid
!= '1':
2314 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2316 # delete any stale bridge-vids under ports
2317 bportifaceobj
[0].delete_config('bridge-pvid')
2319 bportifaceobj
[0].replace_config('bridge-vids',
2320 ' '.join(bport_vids
))
2322 # delete any stale bridge-vids under ports
2323 bportifaceobj
[0].delete_config('bridge-vids')
2324 return running_attrs
2326 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2327 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobjrunning
.name
)
2328 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2330 mcq
= ' '.join(mcqs
)
2333 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2334 bridge_vlan_aware
=False):
2338 skip_kernel_stp_attrs
= 0
2341 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2343 except Exception as e
:
2344 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2346 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2347 if not tmpbridgeattrdict
:
2348 self
.logger
.warn('%s: unable to get bridge attrs'
2349 %ifaceobjrunning
.name
)
2350 return bridgeattrdict
2352 # Fill bridge_ports and bridge stp attributes first
2353 ports
= tmpbridgeattrdict
.get('ports')
2355 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2356 stp
= tmpbridgeattrdict
.get('stp', 'no')
2357 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2358 bridgeattrdict
['bridge-stp'] = [stp
]
2360 if stp
== 'yes' and userspace_stp
:
2361 skip_kernel_stp_attrs
= 1
2363 vlan_stats
= utils
.get_onff_from_onezero(
2364 tmpbridgeattrdict
.get('vlan-stats', None))
2366 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2367 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2369 bool2str
= {'0': 'no', '1': 'yes'}
2370 # pick all other attributes
2371 for k
,v
in tmpbridgeattrdict
.items():
2374 if k
== 'ports' or k
== 'stp':
2377 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2378 # only include igmp attributes if kernel stp is off
2380 attrname
= 'bridge-' + k
2381 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2382 if v
!= mod_default
:
2383 # convert '0|1' running values to 'no|yes'
2384 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2386 bridgeattrdict
[attrname
] = [v
]
2388 if bridge_vlan_aware
:
2391 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2395 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2398 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2401 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2403 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2405 if skip_kernel_stp_attrs
:
2406 return bridgeattrdict
2408 # Do this only for vlan-UNAWARE-bridge
2409 if ports
and not bridge_vlan_aware
:
2410 portconfig
= {'bridge-pathcosts' : '',
2411 'bridge-portprios' : '',
2412 'bridge-learning' : '',
2413 'bridge-unicast-flood' : '',
2414 'bridge-multicast-flood' : '',
2415 'bridge-arp-nd-suppress' : '',
2417 for p
, v
in ports
.items():
2418 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2419 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2421 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2423 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2424 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2426 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2428 v
= utils
.get_onff_from_onezero(
2429 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2432 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2433 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2435 v
= utils
.get_onff_from_onezero(
2436 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2437 p
, 'unicast-flood'))
2439 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2441 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2443 v
= utils
.get_onff_from_onezero(
2444 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2445 p
, 'multicast-flood'))
2447 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2449 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2451 v
= utils
.get_onff_from_onezero(
2452 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2453 p
, 'arp-nd-suppress'))
2455 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2457 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2459 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2462 return bridgeattrdict
2464 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2465 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2466 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2468 mcqs
= attrval
.split()
2470 mcqsout
= ' '.join(mcqs
)
2471 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2472 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2474 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2476 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2478 running_bridge_port_vids
= ''
2479 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2481 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2482 %(ifaceobj
.name
, attrval
))
2487 (port
, val
) = p
.split('=')
2488 vids
= val
.split(',')
2489 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2491 if not self
._compare
_vids
(vids
, running_vids
):
2493 running_bridge_port_vids
+= ' %s=%s' %(port
,
2494 ','.join(running_vids
))
2496 running_bridge_port_vids
+= ' %s' %p
2499 except Exception, e
:
2500 self
.log_warn('%s: failure checking vid %s (%s)'
2501 %(ifaceobj
.name
, p
, str(e
)))
2503 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2504 running_bridge_port_vids
, 1)
2506 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2509 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2511 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2513 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2514 %(ifaceobj
.name
, attrval
))
2516 running_bridge_port_pvids
= ''
2520 (port
, pvid
) = p
.split('=')
2521 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2522 if running_pvid
and running_pvid
== pvid
:
2523 running_bridge_port_pvids
+= ' %s' %p
2526 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2528 except Exception, e
:
2529 self
.log_warn('%s: failure checking pvid %s (%s)'
2530 %(ifaceobj
.name
, pvid
, str(e
)))
2532 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2533 running_bridge_port_pvids
, 1)
2535 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2536 running_bridge_port_pvids
, 0)
2538 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2540 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2542 def _query_check_snooping_wdefault(self
, ifaceobj
):
2543 if (ifupdownflags
.flags
.WITHDEFAULTS
2544 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2545 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2546 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2548 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2549 ifaceobj_getfunc
=None):
2550 if not self
._is
_bridge
(ifaceobj
):
2552 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2553 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2556 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2558 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2559 self
.get_mod_attrs())
2560 #Add default attributes if --with-defaults is set
2561 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2562 ifaceattrs
.append('bridge-stp')
2566 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2567 if not runningattrs
:
2568 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2571 except Exception, e
:
2572 self
.logger
.warn(str(e
))
2575 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2577 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2578 'bridge-port-pvids']
2580 diff
= Set(ifaceattrs
).difference(filterattrs
)
2582 if 'bridge-l2protocol-tunnel' in diff
:
2583 diff
.remove('bridge-l2protocol-tunnel')
2584 # bridge-l2protocol-tunnel requires separate handling
2586 if 'bridge-ports' in diff
:
2587 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2588 diff
.remove('bridge-ports')
2591 # get the corresponding ifaceobj attr
2592 v
= ifaceobj
.get_attr_value_first(k
)
2594 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2595 v
= 'on' if self
.default_stp_on
else 'off'
2598 rv
= runningattrs
.get(k
[7:])
2599 if k
== 'bridge-mcqv4src':
2601 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2602 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2604 if k
== 'bridge-vlan-aware':
2605 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2606 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2607 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2610 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2612 elif k
== 'bridge-stp':
2613 # special case stp compare because it may
2614 # contain more than one valid values
2615 stp_on_vals
= ['on', 'yes']
2616 stp_off_vals
= ['off', 'no']
2617 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2618 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2619 ifaceobjcurr
.update_config_with_status('bridge-stp',
2622 ifaceobjcurr
.update_config_with_status('bridge-stp',
2624 elif k
in ['bridge-pathcosts',
2626 'bridge-portmcrouter',
2629 'bridge-unicast-flood',
2630 'bridge-multicast-flood',
2631 'bridge-arp-nd-suppress',
2633 if k
== 'bridge-arp-nd-suppress':
2634 brctlcmdattrname
= k
[7:]
2636 brctlcmdattrname
= k
[7:].rstrip('s')
2637 # for port attributes, the attributes are in a list
2638 # <portname>=<portattrvalue>
2641 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2644 for vlistitem
in vlist
:
2646 (p
, v
) = vlistitem
.split('=')
2647 if k
in ['bridge-learning',
2648 'bridge-unicast-flood',
2649 'bridge-multicast-flood',
2650 'bridge-arp-nd-suppress',
2652 currv
= utils
.get_onoff_bool(
2653 self
.brctlcmd
.get_bridgeport_attr(
2657 currv
= self
.brctlcmd
.get_bridgeport_attr(
2661 currstr
+= ' %s=%s' %(p
, currv
)
2663 currstr
+= ' %s=%s' %(p
, 'None')
2665 if k
== 'bridge-portmcrouter':
2666 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2670 except Exception, e
:
2671 self
.log_warn(str(e
))
2673 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2674 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2675 rv
= utils
.get_onff_from_onezero(rv
)
2677 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2679 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2681 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2682 # bridge-pvid and bridge-vids on a bridge does
2683 # not correspond directly to a running config
2684 # on the bridge. They correspond to default
2685 # values for the bridge ports. And they are
2686 # already checked against running config of the
2687 # bridge port and reported against a bridge port.
2688 # So, ignore these attributes under the bridge.
2689 # Use '2' for ignore today. XXX: '2' will be
2690 # mapped to a defined value in subsequent patches.
2691 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2693 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2695 elif v
.upper() != rv
.upper():
2696 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2698 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2700 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2702 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2703 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2705 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2706 bridge_all_ports
= []
2707 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2708 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2710 if not running_port_list
and not bridge_all_ports
:
2713 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2716 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2717 # we want to display the same bridge-ports list as provided
2718 # in the interfaces file but if this list contains regexes or
2719 # globs, for now, we won't try to change it.
2720 if 'regex' in port_list
or 'glob' in port_list
:
2721 port_list
= running_port_list
2724 for i
in range(0, len(port_list
)):
2725 if port_list
[i
] in running_port_list
:
2726 ordered
.append(port_list
[i
])
2729 port_list
= running_port_list
2730 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2732 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2733 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2735 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2738 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2739 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2741 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2742 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2743 for ifaceobj
in ifaceobjs
:
2744 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2745 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2748 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2749 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2751 for ifaceobj
in ifaceobjs
:
2752 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2757 def _get_bridge_name(self
, ifaceobj
):
2758 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2760 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2761 ifaceobj_getfunc
, bridgename
):
2762 attr_name
= 'bridge-access'
2763 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2765 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2767 if (not running_pvid
or running_pvid
!= vid
or
2768 (running_vids
and running_vids
[0] != vid
)):
2769 ifaceobjcurr
.update_config_with_status(attr_name
,
2772 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2775 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2777 attr_name
= 'bridge-pvid'
2778 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2780 if running_pvid
and running_pvid
== pvid
:
2781 ifaceobjcurr
.update_config_with_status(attr_name
,
2784 ifaceobjcurr
.update_config_with_status(attr_name
,
2786 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2787 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2788 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2789 # if the interface has multiple iface sections,
2790 # we check the below only for the oldest sibling
2791 # or the last iface section
2792 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2794 if not running_pvid
or running_pvid
!= pvid
:
2795 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2796 ifaceobjcurr
.status_str
= 'bridge pvid error'
2797 elif not running_pvid
or running_pvid
!= '1':
2798 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2799 ifaceobjcurr
.status_str
= 'bridge pvid error'
2801 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2803 vids
= re
.split(r
'[\s\t]\s*', vids
)
2804 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2806 ifaceobjcurr
.update_config_with_status(attr_name
,
2807 ' '.join(running_vids
), 1)
2809 ifaceobjcurr
.update_config_with_status(attr_name
,
2811 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2812 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2813 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2814 # if the interface has multiple iface sections,
2815 # we check the below only for the oldest sibling
2816 # or the last iface section
2818 # check if it matches the bridge vids
2819 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2820 if (bridge_vids
and (not running_vids
or
2821 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2822 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2823 ifaceobjcurr
.status_str
= 'bridge vid error'
2825 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2827 if not self
._is
_bridge
_port
(ifaceobj
):
2828 # Mark all bridge attributes as failed
2829 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2830 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2831 'bridge-pathcosts', 'bridge-portprios',
2832 'bridge-portmcrouter',
2834 'bridge-portmcfl', 'bridge-unicast-flood',
2835 'bridge-multicast-flood',
2836 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2839 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2841 self
.logger
.warn('%s: unable to determine bridge name'
2845 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2846 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2849 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2850 'bridge-portprios' : 'portprio',
2851 'bridge-portmcrouter' : 'portmcrouter',
2852 'bridge-portmcfl' : 'portmcfl',
2853 'bridge-learning' : 'learning',
2854 'bridge-unicast-flood' : 'unicast-flood',
2855 'bridge-multicast-flood' : 'multicast-flood',
2856 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2858 attrval
= ifaceobj
.get_attr_value_first(attr
)
2863 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2864 bridgename
, ifaceobj
.name
, dstattr
)
2866 if dstattr
== 'portmcfl':
2867 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2868 running_attrval
= utils
.get_yesno_boolean(
2869 utils
.get_boolean_from_string(running_attrval
))
2870 elif dstattr
== 'portmcrouter':
2871 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2872 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2874 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2876 elif dstattr
in ['learning',
2881 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2882 running_attrval
= utils
.get_onff_from_onezero(
2885 if running_attrval
!= attrval
:
2886 ifaceobjcurr
.update_config_with_status(attr
,
2889 ifaceobjcurr
.update_config_with_status(attr
,
2891 except Exception, e
:
2892 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2894 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2896 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2897 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2899 if user_config_l2protocol_tunnel
:
2902 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2903 except Exception as e
:
2904 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2906 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2908 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2910 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2911 We need to make sure that all ports comply with the mask given under the bridge
2913 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2915 if user_config_l2protocol_tunnel
:
2916 if '=' in user_config_l2protocol_tunnel
:
2918 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2919 brport_list
= config_per_port_dict
.keys()
2921 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2924 config_per_port_dict
= {}
2925 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2928 for brport_name
in brport_list
:
2929 self
._query
_check
_l2protocol
_tunnel
(
2931 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2934 except Exception as e
:
2935 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2937 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2939 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2940 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2941 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2943 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2944 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2946 if callable(callback
):
2947 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2948 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2949 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2951 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2952 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2953 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2954 running_protocols
= []
2955 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2956 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2957 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2958 running_protocols
.remove('all')
2960 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2961 running_protocols
.append(protocol_name
)
2962 if running_protocols
:
2964 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2965 elif bridge_ifaceobj
:
2966 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2969 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2971 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2973 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2974 if self
._is
_bridge
(ifaceobj
):
2975 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
2977 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2980 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2981 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2982 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2983 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2986 bridge_vlan_aware
=True))
2988 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2989 ifaceobjrunning
, None))
2991 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2992 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2995 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2996 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2997 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2999 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
3000 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
3001 ifaceobjrunning
.update_config('bridge-portprios', v
)
3003 def _query_running_bridge_port(self
, ifaceobjrunning
,
3004 ifaceobj_getfunc
=None):
3006 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
3007 ifaceobjrunning
.name
)
3011 self
.logger
.warn('%s: unable to find bridgename'
3012 %ifaceobjrunning
.name
)
3015 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
3017 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
3018 except Exception as e
:
3019 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
3022 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
3024 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3025 ifaceobjrunning
.name
)
3026 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3027 bridge_port_vids
.remove(bridge_port_pvid
)
3029 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3030 if bridgeifaceobjlist
:
3031 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3032 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3034 if not bridge_port_vids
and bridge_port_pvid
:
3035 # must be an access port
3036 if bridge_port_pvid
!= '1':
3037 ifaceobjrunning
.update_config('bridge-access',
3040 if bridge_port_vids
:
3041 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3042 ifaceobjrunning
.update_config('bridge-vids',
3043 ' '.join(bridge_port_vids
))
3044 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3045 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3046 ifaceobjrunning
.update_config('bridge-pvid',
3049 v
= utils
.get_onff_from_onezero(
3050 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3051 ifaceobjrunning
.name
,
3053 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3054 ifaceobjrunning
.update_config('bridge-learning', v
)
3056 v
= utils
.get_onff_from_onezero(
3057 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3058 ifaceobjrunning
.name
,
3060 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3061 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3063 v
= utils
.get_onff_from_onezero(
3064 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3065 ifaceobjrunning
.name
,
3067 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3068 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3070 v
= utils
.get_onff_from_onezero(
3071 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3072 ifaceobjrunning
.name
,
3074 # Display running 'arp-nd-suppress' only on vxlan ports
3075 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3076 # otherwise, display on all bridge-ports
3078 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3080 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3081 (not self
.arp_nd_suppress_only_on_vxlan
or
3082 (self
.arp_nd_suppress_only_on_vxlan
and
3083 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3084 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3086 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3088 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3090 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3091 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3092 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3093 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3094 except Exception as e
:
3095 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3097 def _query(self
, ifaceobj
, **kwargs
):
3098 """ add default policy attributes supported by the module """
3099 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3100 ifaceobj
.get_attr_value_first('bridge-stp')):
3102 if self
.default_stp_on
:
3103 ifaceobj
.update_config('bridge-stp', 'yes')
3105 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3106 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3107 ['mcquerier', 'bridge-mcquerier'],
3108 ['mcsnoop', 'bridge-mcsnoop']]:
3109 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3110 if value
and not utils
.is_binary_bool(value
):
3111 if attrl
[0] in runningattrs
:
3112 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3113 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3115 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3116 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3117 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3118 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3119 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3120 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3122 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3124 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3126 if 'mcrouter' in running_attrs
:
3127 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3132 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3134 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3136 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3140 (port
, val
) = p
.split('=')
3141 if not utils
.is_binary_bool(val
):
3142 to_convert
.append(port
)
3143 for port
in to_convert
:
3144 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3145 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3150 'query-checkcurr': _query_check
,
3151 'query-running': _query_running
,
3156 """ returns list of ops supported by this module """
3157 return self
._run
_ops
.keys()
3159 def _init_command_handlers(self
):
3161 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3163 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3164 """ run bridge configuration on the interface object passed as
3165 argument. Can create bridge interfaces if they dont exist already
3168 **ifaceobj** (object): iface object
3170 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3174 **query_ifaceobj** (object): query check ifaceobject. This is only
3175 valid when op is 'query-checkcurr'. It is an object same as
3176 ifaceobj, but contains running attribute values and its config
3177 status. The modules can use it to return queried running state
3178 of interfaces. status is success if the running state is same
3179 as user required state in ifaceobj. error otherwise.
3181 op_handler
= self
._run
_ops
.get(operation
)
3184 self
._init
_command
_handlers
()
3186 if (not LinkUtils
.bridge_utils_is_installed
3187 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3188 and LinkUtils
.bridge_utils_missing_warning
):
3189 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3190 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3191 LinkUtils
.bridge_utils_missing_warning
= False
3193 if operation
== 'query-checkcurr':
3194 op_handler(self
, ifaceobj
, query_ifaceobj
,
3195 ifaceobj_getfunc
=ifaceobj_getfunc
)
3197 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)