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>'],
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 multicast router',
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',
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>'],
223 'validrange' : ['yes', 'no', '0', '1'],
225 'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
226 'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
228 { 'help' : 'wait for a max of time secs for the' +
229 ' specified ports to become available,' +
230 'if no ports are specified then those' +
231 ' specified on bridge-ports will be' +
232 ' used here. Specifying no ports here ' +
233 'should not be used if we are using ' +
234 'regex or \"all\" on bridge_ports,' +
235 'as it wouldnt work.',
237 'validvals': ['<number-interface-list>'],
238 'example' : ['bridge-waitport 4 swp1 swp2']},
240 { 'help' : 'forces to time seconds the maximum time ' +
241 'that the Debian bridge setup scripts will ' +
242 'wait for the bridge ports to get to the ' +
243 'forwarding status, doesn\'t allow factional ' +
244 'part. If it is equal to 0 then no waiting' +
246 'validrange' : ['0', '255'],
248 'example' : ['bridge-maxwait 3']},
250 { 'help' : 'bridge port vids. Can be specified ' +
251 'under the bridge or under the port. ' +
252 'If specified under the bridge the ports ' +
253 'inherit it unless overridden by a ' +
254 'bridge-vids attribute under the port',
256 'validvals': ['<number-comma-range-list>'],
257 'example' : ['bridge-vids 4000',
258 'bridge-vids 2000 2200-3000'],
259 'aliases': ['bridge-trunk']},
261 { 'help' : 'bridge port pvid. Must be specified under' +
263 'validrange' : ['0', '4096'],
264 'example' : ['bridge-pvid 1']},
266 { 'help' : 'bridge port access vlan. Must be ' +
267 'specified under the bridge port',
268 'validrange' : ['1', '4094'],
269 'example' : ['bridge-access 300']},
270 'bridge-allow-untagged' :
271 { 'help' : 'indicate if the bridge port accepts ' +
272 'untagged packets or not. Must be ' +
273 'specified under the bridge port. ' +
274 'Default is \'yes\'',
275 'validvals' : ['yes', 'no'],
276 'example' : ['bridge-allow-untagged yes'],
279 { 'help' : 'bridge vlans',
281 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
282 'bridge-port-pvids' :
283 { 'help' : 'bridge port vlans',
285 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
287 { 'help' : 'bridge port learning flag',
288 'validvals': ['on', 'off', '<interface-on-off-list>'],
290 'example' : ['bridge-learning off']},
291 'bridge-igmp-version' :
292 { 'help' : 'mcast igmp version',
293 'validvals': ['2', '3'],
295 'example' : ['bridge-igmp-version 2']},
296 'bridge-mld-version':
297 { 'help' : 'mcast mld version',
298 'validvals': ['1', '2'],
300 'example' : ['bridge-mld-version 1']},
301 'bridge-unicast-flood' :
302 { 'help' : 'bridge port unicast flood flag',
303 'validvals': ['on', 'off', '<interface-on-off-list>'],
305 'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
306 'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
307 'bridge-multicast-flood' :
308 { 'help' : 'bridge port multicast flood flag',
309 'validvals': ['on', 'off', '<interface-on-off-list>'],
311 'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
312 'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
313 'bridge-vlan-protocol' :
314 { 'help' : 'bridge vlan protocol',
315 'default' : '802.1q',
316 'validvals': ['802.1q', '802.1ad'],
317 'example' : ['bridge-vlan-protocol 802.1q']},
318 'bridge-vlan-stats' :
319 { 'help' : 'bridge vlan stats',
321 'validvals': ['on', 'off'],
322 'example' : ['bridge-vlan-stats off']},
323 'bridge-arp-nd-suppress' :
324 { 'help' : 'bridge port arp nd suppress flag',
325 'validvals': ['on', 'off', '<interface-on-off-list>'],
327 'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
328 'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
330 { 'help' : 'bridge multicast stats',
332 'validvals': ['on', 'off'],
333 'example' : ['bridge-mcstats off']},
334 'bridge-l2protocol-tunnel': {
335 'help': 'layer 2 protocol tunneling',
336 'validvals': [ # XXX: lists all combinations, should move to
337 # a better representation
342 'cdp lacp lldp pvst',
357 'lacp lldp pvst stp',
369 '<interface-l2protocol-tunnel-list>'],
371 'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
372 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
373 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
374 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
375 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
380 # Netlink attributes not associated with ifupdown2
381 # attributes are left commented-out for a future use
382 # and kept in order :)
383 _ifla_br_attributes_map
= (
384 # Link.IFLA_BR_UNSPEC,
385 ('bridge-fd', Link
.IFLA_BR_FORWARD_DELAY
),
386 ('bridge-hello', Link
.IFLA_BR_HELLO_TIME
),
387 ('bridge-maxage', Link
.IFLA_BR_MAX_AGE
),
388 ('bridge-ageing', Link
.IFLA_BR_AGEING_TIME
),
389 ('bridge-stp', Link
.IFLA_BR_STP_STATE
),
390 ('bridge-bridgeprio', Link
.IFLA_BR_PRIORITY
),
391 ('bridge-vlan-aware', Link
.IFLA_BR_VLAN_FILTERING
),
392 ('bridge-vlan-protocol', Link
.IFLA_BR_VLAN_PROTOCOL
),
393 # Link.IFLA_BR_GROUP_FWD_MASK,
394 # Link.IFLA_BR_ROOT_ID,
395 # Link.IFLA_BR_BRIDGE_ID,
396 # Link.IFLA_BR_ROOT_PORT,
397 # (Link.IFLA_BR_ROOT_PATH_COST,,
398 # Link.IFLA_BR_TOPOLOGY_CHANGE,
399 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
400 # Link.IFLA_BR_HELLO_TIMER,
401 # Link.IFLA_BR_TCN_TIMER,
402 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
403 # Link.IFLA_BR_GC_TIMER,
404 # Link.IFLA_BR_GROUP_ADDR,
405 # Link.IFLA_BR_FDB_FLUSH,
406 ('bridge-mcrouter', Link
.IFLA_BR_MCAST_ROUTER
),
407 #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
408 ('bridge-mcqifaddr', Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
),
409 ('bridge-mcquerier', Link
.IFLA_BR_MCAST_QUERIER
),
410 ('bridge-hashel', Link
.IFLA_BR_MCAST_HASH_ELASTICITY
),
411 ('bridge-hashmax', Link
.IFLA_BR_MCAST_HASH_MAX
),
412 ('bridge-mclmc', Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
),
413 ('bridge-mcsqc', Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
),
414 ('bridge-mclmi', Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
),
415 ('bridge-mcmi', Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
),
416 ('bridge-mcqpi', Link
.IFLA_BR_MCAST_QUERIER_INTVL
),
417 ('bridge-mcqi', Link
.IFLA_BR_MCAST_QUERY_INTVL
),
418 ('bridge-mcqri', Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
),
419 ('bridge-mcsqi', Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
),
420 # Link.IFLA_BR_NF_CALL_IPTABLES,
421 # Link.IFLA_BR_NF_CALL_IP6TABLES,
422 # Link.IFLA_BR_NF_CALL_ARPTABLES,
423 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
425 # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
426 ('bridge-igmp-version', Link
.IFLA_BR_MCAST_IGMP_VERSION
, ),
427 ('bridge-mcstats', Link
.IFLA_BR_MCAST_STATS_ENABLED
),
428 ('bridge-mld-version', Link
.IFLA_BR_MCAST_MLD_VERSION
)
430 # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
431 # they are supported. It is done this way because this dictionary is used
432 # in a loop, but these attributes require additional work. Thus they are
433 # excluded from this loop without overhead.
435 # we are still using the old linkCache we need an easy way
436 # to use this cache with the new full-netlink approach
437 _ifla_br_attributes_old_cache_key_map
= dict(
439 (Link
.IFLA_BR_FORWARD_DELAY
, 'fd'),
440 (Link
.IFLA_BR_HELLO_TIME
, 'hello'),
441 (Link
.IFLA_BR_MAX_AGE
, 'maxage'),
442 (Link
.IFLA_BR_AGEING_TIME
, 'ageing'),
443 (Link
.IFLA_BR_STP_STATE
, 'stp'),
444 (Link
.IFLA_BR_PRIORITY
, 'bridgeprio'),
445 (Link
.IFLA_BR_VLAN_FILTERING
, 'vlan_filtering'),
446 (Link
.IFLA_BR_VLAN_PROTOCOL
, 'vlan-protocol'),
447 (Link
.IFLA_BR_MCAST_ROUTER
, 'mcrouter'),
448 (Link
.IFLA_BR_MCAST_SNOOPING
, 'mcsnoop'),
449 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, 'mcqifaddr'),
450 (Link
.IFLA_BR_MCAST_QUERIER
, 'mcquerier'),
451 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, 'hashel'),
452 (Link
.IFLA_BR_MCAST_HASH_MAX
, 'hashmax'),
453 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, 'mclmc'),
454 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, 'mcsqc'),
455 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, 'mclmi'),
456 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, 'mcmi'),
457 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, 'mcqpi'),
458 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, 'mcqi'),
459 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, 'mcqri'),
460 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, 'mcsqi'),
461 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, 'vlan-stats'),
462 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, 'mcstats'),
463 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, 'igmp-version'),
464 (Link
.IFLA_BR_MCAST_MLD_VERSION
, 'mld-version')
468 _ifla_br_attributes_translate_user_config_to_netlink_map
= dict(
470 # Link.IFLA_BR_UNSPEC,
471 (Link
.IFLA_BR_FORWARD_DELAY
, lambda x
: int(x
) * 100),
472 (Link
.IFLA_BR_HELLO_TIME
, lambda x
: int(x
) * 100),
473 (Link
.IFLA_BR_MAX_AGE
, lambda x
: int(x
) * 100),
474 (Link
.IFLA_BR_AGEING_TIME
, lambda x
: int(x
) * 100),
475 # Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
476 (Link
.IFLA_BR_PRIORITY
, int),
477 (Link
.IFLA_BR_VLAN_FILTERING
, utils
.get_boolean_from_string
),
478 (Link
.IFLA_BR_VLAN_PROTOCOL
, str),
479 # Link.IFLA_BR_GROUP_FWD_MASK,
480 # Link.IFLA_BR_ROOT_ID,
481 # Link.IFLA_BR_BRIDGE_ID,
482 # Link.IFLA_BR_ROOT_PORT,
483 # Link.IFLA_BR_ROOT_PATH_COST,
484 # Link.IFLA_BR_TOPOLOGY_CHANGE,
485 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
486 # Link.IFLA_BR_HELLO_TIMER,
487 # Link.IFLA_BR_TCN_TIMER,
488 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
489 # Link.IFLA_BR_GC_TIMER,
490 # Link.IFLA_BR_GROUP_ADDR,
491 # Link.IFLA_BR_FDB_FLUSH,
492 (Link
.IFLA_BR_MCAST_ROUTER
, utils
.get_int_from_boolean_and_string
),
493 (Link
.IFLA_BR_MCAST_SNOOPING
, utils
.get_boolean_from_string
),
494 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, utils
.get_boolean_from_string
),
495 (Link
.IFLA_BR_MCAST_QUERIER
, utils
.get_boolean_from_string
),
496 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, int),
497 (Link
.IFLA_BR_MCAST_HASH_MAX
, int),
498 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, int),
499 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, int),
500 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, lambda x
: int(x
) * 100),
501 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, lambda x
: int(x
) * 100),
502 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, lambda x
: int(x
) * 100),
503 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, lambda x
: int(x
) * 100),
504 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, lambda x
: int(x
) * 100),
505 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, lambda x
: int(x
) * 100),
506 # Link.IFLA_BR_NF_CALL_IPTABLES,
507 # Link.IFLA_BR_NF_CALL_IP6TABLES,
508 # Link.IFLA_BR_NF_CALL_ARPTABLES,
509 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
511 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, utils
.get_boolean_from_string
),
512 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, int),
513 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, utils
.get_boolean_from_string
),
514 (Link
.IFLA_BR_MCAST_MLD_VERSION
, int)
518 _ifla_brport_attributes_map
= (
519 # Link.IFLA_BRPORT_UNSPEC,
520 # Link.IFLA_BRPORT_STATE,
521 ('bridge-portprios', Link
.IFLA_BRPORT_PRIORITY
),
522 ('bridge-pathcosts', Link
.IFLA_BRPORT_COST
),
523 # Link.IFLA_BRPORT_MODE,
524 # Link.IFLA_BRPORT_GUARD,
525 # Link.IFLA_BRPORT_PROTECT,
526 ('bridge-portmcfl', Link
.IFLA_BRPORT_FAST_LEAVE
),
527 ('bridge-learning', Link
.IFLA_BRPORT_LEARNING
),
528 ('bridge-unicast-flood', Link
.IFLA_BRPORT_UNICAST_FLOOD
),
529 # Link.IFLA_BRPORT_PROXYARP,
530 # Link.IFLA_BRPORT_LEARNING_SYNC,
531 # Link.IFLA_BRPORT_PROXYARP_WIFI,
532 # Link.IFLA_BRPORT_ROOT_ID,
533 # Link.IFLA_BRPORT_BRIDGE_ID,
534 # Link.IFLA_BRPORT_DESIGNATED_PORT,
535 # Link.IFLA_BRPORT_DESIGNATED_COST,
536 # Link.IFLA_BRPORT_ID,
537 # Link.IFLA_BRPORT_NO,
538 # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
539 # Link.IFLA_BRPORT_CONFIG_PENDING,
540 # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
541 # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
542 # Link.IFLA_BRPORT_HOLD_TIMER,
543 # Link.IFLA_BRPORT_FLUSH,
544 ('bridge-portmcrouter', Link
.IFLA_BRPORT_MULTICAST_ROUTER
),
545 # Link.IFLA_BRPORT_PAD,
546 ('bridge-multicast-flood', Link
.IFLA_BRPORT_MCAST_FLOOD
),
547 # Link.IFLA_BRPORT_MCAST_TO_UCAST,
548 # Link.IFLA_BRPORT_VLAN_TUNNEL,
549 # Link.IFLA_BRPORT_BCAST_FLOOD
550 ('bridge-l2protocol-tunnel', Link
.IFLA_BRPORT_GROUP_FWD_MASK
),
551 # Link.IFLA_BRPORT_PEER_LINK,
552 # Link.IFLA_BRPORT_DUAL_LINK,
553 ('bridge-arp-nd-suppress', Link
.IFLA_BRPORT_ARP_SUPPRESS
),
556 _ifla_brport_multicast_router_dict_to_int
= {
567 # callable to translate <interface-yes-no-0-1-list> to netlink value
568 _ifla_brport_attributes_translate_user_config_to_netlink_map
= dict(
570 (Link
.IFLA_BRPORT_PRIORITY
, int),
571 (Link
.IFLA_BRPORT_COST
, int),
572 (Link
.IFLA_BRPORT_MULTICAST_ROUTER
, lambda x
: bridge
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(x
, 0)),
573 (Link
.IFLA_BRPORT_FAST_LEAVE
, utils
.get_boolean_from_string
),
574 (Link
.IFLA_BRPORT_LEARNING
, utils
.get_boolean_from_string
),
575 (Link
.IFLA_BRPORT_UNICAST_FLOOD
, utils
.get_boolean_from_string
),
576 (Link
.IFLA_BRPORT_MCAST_FLOOD
, utils
.get_boolean_from_string
),
577 (Link
.IFLA_BRPORT_GROUP_FWD_MASK
, lambda x
: x
),
578 (Link
.IFLA_BRPORT_ARP_SUPPRESS
, utils
.get_boolean_from_string
)
582 def __init__(self
, *args
, **kargs
):
583 moduleBase
.__init
__(self
, *args
, **kargs
)
585 self
.name
= self
.__class
__.__name
__
587 self
._running
_vidinfo
= {}
588 self
._running
_vidinfo
_valid
= False
589 self
._resv
_vlan
_range
= self
._get
_reserved
_vlan
_range
()
590 self
.logger
.debug('%s: using reserved vlan range %s' % (self
.__class
__.__name
__, str(self
._resv
_vlan
_range
)))
592 self
.default_stp_on
= utils
.get_boolean_from_string(
593 policymanager
.policymanager_api
.get_attr_default(
594 module_name
=self
.__class
__.__name
__,
599 self
.default_vlan_stats
= policymanager
.policymanager_api
.get_attr_default(
600 module_name
=self
.__class
__.__name
__,
601 attr
='bridge-vlan-stats'
604 self
.warn_on_untagged_bridge_absence
= utils
.get_boolean_from_string(
605 policymanager
.policymanager_api
.get_module_globals(
606 module_name
=self
.__class
__.__name
__,
607 attr
='warn_on_untagged_bridge_absence'
610 self
.logger
.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
611 % self
.warn_on_untagged_bridge_absence
)
613 self
._vxlan
_bridge
_default
_igmp
_snooping
= policymanager
.policymanager_api
.get_module_globals(
614 self
.__class
__.__name
__,
615 'vxlan_bridge_default_igmp_snooping'
617 self
.logger
.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
618 % self
._vxlan
_bridge
_default
_igmp
_snooping
)
620 self
.arp_nd_suppress_only_on_vxlan
= utils
.get_boolean_from_string(
621 policymanager
.policymanager_api
.get_module_globals(
622 module_name
=self
.__class
__.__name
__,
623 attr
='allow_arp_nd_suppress_only_on_vxlan'
626 self
.logger
.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self
.arp_nd_suppress_only_on_vxlan
)
629 self
.bridge_allow_multiple_vlans
= utils
.get_boolean_from_string(
630 self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
633 # Cumulus Linux specific variable. Failure probably means that
634 # ifupdown2 is running a a different system.
635 self
.bridge_allow_multiple_vlans
= True
636 self
.logger
.debug('bridge: init: multiple vlans allowed %s' % self
.bridge_allow_multiple_vlans
)
638 self
.bridge_mac_iface_list
= policymanager
.policymanager_api
.get_module_globals(self
.__class
__.__name
__, 'bridge_mac_iface') or []
639 self
.bridge_mac_iface
= None, None # ifname, mac
641 self
.bridge_set_static_mac_from_port
= utils
.get_boolean_from_string(
642 policymanager
.policymanager_api
.get_module_globals(
643 self
.__class
__.__name
__, 'bridge_set_static_mac_from_port'
647 self
.l2protocol_tunnel_callback
= {
648 'all': self
._l2protocol
_tunnel
_set
_all
,
649 'stp': self
._l2protocol
_tunnel
_set
_stp
,
650 'cdp': self
._l2protocol
_tunnel
_set
_cdp
,
651 'pvst': self
._l2protocol
_tunnel
_set
_pvst
,
652 'lldp': self
._l2protocol
_tunnel
_set
_lldp
,
653 'lacp': self
._l2protocol
_tunnel
_set
_lacp
656 self
.query_check_l2protocol_tunnel_callback
= {
657 'all': self
._query
_check
_l2protocol
_tunnel
_all
,
658 'stp': self
._query
_check
_l2protocol
_tunnel
_stp
,
659 'cdp': self
._query
_check
_l2protocol
_tunnel
_cdp
,
660 'pvst': self
._query
_check
_l2protocol
_tunnel
_pvst
,
661 'lldp': self
._query
_check
_l2protocol
_tunnel
_lldp
,
662 'lacp': self
._query
_check
_l2protocol
_tunnel
_lacp
666 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
667 ifla_brport_group_maskhi |
= 0x1
668 return ifla_brport_group_mask
, ifla_brport_group_maskhi
671 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
672 ifla_brport_group_maskhi |
= 0x2
673 return ifla_brport_group_mask
, ifla_brport_group_maskhi
676 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
677 ifla_brport_group_mask |
= 0x1
678 return ifla_brport_group_mask
, ifla_brport_group_maskhi
681 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
682 ifla_brport_group_mask |
= 0x4
683 return ifla_brport_group_mask
, ifla_brport_group_maskhi
686 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
687 ifla_brport_group_mask |
= 0x4000
688 return ifla_brport_group_mask
, ifla_brport_group_maskhi
691 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
692 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
693 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
696 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
697 return ifla_brport_group_mask
& 0x1
700 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
701 return ifla_brport_group_maskhi
& 0x2
704 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
705 return ifla_brport_group_maskhi
& 0x1
708 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
709 return ifla_brport_group_mask
& 0x4000
712 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
713 return ifla_brport_group_mask
& 0x4
716 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
717 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
719 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
720 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
721 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
722 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
724 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
725 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
726 return retval
and c1
#and c2
728 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
730 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
732 for brport_name
in ifaceobj
.lowerifaces
:
733 for obj
in ifaceobj_getfunc(brport_name
) or []:
734 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
735 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
736 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
737 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
738 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
739 % (ifaceobj
.name
, brport_name
))
742 vlan_id
= sub_intf_vlan_id
745 def check_bridge_port_vid_attrs(self
, ifaceobj
):
746 if (ifaceobj
.get_attr_value('bridge-access') and
747 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
748 ifaceobj
.get_attr_value('bridge-pvid'))):
749 self
.logger
.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
750 'will be ignored' % ifaceobj
.name
)
754 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
755 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
756 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
760 for port_name
in ports
:
761 port_obj_l
= ifaceobj_getfunc(port_name
)
762 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
763 self
.logger
.error('%s: %s: vlan sub-interface is not '
764 'supported in a vlan-aware bridge'
765 % (ifaceobj
.name
, port_name
))
768 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
769 self
.arp_nd_suppress_only_on_vxlan
and
770 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
771 self
.log_error('\'bridge-arp-nd-suppress\' is not '
772 'supported on a non-vxlan port %s'
778 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
779 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
780 'device (%s) is part of vlan aware bridge (%s)'
781 % (ifaceobj
.name
, bridgename
), ifaceobj
)
783 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
784 if not ifaceobj_getfunc
:
786 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
787 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
788 if ifaceobj
.get_attr_value('bridge-access'):
790 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
791 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
792 if not ifaceobj_upper_list
:
794 ifaceobj_upper
= ifaceobj_upper_list
[0]
795 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
796 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
797 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
798 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
801 or not self
._compare
_vids
(bridge_vids
,
804 self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
,
810 def _is_bridge(ifaceobj
):
811 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
812 ifaceobj
.get_attr_value_first('bridge-ports') or
813 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
815 def _get_ifaceobj_bridge_ports(self
, ifaceobj
, warn
=True):
816 ports
= ifaceobj
.get_attr_value('bridge-ports')
817 if warn
and ports
and len(ports
) > 1:
818 self
.log_warn('%s: ignoring duplicate bridge-ports lines: %s'
819 %(ifaceobj
.name
, ports
[1:]))
821 if 'none' in ports
[0]:
826 def _is_bridge_port(self
, ifaceobj
):
827 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
831 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
832 if not self
._is
_bridge
(ifaceobj
):
834 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
835 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
836 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
837 # for special vlan aware bridges, we need to add another bit
838 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
839 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
840 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
841 ifaceobj
.role |
= ifaceRole
.MASTER
842 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
843 return self
.parse_port_list(ifaceobj
.name
,
844 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
847 def get_dependent_ifacenames_running(self
, ifaceobj
):
848 self
._init
_command
_handlers
()
849 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
851 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
853 def _get_bridge_port_list(self
, ifaceobj
):
855 # port list is also available in the previously
856 # parsed dependent list. Use that if available, instead
857 # of parsing port expr again
858 port_list
= ifaceobj
.lowerifaces
861 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
863 return self
.parse_port_list(ifaceobj
.name
, ports
)
867 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
868 # When enslaving bridge-ports we need to return the exact user
869 # configured bridge ports list (bridge will inherit the mac of the
871 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
872 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
874 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
875 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
876 if not waitport_value
: return
878 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
879 if not waitportvals
: return
881 waitporttime
= int(waitportvals
[0])
883 self
.log_warn('%s: invalid waitport value \'%s\''
884 %(ifaceobj
.name
, waitportvals
[0]))
886 if waitporttime
<= 0: return
888 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
890 except IndexError, e
:
891 # ignore error and use all bridge ports
892 waitportlist
= portlist
894 if not waitportlist
: return
895 self
.logger
.info('%s: waiting for ports %s to exist ...'
896 %(ifaceobj
.name
, str(waitportlist
)))
897 starttime
= time
.time()
898 while ((time
.time() - starttime
) < waitporttime
):
899 if all([False for p
in waitportlist
900 if not self
.ipcmd
.link_exists(p
)]):
904 self
.log_warn('%s: unable to process waitport: %s'
905 %(ifaceobj
.name
, str(e
)))
907 def _enable_disable_ipv6(self
, port
, enable
='1'):
909 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
911 self
.logger
.info(str(e
))
913 def handle_ipv6(self
, ports
, state
, ifaceobj
=None):
915 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
) and
916 not ifaceobj
.get_attr_value('address')):
917 self
._enable
_disable
_ipv
6(ifaceobj
.name
, state
)
919 self
._enable
_disable
_ipv
6(p
, state
)
921 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
922 """ pretty print bridge port add errors.
923 since the commands are batched and the kernel only returns error
924 codes, this function tries to interpret some error codes
925 and prints clearer errors """
927 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
928 # Cumulus Linux specific error checks
930 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
932 for bport
in bridgeports
:
933 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
935 if currvlanid
!= vlanid
:
936 self
.log_error('%s: ' %bridgeifaceobj
.name
+
937 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
941 except Exception as e
:
942 errstr
+= '\n%s' % str(e
)
943 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
945 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
946 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
947 runningbridgeports
= []
949 self
.ipcmd
.batch_start()
950 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
951 self
.ipcmd
.batch_start()
952 # Delete active ports not in the new port list
953 if not ifupdownflags
.flags
.PERFMODE
:
954 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
955 if runningbridgeports
:
956 for bport
in runningbridgeports
:
957 if not bridgeports
or bport
not in bridgeports
:
958 self
.ipcmd
.link_set(bport
, 'nomaster')
959 # set admin DOWN on all removed ports
960 # that don't have config outside bridge
961 if not ifaceobj_getfunc(bport
):
962 netlink
.link_set_updown(bport
, "down")
963 # enable ipv6 for ports that were removed
964 self
.handle_ipv6([bport
], '0')
966 runningbridgeports
= []
968 self
.ipcmd
.batch_commit()
972 newbridgeports
= Set(bridgeports
).difference(Set(runningbridgeports
))
973 newly_enslaved_ports
= []
975 newbridgeports_ordered
= []
976 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
977 if br_port
in newbridgeports
:
978 newbridgeports_ordered
.append(br_port
)
980 for bridgeport
in newbridgeports_ordered
:
982 if (not ifupdownflags
.flags
.DRYRUN
and
983 not self
.ipcmd
.link_exists(bridgeport
)):
984 self
.log_error('%s: bridge port %s does not exist'
985 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
988 hwaddress
= self
.ipcmd
.link_get_hwaddress(bridgeport
)
989 if not self
._valid
_ethaddr
(hwaddress
):
990 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
991 bridgeport
) + 'invalid ether addr %s'
994 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
995 newly_enslaved_ports
.append(bridgeport
)
996 self
.handle_ipv6([bridgeport
], '1')
997 self
.ipcmd
.addr_flush(bridgeport
)
1001 self
.ipcmd
.batch_commit()
1002 self
.ipcmd
.batch_start()
1003 except Exception, e
:
1004 self
.logger
.error(str(e
))
1007 self
.ipcmd
.batch_commit()
1008 except Exception, e
:
1009 self
._pretty
_print
_add
_ports
_error
(str(e
), ifaceobj
,
1014 self
.log_error('bridge configuration failed (missing ports)')
1016 return newly_enslaved_ports
1018 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1019 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1020 if not maxwait
: return
1022 maxwait
= int(maxwait
)
1024 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1027 if not maxwait
: return
1028 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1031 starttime
= time
.time()
1032 while ((time
.time() - starttime
) < maxwait
):
1033 if all([False for p
in portlist
1034 if self
.read_file_oneline(
1035 '/sys/class/net/%s/brif/%s/state'
1036 %(ifaceobj
.name
, p
)) != '3']):
1039 except Exception, e
:
1040 self
.log_warn('%s: unable to process maxwait: %s'
1041 %(ifaceobj
.name
, str(e
)))
1043 def _ints_to_ranges(self
, ints
):
1044 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
1046 yield b
[0][1], b
[-1][1]
1048 def _ranges_to_ints(self
, rangelist
):
1049 """ returns expanded list of integers given set of string ranges
1050 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1054 for part
in rangelist
:
1056 a
, b
= part
.split('-')
1057 a
, b
= int(a
), int(b
)
1058 result
.extend(range(a
, b
+ 1))
1063 self
.logger
.warn('unable to parse vids \'%s\''
1064 %''.join(rangelist
))
1068 def _compress_into_ranges(self
, vids_ints
):
1069 return ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
1070 for start
, end
in self
._ints
_to
_ranges
(vids_ints
)]
1072 def _diff_vids(self
, vids1_ints
, vids2_ints
):
1073 return Set(vids2_ints
).difference(vids1_ints
), Set(vids1_ints
).difference(vids2_ints
)
1075 def _compare_vids(self
, vids1
, vids2
, pvid
=None):
1076 """ Returns true if the vids are same else return false """
1078 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
1079 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
1080 set_diff
= Set(vids1_ints
).symmetric_difference(vids2_ints
)
1081 if pvid
and int(pvid
) in set_diff
:
1082 set_diff
.remove(int(pvid
))
1088 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1090 # Sets old style igmp querier
1092 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1094 running_mcqv4src
= {}
1095 if not ifupdownflags
.flags
.PERFMODE
:
1096 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1098 srclist
= attrval
.split()
1103 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
1105 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1106 for v
in mcqs
.keys():
1107 self
.brctlcmd
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1108 elif not ifupdownflags
.flags
.PERFMODE
:
1109 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1110 if running_mcqv4src
:
1111 for v
in running_mcqv4src
.keys():
1112 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1114 def _get_running_vidinfo(self
):
1115 if self
._running
_vidinfo
_valid
:
1116 return self
._running
_vidinfo
1117 self
._running
_vidinfo
= {}
1119 # Removed check for PERFMODE. Need the get in all cases
1120 # including reboot, so that we can configure the pvid correctly.
1121 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all_json()
1122 self
._running
_vidinfo
_valid
= True
1123 return self
._running
_vidinfo
1125 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1127 # Supports old style vlan vid info format
1130 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1131 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1132 if not bridge_port_pvids
and not bridge_port_vids
:
1135 # Handle bridge vlan attrs
1137 if bridge_port_pvids
:
1138 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1140 self
.log_warn('%s: could not parse \'%s %s\''
1141 %(ifaceobj
.name
, 'bridge-port-pvids',
1146 (port
, pvid
) = p
.split('=')
1148 running_pvid
= self
._get
_running
_pvid
(port
)
1150 if running_pvid
== pvid
:
1153 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
1154 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
1155 except Exception, e
:
1156 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1157 %(ifaceobj
.name
, p
, str(e
)))
1160 if bridge_port_vids
:
1161 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1163 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1164 'bridge-port-vids', bridge_port_vids
))
1168 (port
, val
) = p
.split('=')
1169 vids
= val
.split(',')
1170 vids_int
= self
._ranges
_to
_ints
(vids
)
1171 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
1173 (vids_to_del
, vids_to_add
) = \
1174 self
._diff
_vids
(vids_int
, running_vids
)
1176 self
.ipcmd
.bridge_port_vids_del(port
,
1177 self
._compress
_into
_ranges
(vids_to_del
))
1179 self
.ipcmd
.bridge_port_vids_add(port
,
1180 self
._compress
_into
_ranges
(vids_to_add
))
1182 self
.ipcmd
.bridge_port_vids_add(port
, vids_int
)
1183 except Exception, e
:
1184 self
.log_warn('%s: failed to set vid `%s` (%s)'
1185 %(ifaceobj
.name
, p
, str(e
)))
1187 def _is_running_stp_state_on(self
, bridgename
):
1188 """ Returns True if running stp state is on, else False """
1190 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1192 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1193 return running_stp_state
and running_stp_state
!= '0'
1197 def _is_config_stp_state_on(self
, ifaceobj
):
1198 """ Returns true if user specified stp state is on, else False """
1200 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1202 return self
.default_stp_on
1203 return utils
.get_boolean_from_string(stp_attr
)
1205 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1206 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1207 if not mcsnoop
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1208 return self
._vxlan
_bridge
_default
_igmp
_snooping
1211 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1219 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1221 if not callable(translate_func
):
1225 user_config
= policymanager
.policymanager_api
.get_iface_default(
1226 module_name
=self
.__class
__.__name
__,
1231 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1232 if old_cache_key
and not link_just_created
:
1233 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1234 if not cached_value
:
1235 # the link already exists but we don't have any value
1236 # cached for this attr, it probably means that the
1237 # capability is not available on this system (i.e old kernel)
1238 self
.logger
.debug('%s: ignoring %s %s: capability '
1239 'probably not supported on this system'
1240 % (ifname
, attr_name
, user_config
))
1242 # we need to convert the cache value to "netlink" format
1243 cached_value
= translate_func(cached_value
.lower())
1247 if not user_config
and not link_just_created
and cached_value
is not None:
1248 # there is no user configuration for this attribute
1249 # if the bridge existed before we need to check if
1250 # this attribute needs to be reset to default value
1251 default_value
= self
.get_attr_default_value(attr_name
)
1254 # the attribute has a default value, we need to convert it to
1255 # netlink format to compare it with the cache value
1256 default_value_nl
= translate_func(default_value
) # default_value.lower()
1258 if default_value_nl
!= cached_value
:
1259 # the running value difers from the default value
1260 # but the user didn't specify any config
1261 # resetting attribute to default
1262 ifla_info_data
[nl_attr
] = default_value_nl
1263 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1265 user_config_nl
= translate_func(user_config
) # user_config.lower()
1267 if user_config_nl
!= cached_value
:
1268 ifla_info_data
[nl_attr
] = user_config_nl
1270 if cached_value
is not None:
1271 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1273 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1274 except Exception as e
:
1275 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1277 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1278 ifla_info_data
= dict()
1279 ifname
= ifaceobj
.name
1281 self
.logger
.info('%s: apply bridge settings' % ifname
)
1283 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1284 self
.fill_ifla_info_data_with_ifla_br_attribute(
1285 ifla_info_data
=ifla_info_data
,
1286 link_just_created
=link_just_created
,
1289 attr_name
=attr_name
,
1290 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1294 self
.fill_ifla_info_data_with_ifla_br_attribute(
1295 ifla_info_data
=ifla_info_data
,
1296 link_just_created
=link_just_created
,
1298 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1299 attr_name
='bridge-mcsnoop',
1300 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1304 if bridge_vlan_aware
:
1305 self
.fill_ifla_info_data_with_ifla_br_attribute(
1306 ifla_info_data
=ifla_info_data
,
1307 link_just_created
=link_just_created
,
1309 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1310 attr_name
='bridge-vlan-stats',
1311 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1315 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1316 if not self
._is
_running
_stp
_state
_on
(ifname
):
1317 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1318 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1319 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1320 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1321 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1323 # If stp not specified and running stp state on, set it to off
1324 if self
._is
_running
_stp
_state
_on
(ifname
):
1325 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1326 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1327 except Exception as e
:
1328 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1331 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1333 def _check_vids(self
, ifaceobj
, vids
):
1338 va
, vb
= v
.split('-')
1339 va
, vb
= int(va
), int(vb
)
1340 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1343 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1344 except exceptions
.ReservedVlanException
as e
:
1347 self
.logger
.warn('%s: unable to parse vid \'%s\''
1348 %(ifaceobj
.name
, v
))
1351 def _get_running_pvid(self
, ifacename
):
1354 running_vidinfo
= self
._get
_running
_vidinfo
()
1355 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1356 v
= vinfo
.get('vlan')
1357 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1362 def _get_running_vids_n_pvid_str(self
, ifacename
):
1366 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1369 ret_vids
= self
._compress
_into
_ranges
(vids
)
1374 ret_pvid
= '%s' %pvid
1377 return (ret_vids
, ret_pvid
)
1379 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1381 """ This method is a combination of methods _apply_bridge_vids and
1382 _apply_bridge_port_pvids above. A combined function is
1383 found necessary to do the deletes first and the adds later
1384 because kernel does honor vid info flags during deletes.
1387 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1388 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1389 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1390 bportifaceobj
.upperifaces
[0])
1393 vids_int
= self
._ranges
_to
_ints
(vids
)
1395 pvid_int
= int(pvid
) if pvid
else 0
1397 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1398 %(bportifaceobj
.name
, pvid
))
1403 vids_to_add
= vids_int
1405 pvid_to_add
= pvid_int
1408 if not self
._check
_vids
(bportifaceobj
, vids
):
1411 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1414 if not running_vids
and not running_pvid
:
1415 # There cannot be a no running pvid.
1416 # It might just not be in our cache:
1417 # this can happen if at the time we were
1418 # creating the bridge vlan cache, the port
1419 # was not part of the bridge. And we need
1420 # to make sure both vids and pvid is not in
1421 # the cache, to declare that our cache may
1427 (vids_to_del
, vids_to_add
) = \
1428 self
._diff
_vids
(vids_to_add
, running_vids
)
1431 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1432 pvid_to_del
= running_pvid
1434 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1435 (pvid_to_del
not in vids_to_add
)):
1436 # kernel deletes dont take into account
1437 # bridge vid flags and its possible that
1438 # the pvid deletes we do end up deleting
1439 # the vids. Be proactive and add the pvid
1440 # to the vid add list if it is in the vids
1441 # and not already part of vids_to_add.
1442 # This helps with a small corner case:
1446 # - new change is going to move the state to
1449 vids_to_add
.add(pvid_to_del
)
1450 except exceptions
.ReservedVlanException
as e
:
1452 except Exception, e
:
1453 self
.log_error('%s: failed to process vids/pvids'
1454 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1455 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1456 bportifaceobj
, raise_error
=False)
1459 if pvid_to_add
in vids_to_del
:
1460 vids_to_del
.remove(pvid_to_add
)
1461 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1462 self
._compress
_into
_ranges
(
1463 vids_to_del
), isbridge
)
1464 except Exception, e
:
1465 self
.log_warn('%s: failed to del vid `%s` (%s)'
1466 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1470 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1472 except Exception, e
:
1473 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1474 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1478 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1479 self
._compress
_into
_ranges
(
1480 vids_to_add
), isbridge
)
1481 except Exception, e
:
1482 self
.log_error('%s: failed to set vid `%s` (%s)'
1483 %(bportifaceobj
.name
, str(vids_to_add
),
1484 str(e
)), bportifaceobj
, raise_error
=False)
1487 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1488 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1490 except Exception, e
:
1491 self
.log_error('%s: failed to set pvid `%s` (%s)'
1492 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1495 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1502 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1504 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1506 allow_untagged
= 'yes'
1507 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1509 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1511 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1513 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1515 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1517 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1522 vids_final
= bridge_vids
1524 if allow_untagged
== 'yes':
1526 pvid_final
= pvids
[0]
1528 pvid_final
= bridge_pvid
1534 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1537 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1540 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1541 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1542 # Old style bridge port vid info
1543 # skip new style setting on ports
1545 self
.logger
.info('%s: applying bridge configuration '
1546 %ifaceobj
.name
+ 'specific to ports')
1548 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1550 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1554 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1556 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1560 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1561 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1562 port_processed_override
= True
1564 port_processed_override
= False
1566 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1568 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1570 self
.ipcmd
.batch_start()
1571 for bport
in bridgeports
:
1572 # Use the brctlcmd bulk set method: first build a dictionary
1574 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1575 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1576 ' for port %s (missing port)' %bport
)
1578 self
.logger
.info('%s: processing bridge config for port %s'
1579 %(ifaceobj
.name
, bport
))
1580 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1581 if not bportifaceobjlist
:
1583 for bportifaceobj
in bportifaceobjlist
:
1584 # Dont process bridge port if it already has been processed
1585 # and there is no override on port_processed
1586 if (not port_processed_override
and
1587 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1588 bridgeFlags
.PORT_PROCESSED
)):
1591 # Add attributes specific to the vlan aware bridge
1592 if bridge_vlan_aware
:
1593 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1594 bportifaceobj
, bridge_vids
, bridge_pvid
)
1595 elif self
.warn_on_untagged_bridge_absence
:
1596 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1597 except exceptions
.ReservedVlanException
as e
:
1599 except Exception, e
:
1601 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1603 self
.ipcmd
.bridge_batch_commit()
1605 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1607 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1608 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1609 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1610 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1611 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1612 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1613 self
.warn_on_untagged_bridge_absence
= False
1615 def bridge_port_get_bridge_name(self
, ifaceobj
):
1616 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1618 # bridge port is not enslaved to a bridge we need to find
1619 # the bridge in it's upper ifaces then enslave it
1620 for u
in ifaceobj
.upperifaces
:
1621 if self
.ipcmd
.is_bridge(u
):
1624 # return should_enslave port, bridgename
1625 return False, bridgename
1627 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1628 if should_enslave_port
:
1629 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1630 self
.handle_ipv6([ifaceobj
.name
], '1')
1632 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1633 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1635 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1636 except Exception as e
:
1637 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1640 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1641 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1644 # bridge doesn't exist
1647 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1648 if vlan_aware_bridge
:
1649 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1652 should_enslave_port
)
1654 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1656 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1657 ifaceobj
=bridge_ifaceobj
,
1658 ifaceobj_getfunc
=ifaceobj_getfunc
,
1659 bridge_vlan_aware
=vlan_aware_bridge
)
1661 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1663 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1664 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1665 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1668 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1673 def parse_interface_list_value(user_config
):
1675 for entry
in user_config
.split():
1676 ifname
, value
= entry
.split('=')
1677 config
[ifname
] = value
1680 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1681 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1683 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1685 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1687 Checks are not performed in this function and must be verified
1688 before. This is done this way to avoid calling this method on
1689 non vlan & bridge port interfaces thus wasting a bit less time
1695 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1696 # if the user explicitly defined vxlan-learning we need to honor his config
1697 # and not sync vxlan-learning with bridge-learning
1699 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1701 # if BRIDGE_LEARNING is in the desired configuration
1702 # and differs from the running vxlan configuration
1703 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1705 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1706 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1707 % (bridge_name
, brport_name
, brport_learning
))
1709 elif brport_learning
is None and bridge_vlan_aware
:
1710 # is bridge-learning is not configured but the bridge is vlan-aware
1712 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1713 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1715 if default_value
!= running_value
:
1716 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1718 if not brport_vxlan_learning_config
:
1720 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1721 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1722 % (bridge_name
, brport_name
, default_value
))
1724 # if kind and ifla_info_data are set they will be added to the
1725 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1726 return kind
, ifla_info_data
1728 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1730 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1731 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1732 'is not supported on a non-vxlan port'
1733 % (ifaceobj
.name
, brport_name
))
1735 elif (bridge_vlan_aware
and
1736 (not self
.arp_nd_suppress_only_on_vxlan
or
1737 (self
.arp_nd_suppress_only_on_vxlan
and
1738 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1739 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1742 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1743 ifname
= ifaceobj
.name
1746 brports_ifla_info_slave_data
= dict()
1747 brport_ifaceobj_dict
= dict()
1749 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1753 for brport_name
in target_ports
:
1754 if brport_name
not in running_brports
:
1755 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1757 new_targets
.append(brport_name
)
1758 running_brports
= new_targets
1760 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1762 # If target_ports is specified we want to configure only this
1763 # sub-list of port we need to check if these ports are already
1764 # enslaved, if not they will be ignored.
1765 # If target_ports is not populated we will apply the brport
1766 # attributes on all running brport.
1768 for port
in running_brports
:
1769 brport_list
= ifaceobj_getfunc(port
)
1771 brport_ifaceobj_dict
[port
] = brport_list
[0]
1772 brports_ifla_info_slave_data
[port
] = dict()
1774 bridge_ports_learning
= {}
1776 # we iterate through all IFLA_BRPORT supported attributes
1777 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1778 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1779 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1781 if not translate_func
:
1782 # if no translation function is found,
1783 # we ignore this attribute and continue
1787 # user didn't specify any value for this attribute
1788 # looking at policy overrides
1789 br_config
= policymanager
.policymanager_api
.get_iface_default(
1790 module_name
=self
.__class
__.__name
__,
1796 #if bridge_vlan_aware:
1797 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1798 # 'should be configured under the ports'
1799 # % (ifname, attr_name, br_config))
1801 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1802 # brport_name: { attr: value }
1804 # bridge-portprios swp1=5 swp2=32
1805 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1806 if '=' in br_config
:
1808 br_config
= self
.parse_interface_list_value(br_config
)
1810 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1813 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1814 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1815 brport_name
= brport_ifaceobj
.name
1817 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1818 # if the port has just been enslaved, info_slave_data is not cached yet
1819 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1823 if not brport_config
:
1824 # if a brport attribute was specified under the bridge and not under the port
1825 # we assign the bridge value to the port. If an attribute is both defined under
1826 # the bridge and the brport we keep the value of the port and ignore the br val.
1827 if type(br_config
) == dict:
1828 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1829 # br_config is a dictionary, example:
1830 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1831 brport_config
= br_config
.get(brport_name
)
1833 brport_config
= br_config
1835 if not brport_config
:
1836 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1837 module_name
=self
.__class
__.__name
__,
1842 user_config
= brport_config
1844 # attribute specific work
1845 # This shouldn't be here but we don't really have a choice otherwise this
1846 # will require too much code duplication and will make the code very complex
1847 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1849 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1855 user_config
= arp_suppress
1858 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1859 # special handking for group_fwd_mask because Cisco proprietary
1860 # protocol needs to be set via a private netlink attribute
1861 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1862 brports_ifla_info_slave_data
,
1863 user_config
, cached_value
)
1867 # if not bridge_vlan_aware:
1868 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1869 # 'should be configured under the bridge'
1870 # % (ifname, brport_name,
1871 # attr_name, brport_config))
1874 user_config_nl
= translate_func(user_config
)
1875 # check config value against running value
1876 if user_config_nl
!= cached_value
:
1877 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1878 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1879 self
.logger
.debug('(cache %s)' % cached_value
)
1881 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1882 # for vxlan-learning sync purposes we need to save the user config for each brports.
1883 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1884 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1885 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1886 # the brport since it might go out of sync for X and Y reasons.
1887 bridge_ports_learning
[brport_name
] = user_config_nl
1889 elif cached_value
is not None:
1890 # no config found, do we need to reset to default?
1891 default
= self
.get_attr_default_value(attr_name
)
1893 default_netlink
= translate_func(default
)
1895 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1896 and not ifupdownflags
.flags
.PERFMODE
1897 and brport_name
not in newly_enslaved_ports
):
1899 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1900 if default_netlink
!= cached_value
:
1901 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1902 % (ifname
, brport_name
))
1904 bridge_ports_learning
[brport_name
] = default_netlink
1905 except Exception as e
:
1906 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1908 if default_netlink
!= cached_value
:
1909 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1910 % (ifname
, brport_name
, attr_name
, default
))
1911 self
.logger
.debug('(cache %s)' % cached_value
)
1912 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1914 # applying bridge port configuration via netlink
1915 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1917 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1919 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1920 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1921 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1922 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1923 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1927 brport_ifla_info_slave_data
,
1928 bridge_ports_learning
.get(brport_name
))
1933 if brport_ifla_info_slave_data
or ifla_info_data
:
1935 netlink
.link_add_set(ifname
=brport_name
,
1937 ifla_info_data
=ifla_info_data
,
1938 slave_kind
='bridge',
1939 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1940 except Exception as e
:
1941 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1943 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1944 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1945 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1947 except Exception as e
:
1948 self
.log_error(str(e
), ifaceobj
)
1950 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1952 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1953 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1954 field we need to have special handling for that.
1956 ifla_brport_group_fwd_mask
= 0
1957 ifla_brport_group_fwd_maskhi
= 0
1959 for group
in re
.split(',|\s*', user_config
):
1963 callback
= self
.l2protocol_tunnel_callback
.get(group
)
1965 if not callable(callback
):
1966 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
1968 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
1970 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
1971 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
1973 log_mask_change
= True
1974 # if user specify bridge-l2protocol-tunnel stp cdp
1975 # we need to set both MASK and MASKHI but we only want to log once
1977 if cached_ifla_brport_group_fwd_mask
is None:
1978 cached_ifla_brport_group_fwd_mask
= 0
1979 if cached_ifla_brport_group_fwd_maskhi
is None:
1980 cached_ifla_brport_group_fwd_maskhi
= 0
1982 # if the cache value is None it means that the kernel doesn't support this attribute
1983 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
1985 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
1987 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
1988 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
1989 log_mask_change
= False
1990 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
1992 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
1994 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
1995 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
1996 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
1998 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
1999 ifname
= ifaceobj
.name
2001 if ifupdownflags
.flags
.PERFMODE
:
2002 link_just_created
= True
2005 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2006 link_just_created
= not link_exists
2009 netlink
.link_add_bridge(ifname
)
2011 self
.logger
.info('%s: bridge already exists' % ifname
)
2013 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2015 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2018 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2019 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2020 newly_enslaved_ports
=newly_enslaved_ports
)
2021 except Exception as e
:
2022 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2026 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2027 if not running_ports
:
2029 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2030 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2031 ifaceobj_getfunc
=ifaceobj_getfunc
,
2032 bridge_vlan_aware
=bridge_vlan_aware
)
2033 except exceptions
.ReservedVlanException
as e
:
2035 except Exception as e
:
2036 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2038 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2039 for p
in running_ports
:
2040 if (ifaceobj_getfunc(p
)[0].link_privflags
&
2041 ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2042 netlink
.link_set_updown(p
, "down")
2045 netlink
.link_set_updown(p
, "up")
2046 except Exception, e
:
2047 self
.logger
.debug('%s: %s: link set up (%s)'
2048 % (ifaceobj
.name
, p
, str(e
)))
2052 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2053 except Exception as e
:
2054 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2056 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2057 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2058 return self
.bridge_mac_iface
2060 if self
.bridge_mac_iface_list
:
2061 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2063 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2064 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2068 for obj
in ifaceobj_list
:
2069 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2070 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2071 if iface_user_configured_hwaddress
:
2072 iface_mac
= iface_user_configured_hwaddress
2074 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2078 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2079 # if hwaddress attribute is not configured we use the running mac addr
2081 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2082 return self
.bridge_mac_iface
2083 elif self
.bridge_set_static_mac_from_port
:
2084 # no policy was provided, we need to get the first physdev or bond ports
2085 # and use its hwaddress to set the bridge mac
2086 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2087 # iterate through the bridge-port list
2088 for port_obj
in ifaceobj_getfunc(port
) or []:
2089 # check if the port is a physdev (link_kind is null) or a bon
2090 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2091 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2092 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2093 if iface_user_configured_hwaddress
:
2094 iface_mac
= iface_user_configured_hwaddress
.lower()
2095 # we need to "normalize" the user provided MAC so it can match with
2096 # what we have in the cache (data retrieved via a netlink dump by
2097 # nlmanager). nlmanager return all macs in lower-case
2099 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2102 self
.bridge_mac_iface
= (port
, iface_mac
)
2103 return self
.bridge_mac_iface
2107 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2108 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2109 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2111 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2113 We have a day one bridge mac changing problem with changing ports
2114 (basically bridge mac changes when the port it inherited the mac from
2117 We have discussed this problem many times before and tabled it.
2118 The issue has aggravated with vxlan bridge ports having auto-generated
2119 random macs...which change on every reboot.
2121 ifupdown2 extract from policy files an iface to select a mac from and
2122 configure it automatically.
2124 if ifaceobj
.get_attr_value('hwaddress'):
2125 # if the user configured a static hwaddress
2126 # there is no need to assign one
2129 ifname
= ifaceobj
.name
2130 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2131 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2132 %(ifname
, mac_intf
, bridge_mac
))
2135 # if an interface is configured with the following attribute:
2136 # hwaddress 08:00:27:42:42:4
2137 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2138 # from the kernel. The only way to counter that is to convert all mac to int
2139 # and compare the ints, it will increase perfs and be safer.
2140 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2141 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2142 if cached_value
and cached_value
== bridge_mac
:
2143 # the bridge mac is already set to the bridge_mac_intf's mac
2146 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2148 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2149 except Exception as e
:
2150 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2151 # log info this error because the user didn't explicitly configured this
2153 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2155 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2156 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2157 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2159 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2160 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2162 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2163 if not self
._is
_bridge
(ifaceobj
):
2165 ifname
= ifaceobj
.name
2166 if not self
.ipcmd
.link_exists(ifname
):
2169 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2171 self
.handle_ipv6(running_ports
, '0')
2172 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2173 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2174 except Exception as e
:
2175 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2177 netlink
.link_del(ifname
)
2178 except Exception as e
:
2179 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2180 self
.logger
.error(str(e
))
2181 # netlink exception already contains the ifname
2183 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2186 running_bridge_port_vids
= ''
2189 running_vids
= self
._get
_runing
_vids
(p
)
2191 running_bridge_port_vids
+= ' %s=%s' %(p
,
2192 ','.join(running_vids
))
2195 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2197 running_bridge_port_pvid
= ''
2200 running_pvid
= self
._get
_runing
_pvid
(p
)
2202 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2206 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2208 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2209 if running_bridge_vids
:
2210 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2211 return running_attrs
2213 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2217 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2218 # so query the ports
2219 running_bridgeport_vids
= []
2220 running_bridgeport_pvids
= []
2221 for bport
in bridgeports
:
2222 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2224 running_bridgeport_vids
.append(' '.join(vids
))
2226 running_bridgeport_pvids
.append(pvid
)
2229 if running_bridgeport_vids
:
2230 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2231 if freq
== len(bridgeports
):
2232 running_attrs
['bridge-vids'] = vidval
2233 bridge_vids
= vidval
.split()
2236 if running_bridgeport_pvids
:
2237 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2238 if freq
== len(bridgeports
) and vidval
!= '1':
2239 running_attrs
['bridge-pvid'] = vidval
2240 bridge_pvid
= vidval
.split()[0]
2242 # Go through all bridge ports and find their vids
2243 for bport
in bridgeports
:
2244 bportifaceobj
= ifaceobj_getfunc(bport
)
2245 if not bportifaceobj
:
2249 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2250 if vids
and vids
!= bridge_vids
:
2252 if pvid
and pvid
!= bridge_pvid
:
2254 if bport_vids
and bport_pvid
in bport_vids
:
2255 bport_vids
.remove(bport_pvid
)
2256 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2257 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2258 bportifaceobj
[0].delete_config('bridge-pvid')
2259 bportifaceobj
[0].delete_config('bridge-vids')
2261 if bport_pvid
and bport_pvid
!= '1':
2262 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2264 # delete any stale bridge-vids under ports
2265 bportifaceobj
[0].delete_config('bridge-pvid')
2267 bportifaceobj
[0].replace_config('bridge-vids',
2268 ' '.join(bport_vids
))
2270 # delete any stale bridge-vids under ports
2271 bportifaceobj
[0].delete_config('bridge-vids')
2272 return running_attrs
2274 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2275 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobjrunning
.name
)
2276 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2278 mcq
= ' '.join(mcqs
)
2281 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2282 bridge_vlan_aware
=False):
2286 skip_kernel_stp_attrs
= 0
2289 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2291 except Exception as e
:
2292 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2294 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2295 if not tmpbridgeattrdict
:
2296 self
.logger
.warn('%s: unable to get bridge attrs'
2297 %ifaceobjrunning
.name
)
2298 return bridgeattrdict
2300 # Fill bridge_ports and bridge stp attributes first
2301 ports
= tmpbridgeattrdict
.get('ports')
2303 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2304 stp
= tmpbridgeattrdict
.get('stp', 'no')
2305 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2306 bridgeattrdict
['bridge-stp'] = [stp
]
2308 if stp
== 'yes' and userspace_stp
:
2309 skip_kernel_stp_attrs
= 1
2311 vlan_stats
= utils
.get_onff_from_onezero(
2312 tmpbridgeattrdict
.get('vlan-stats', None))
2314 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2315 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2317 bool2str
= {'0': 'no', '1': 'yes'}
2318 # pick all other attributes
2319 for k
,v
in tmpbridgeattrdict
.items():
2322 if k
== 'ports' or k
== 'stp':
2325 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2326 # only include igmp attributes if kernel stp is off
2328 attrname
= 'bridge-' + k
2329 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2330 if v
!= mod_default
:
2331 # convert '0|1' running values to 'no|yes'
2332 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2334 bridgeattrdict
[attrname
] = [v
]
2336 if bridge_vlan_aware
:
2339 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2343 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2346 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2349 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2351 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2353 if skip_kernel_stp_attrs
:
2354 return bridgeattrdict
2356 # Do this only for vlan-UNAWARE-bridge
2357 if ports
and not bridge_vlan_aware
:
2358 portconfig
= {'bridge-pathcosts' : '',
2359 'bridge-portprios' : '',
2360 'bridge-learning' : '',
2361 'bridge-unicast-flood' : '',
2362 'bridge-multicast-flood' : '',
2363 'bridge-arp-nd-suppress' : '',
2365 for p
, v
in ports
.items():
2366 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2367 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2369 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2371 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2372 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2374 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2376 v
= utils
.get_onff_from_onezero(
2377 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2380 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2381 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2383 v
= utils
.get_onff_from_onezero(
2384 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2385 p
, 'unicast-flood'))
2387 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2389 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2391 v
= utils
.get_onff_from_onezero(
2392 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2393 p
, 'multicast-flood'))
2395 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2397 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2399 v
= utils
.get_onff_from_onezero(
2400 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2401 p
, 'arp-nd-suppress'))
2403 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2405 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2407 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2410 return bridgeattrdict
2412 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2413 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2414 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2416 mcqs
= attrval
.split()
2418 mcqsout
= ' '.join(mcqs
)
2419 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2420 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2422 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2424 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2426 running_bridge_port_vids
= ''
2427 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2429 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2430 %(ifaceobj
.name
, attrval
))
2435 (port
, val
) = p
.split('=')
2436 vids
= val
.split(',')
2437 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2439 if not self
._compare
_vids
(vids
, running_vids
):
2441 running_bridge_port_vids
+= ' %s=%s' %(port
,
2442 ','.join(running_vids
))
2444 running_bridge_port_vids
+= ' %s' %p
2447 except Exception, e
:
2448 self
.log_warn('%s: failure checking vid %s (%s)'
2449 %(ifaceobj
.name
, p
, str(e
)))
2451 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2452 running_bridge_port_vids
, 1)
2454 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2457 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2459 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2461 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2462 %(ifaceobj
.name
, attrval
))
2464 running_bridge_port_pvids
= ''
2468 (port
, pvid
) = p
.split('=')
2469 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2470 if running_pvid
and running_pvid
== pvid
:
2471 running_bridge_port_pvids
+= ' %s' %p
2474 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2476 except Exception, e
:
2477 self
.log_warn('%s: failure checking pvid %s (%s)'
2478 %(ifaceobj
.name
, pvid
, str(e
)))
2480 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2481 running_bridge_port_pvids
, 1)
2483 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2484 running_bridge_port_pvids
, 0)
2486 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2488 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2490 def _query_check_snooping_wdefault(self
, ifaceobj
):
2491 if (ifupdownflags
.flags
.WITHDEFAULTS
2492 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2493 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2494 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2496 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2497 ifaceobj_getfunc
=None):
2498 if not self
._is
_bridge
(ifaceobj
):
2500 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2501 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2504 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2506 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2507 self
.get_mod_attrs())
2508 #Add default attributes if --with-defaults is set
2509 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2510 ifaceattrs
.append('bridge-stp')
2514 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2515 if not runningattrs
:
2516 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2519 except Exception, e
:
2520 self
.logger
.warn(str(e
))
2523 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2525 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2526 'bridge-port-pvids']
2528 diff
= Set(ifaceattrs
).difference(filterattrs
)
2530 if 'bridge-l2protocol-tunnel' in diff
:
2531 diff
.remove('bridge-l2protocol-tunnel')
2532 # bridge-l2protocol-tunnel requires separate handling
2535 # get the corresponding ifaceobj attr
2536 v
= ifaceobj
.get_attr_value_first(k
)
2538 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2539 v
= 'on' if self
.default_stp_on
else 'off'
2542 rv
= runningattrs
.get(k
[7:])
2543 if k
== 'bridge-mcqv4src':
2545 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2546 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2548 if k
== 'bridge-vlan-aware':
2549 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2550 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2551 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2554 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2556 elif k
== 'bridge-stp':
2557 # special case stp compare because it may
2558 # contain more than one valid values
2559 stp_on_vals
= ['on', 'yes']
2560 stp_off_vals
= ['off', 'no']
2561 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2562 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2563 ifaceobjcurr
.update_config_with_status('bridge-stp',
2566 ifaceobjcurr
.update_config_with_status('bridge-stp',
2568 elif k
== 'bridge-ports':
2569 # special case ports because it can contain regex or glob
2570 running_port_list
= rv
.keys() if rv
else []
2571 bridge_port_list
= self
._get
_bridge
_port
_list
(ifaceobj
)
2572 if not running_port_list
and not bridge_port_list
:
2575 if running_port_list
and bridge_port_list
:
2576 difference
= set(running_port_list
2577 ).symmetric_difference(bridge_port_list
)
2581 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
,
2583 # we want to display the same bridge-ports list as provided
2584 # in the interfaces file but if this list contains regexes or
2585 # globs, for now, we won't try to change it.
2586 if 'regex' in port_list
or 'glob' in port_list
:
2587 port_list
= running_port_list
2590 for i
in range(0, len(port_list
)):
2591 if port_list
[i
] in running_port_list
:
2592 ordered
.append(port_list
[i
])
2595 port_list
= running_port_list
2596 ifaceobjcurr
.update_config_with_status('bridge-ports',
2597 (' '.join(port_list
)
2598 if port_list
else ''),
2600 elif k
in ['bridge-pathcosts',
2602 'bridge-portmcrouter',
2605 'bridge-unicast-flood',
2606 'bridge-multicast-flood',
2607 'bridge-arp-nd-suppress',
2609 if k
== 'bridge-arp-nd-suppress':
2610 brctlcmdattrname
= k
[7:]
2612 brctlcmdattrname
= k
[7:].rstrip('s')
2613 # for port attributes, the attributes are in a list
2614 # <portname>=<portattrvalue>
2617 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2620 for vlistitem
in vlist
:
2622 (p
, v
) = vlistitem
.split('=')
2623 if k
in ['bridge-learning',
2624 'bridge-unicast-flood',
2625 'bridge-multicast-flood',
2626 'bridge-arp-nd-suppress',
2628 currv
= utils
.get_onoff_bool(
2629 self
.brctlcmd
.get_bridgeport_attr(
2633 currv
= self
.brctlcmd
.get_bridgeport_attr(
2637 currstr
+= ' %s=%s' %(p
, currv
)
2639 currstr
+= ' %s=%s' %(p
, 'None')
2641 if k
== 'bridge-portmcrouter':
2642 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2646 except Exception, e
:
2647 self
.log_warn(str(e
))
2649 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2650 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2651 rv
= utils
.get_onff_from_onezero(rv
)
2653 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2655 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2657 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2658 # bridge-pvid and bridge-vids on a bridge does
2659 # not correspond directly to a running config
2660 # on the bridge. They correspond to default
2661 # values for the bridge ports. And they are
2662 # already checked against running config of the
2663 # bridge port and reported against a bridge port.
2664 # So, ignore these attributes under the bridge.
2665 # Use '2' for ignore today. XXX: '2' will be
2666 # mapped to a defined value in subsequent patches.
2667 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2669 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2671 elif v
.upper() != rv
.upper():
2672 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2674 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2676 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2678 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2679 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2681 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2682 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2684 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2687 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2688 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2690 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2691 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2692 for ifaceobj
in ifaceobjs
:
2693 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2694 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2697 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2698 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2700 for ifaceobj
in ifaceobjs
:
2701 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2706 def _get_bridge_name(self
, ifaceobj
):
2707 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2709 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2710 ifaceobj_getfunc
, bridgename
):
2711 attr_name
= 'bridge-access'
2712 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2714 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2716 if (not running_pvid
or running_pvid
!= vid
or
2717 (running_vids
and running_vids
[0] != vid
)):
2718 ifaceobjcurr
.update_config_with_status(attr_name
,
2721 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2724 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2726 attr_name
= 'bridge-pvid'
2727 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2729 if running_pvid
and running_pvid
== pvid
:
2730 ifaceobjcurr
.update_config_with_status(attr_name
,
2733 ifaceobjcurr
.update_config_with_status(attr_name
,
2735 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2736 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2737 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2738 # if the interface has multiple iface sections,
2739 # we check the below only for the oldest sibling
2740 # or the last iface section
2741 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2743 if not running_pvid
or running_pvid
!= pvid
:
2744 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2745 ifaceobjcurr
.status_str
= 'bridge pvid error'
2746 elif not running_pvid
or running_pvid
!= '1':
2747 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2748 ifaceobjcurr
.status_str
= 'bridge pvid error'
2750 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2752 vids
= re
.split(r
'[\s\t]\s*', vids
)
2753 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2755 ifaceobjcurr
.update_config_with_status(attr_name
,
2756 ' '.join(running_vids
), 1)
2758 ifaceobjcurr
.update_config_with_status(attr_name
,
2760 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2761 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2762 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2763 # if the interface has multiple iface sections,
2764 # we check the below only for the oldest sibling
2765 # or the last iface section
2767 # check if it matches the bridge vids
2768 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2769 if (bridge_vids
and (not running_vids
or
2770 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2771 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2772 ifaceobjcurr
.status_str
= 'bridge vid error'
2774 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2776 if not self
._is
_bridge
_port
(ifaceobj
):
2777 # Mark all bridge attributes as failed
2778 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2779 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2780 'bridge-pathcosts', 'bridge-portprios',
2781 'bridge-portmcrouter',
2783 'bridge-portmcfl', 'bridge-unicast-flood',
2784 'bridge-multicast-flood',
2785 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2788 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2790 self
.logger
.warn('%s: unable to determine bridge name'
2794 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2795 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2798 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2799 'bridge-portprios' : 'portprio',
2800 'bridge-portmcrouter' : 'portmcrouter',
2801 'bridge-portmcfl' : 'portmcfl',
2802 'bridge-learning' : 'learning',
2803 'bridge-unicast-flood' : 'unicast-flood',
2804 'bridge-multicast-flood' : 'multicast-flood',
2805 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2807 attrval
= ifaceobj
.get_attr_value_first(attr
)
2812 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2813 bridgename
, ifaceobj
.name
, dstattr
)
2815 if dstattr
== 'portmcfl':
2816 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2817 running_attrval
= utils
.get_yesno_boolean(
2818 utils
.get_boolean_from_string(running_attrval
))
2819 elif dstattr
== 'portmcrouter':
2820 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2821 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2823 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2825 elif dstattr
in ['learning',
2830 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2831 running_attrval
= utils
.get_onff_from_onezero(
2834 if running_attrval
!= attrval
:
2835 ifaceobjcurr
.update_config_with_status(attr
,
2838 ifaceobjcurr
.update_config_with_status(attr
,
2840 except Exception, e
:
2841 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2843 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2845 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2846 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2848 if user_config_l2protocol_tunnel
:
2851 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2852 except Exception as e
:
2853 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2855 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2857 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2859 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2860 We need to make sure that all ports comply with the mask given under the bridge
2862 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2864 if user_config_l2protocol_tunnel
:
2865 if '=' in user_config_l2protocol_tunnel
:
2867 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2868 brport_list
= config_per_port_dict
.keys()
2870 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2873 config_per_port_dict
= {}
2874 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2877 for brport_name
in brport_list
:
2878 self
._query
_check
_l2protocol
_tunnel
(
2880 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2883 except Exception as e
:
2884 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2886 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2888 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2889 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2890 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2892 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2893 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2895 if callable(callback
):
2896 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2897 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2898 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2900 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2901 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2902 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2903 running_protocols
= []
2904 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2905 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2906 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2907 running_protocols
.remove('all')
2909 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2910 running_protocols
.append(protocol_name
)
2911 if running_protocols
:
2913 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2914 elif bridge_ifaceobj
:
2915 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2918 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2920 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2922 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2923 if self
._is
_bridge
(ifaceobj
):
2924 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
)
2926 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2929 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2930 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2931 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2932 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2935 bridge_vlan_aware
=True))
2937 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2938 ifaceobjrunning
, None))
2940 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2941 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2944 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2945 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2946 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2948 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2949 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
2950 ifaceobjrunning
.update_config('bridge-portprios', v
)
2952 def _query_running_bridge_port(self
, ifaceobjrunning
,
2953 ifaceobj_getfunc
=None):
2955 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
2956 ifaceobjrunning
.name
)
2960 self
.logger
.warn('%s: unable to find bridgename'
2961 %ifaceobjrunning
.name
)
2964 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2966 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
2967 except Exception as e
:
2968 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
2971 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
2973 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2974 ifaceobjrunning
.name
)
2975 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
2976 bridge_port_vids
.remove(bridge_port_pvid
)
2978 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
2979 if bridgeifaceobjlist
:
2980 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
2981 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
2983 if not bridge_port_vids
and bridge_port_pvid
:
2984 # must be an access port
2985 if bridge_port_pvid
!= '1':
2986 ifaceobjrunning
.update_config('bridge-access',
2989 if bridge_port_vids
:
2990 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
2991 ifaceobjrunning
.update_config('bridge-vids',
2992 ' '.join(bridge_port_vids
))
2993 if bridge_port_pvid
and bridge_port_pvid
!= '1':
2994 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
2995 ifaceobjrunning
.update_config('bridge-pvid',
2998 v
= utils
.get_onff_from_onezero(
2999 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3000 ifaceobjrunning
.name
,
3002 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3003 ifaceobjrunning
.update_config('bridge-learning', v
)
3005 v
= utils
.get_onff_from_onezero(
3006 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3007 ifaceobjrunning
.name
,
3009 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3010 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3012 v
= utils
.get_onff_from_onezero(
3013 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3014 ifaceobjrunning
.name
,
3016 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3017 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3019 v
= utils
.get_onff_from_onezero(
3020 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3021 ifaceobjrunning
.name
,
3023 # Display running 'arp-nd-suppress' only on vxlan ports
3024 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3025 # otherwise, display on all bridge-ports
3027 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3029 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3030 (not self
.arp_nd_suppress_only_on_vxlan
or
3031 (self
.arp_nd_suppress_only_on_vxlan
and
3032 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3033 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3035 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3037 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3039 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3040 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3041 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3042 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3043 except Exception as e
:
3044 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3046 def _query(self
, ifaceobj
, **kwargs
):
3047 """ add default policy attributes supported by the module """
3048 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3049 ifaceobj
.get_attr_value_first('bridge-stp')):
3051 if self
.default_stp_on
:
3052 ifaceobj
.update_config('bridge-stp', 'yes')
3054 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3055 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3056 ['mcquerier', 'bridge-mcquerier'],
3057 ['mcsnoop', 'bridge-mcsnoop']]:
3058 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3059 if value
and not utils
.is_binary_bool(value
):
3060 if attrl
[0] in runningattrs
:
3061 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3062 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3064 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3065 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3066 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3067 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3068 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3069 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3071 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3073 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3075 if 'mcrouter' in running_attrs
:
3076 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3081 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3083 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3085 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3089 (port
, val
) = p
.split('=')
3090 if not utils
.is_binary_bool(val
):
3091 to_convert
.append(port
)
3092 for port
in to_convert
:
3093 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3094 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3099 'query-checkcurr': _query_check
,
3100 'query-running': _query_running
,
3105 """ returns list of ops supported by this module """
3106 return self
._run
_ops
.keys()
3108 def _init_command_handlers(self
):
3110 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3112 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3113 """ run bridge configuration on the interface object passed as
3114 argument. Can create bridge interfaces if they dont exist already
3117 **ifaceobj** (object): iface object
3119 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3123 **query_ifaceobj** (object): query check ifaceobject. This is only
3124 valid when op is 'query-checkcurr'. It is an object same as
3125 ifaceobj, but contains running attribute values and its config
3126 status. The modules can use it to return queried running state
3127 of interfaces. status is success if the running state is same
3128 as user required state in ifaceobj. error otherwise.
3130 op_handler
= self
._run
_ops
.get(operation
)
3133 self
._init
_command
_handlers
()
3135 if (not LinkUtils
.bridge_utils_is_installed
3136 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3137 and LinkUtils
.bridge_utils_missing_warning
):
3138 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3139 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3140 LinkUtils
.bridge_utils_missing_warning
= False
3142 if operation
== 'query-checkcurr':
3143 op_handler(self
, ifaceobj
, query_ifaceobj
,
3144 ifaceobj_getfunc
=ifaceobj_getfunc
)
3146 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)