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
):
818 for brport
in ifaceobj
.get_attr_value('bridge-ports') or []:
820 bridge_ports
.extend(brport
.split())
822 return ' '.join(bridge_ports
)
824 def _is_bridge_port(self
, ifaceobj
):
825 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
829 def check_valid_bridge(self
, ifaceobj
, ifname
):
830 if LinkUtils
.link_exists(ifname
) and not LinkUtils
.is_bridge(ifname
):
831 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
835 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
836 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
838 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
839 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
840 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
841 # for special vlan aware bridges, we need to add another bit
842 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
843 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
844 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
845 ifaceobj
.role |
= ifaceRole
.MASTER
846 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
847 return self
.parse_port_list(ifaceobj
.name
,
848 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
851 def get_dependent_ifacenames_running(self
, ifaceobj
):
852 self
._init
_command
_handlers
()
853 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
855 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
857 def _get_bridge_port_list(self
, ifaceobj
):
859 # port list is also available in the previously
860 # parsed dependent list. Use that if available, instead
861 # of parsing port expr again
862 port_list
= ifaceobj
.lowerifaces
865 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
867 return self
.parse_port_list(ifaceobj
.name
, ports
)
871 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
872 # When enslaving bridge-ports we need to return the exact user
873 # configured bridge ports list (bridge will inherit the mac of the
875 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
876 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
878 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
879 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
880 if not waitport_value
: return
882 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
883 if not waitportvals
: return
885 waitporttime
= int(waitportvals
[0])
887 self
.log_warn('%s: invalid waitport value \'%s\''
888 %(ifaceobj
.name
, waitportvals
[0]))
890 if waitporttime
<= 0: return
892 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
894 except IndexError, e
:
895 # ignore error and use all bridge ports
896 waitportlist
= portlist
898 if not waitportlist
: return
899 self
.logger
.info('%s: waiting for ports %s to exist ...'
900 %(ifaceobj
.name
, str(waitportlist
)))
901 starttime
= time
.time()
902 while ((time
.time() - starttime
) < waitporttime
):
903 if all([False for p
in waitportlist
904 if not self
.ipcmd
.link_exists(p
)]):
908 self
.log_warn('%s: unable to process waitport: %s'
909 %(ifaceobj
.name
, str(e
)))
911 def _enable_disable_ipv6(self
, port
, enable
='1'):
913 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
915 self
.logger
.info(str(e
))
917 def handle_ipv6(self
, ports
, state
, ifaceobj
=None):
919 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
) and
920 not ifaceobj
.get_attr_value('address')):
921 self
._enable
_disable
_ipv
6(ifaceobj
.name
, state
)
923 self
._enable
_disable
_ipv
6(p
, state
)
925 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
926 """ pretty print bridge port add errors.
927 since the commands are batched and the kernel only returns error
928 codes, this function tries to interpret some error codes
929 and prints clearer errors """
931 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
932 # Cumulus Linux specific error checks
934 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
936 for bport
in bridgeports
:
937 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
939 if currvlanid
!= vlanid
:
940 self
.log_error('%s: ' %bridgeifaceobj
.name
+
941 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
945 except Exception as e
:
946 errstr
+= '\n%s' % str(e
)
947 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
949 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
950 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
951 runningbridgeports
= []
953 self
.ipcmd
.batch_start()
954 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
955 self
.ipcmd
.batch_start()
956 # Delete active ports not in the new port list
957 if not ifupdownflags
.flags
.PERFMODE
:
958 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
959 if runningbridgeports
:
960 for bport
in runningbridgeports
:
961 if not bridgeports
or bport
not in bridgeports
:
962 self
.ipcmd
.link_set(bport
, 'nomaster')
963 # set admin DOWN on all removed ports
964 # that don't have config outside bridge
965 if not ifaceobj_getfunc(bport
):
966 netlink
.link_set_updown(bport
, "down")
967 # enable ipv6 for ports that were removed
968 self
.handle_ipv6([bport
], '0')
970 runningbridgeports
= []
972 self
.ipcmd
.batch_commit()
976 newbridgeports
= Set(bridgeports
).difference(Set(runningbridgeports
))
977 newly_enslaved_ports
= []
979 newbridgeports_ordered
= []
980 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
981 if br_port
in newbridgeports
:
982 newbridgeports_ordered
.append(br_port
)
984 for bridgeport
in newbridgeports_ordered
:
986 if (not ifupdownflags
.flags
.DRYRUN
and
987 not self
.ipcmd
.link_exists(bridgeport
)):
988 self
.log_error('%s: bridge port %s does not exist'
989 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
992 hwaddress
= self
.ipcmd
.link_get_hwaddress(bridgeport
)
993 if not self
._valid
_ethaddr
(hwaddress
):
994 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
995 bridgeport
) + 'invalid ether addr %s'
998 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
999 newly_enslaved_ports
.append(bridgeport
)
1000 self
.handle_ipv6([bridgeport
], '1')
1001 self
.ipcmd
.addr_flush(bridgeport
)
1005 self
.ipcmd
.batch_commit()
1006 self
.ipcmd
.batch_start()
1007 except Exception, e
:
1008 self
.logger
.error(str(e
))
1011 self
.ipcmd
.batch_commit()
1012 except Exception, e
:
1013 self
._pretty
_print
_add
_ports
_error
(str(e
), ifaceobj
,
1018 self
.log_error('bridge configuration failed (missing ports)')
1020 return newly_enslaved_ports
1022 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1023 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1024 if not maxwait
: return
1026 maxwait
= int(maxwait
)
1028 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1031 if not maxwait
: return
1032 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1035 starttime
= time
.time()
1036 while ((time
.time() - starttime
) < maxwait
):
1037 if all([False for p
in portlist
1038 if self
.read_file_oneline(
1039 '/sys/class/net/%s/brif/%s/state'
1040 %(ifaceobj
.name
, p
)) != '3']):
1043 except Exception, e
:
1044 self
.log_warn('%s: unable to process maxwait: %s'
1045 %(ifaceobj
.name
, str(e
)))
1047 def _ints_to_ranges(self
, ints
):
1048 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
1050 yield b
[0][1], b
[-1][1]
1052 def _ranges_to_ints(self
, rangelist
):
1053 """ returns expanded list of integers given set of string ranges
1054 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1058 for part
in rangelist
:
1060 a
, b
= part
.split('-')
1061 a
, b
= int(a
), int(b
)
1062 result
.extend(range(a
, b
+ 1))
1067 self
.logger
.warn('unable to parse vids \'%s\''
1068 %''.join(rangelist
))
1072 def _compress_into_ranges(self
, vids_ints
):
1073 return ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
1074 for start
, end
in self
._ints
_to
_ranges
(vids_ints
)]
1076 def _diff_vids(self
, vids1_ints
, vids2_ints
):
1077 return Set(vids2_ints
).difference(vids1_ints
), Set(vids1_ints
).difference(vids2_ints
)
1079 def _compare_vids(self
, vids1
, vids2
, pvid
=None):
1080 """ Returns true if the vids are same else return false """
1082 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
1083 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
1084 set_diff
= Set(vids1_ints
).symmetric_difference(vids2_ints
)
1085 if pvid
and int(pvid
) in set_diff
:
1086 set_diff
.remove(int(pvid
))
1092 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1094 # Sets old style igmp querier
1096 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1098 running_mcqv4src
= {}
1099 if not ifupdownflags
.flags
.PERFMODE
:
1100 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1102 srclist
= attrval
.split()
1107 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
1109 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1110 for v
in mcqs
.keys():
1111 self
.brctlcmd
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1112 elif not ifupdownflags
.flags
.PERFMODE
:
1113 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1114 if running_mcqv4src
:
1115 for v
in running_mcqv4src
.keys():
1116 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1118 def _get_running_vidinfo(self
):
1119 if self
._running
_vidinfo
_valid
:
1120 return self
._running
_vidinfo
1121 self
._running
_vidinfo
= {}
1123 # Removed check for PERFMODE. Need the get in all cases
1124 # including reboot, so that we can configure the pvid correctly.
1125 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all_json()
1126 self
._running
_vidinfo
_valid
= True
1127 return self
._running
_vidinfo
1129 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1131 # Supports old style vlan vid info format
1134 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1135 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1136 if not bridge_port_pvids
and not bridge_port_vids
:
1139 # Handle bridge vlan attrs
1141 if bridge_port_pvids
:
1142 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1144 self
.log_warn('%s: could not parse \'%s %s\''
1145 %(ifaceobj
.name
, 'bridge-port-pvids',
1150 (port
, pvid
) = p
.split('=')
1152 running_pvid
= self
._get
_running
_pvid
(port
)
1154 if running_pvid
== pvid
:
1157 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
1158 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
1159 except Exception, e
:
1160 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1161 %(ifaceobj
.name
, p
, str(e
)))
1164 if bridge_port_vids
:
1165 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1167 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1168 'bridge-port-vids', bridge_port_vids
))
1172 (port
, val
) = p
.split('=')
1173 vids
= val
.split(',')
1174 vids_int
= self
._ranges
_to
_ints
(vids
)
1175 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
1177 (vids_to_del
, vids_to_add
) = \
1178 self
._diff
_vids
(vids_int
, running_vids
)
1180 self
.ipcmd
.bridge_port_vids_del(port
,
1181 self
._compress
_into
_ranges
(vids_to_del
))
1183 self
.ipcmd
.bridge_port_vids_add(port
,
1184 self
._compress
_into
_ranges
(vids_to_add
))
1186 self
.ipcmd
.bridge_port_vids_add(port
, vids_int
)
1187 except Exception, e
:
1188 self
.log_warn('%s: failed to set vid `%s` (%s)'
1189 %(ifaceobj
.name
, p
, str(e
)))
1191 def _is_running_stp_state_on(self
, bridgename
):
1192 """ Returns True if running stp state is on, else False """
1194 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1196 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1197 return running_stp_state
and running_stp_state
!= '0'
1201 def _is_config_stp_state_on(self
, ifaceobj
):
1202 """ Returns true if user specified stp state is on, else False """
1204 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1206 return self
.default_stp_on
1207 return utils
.get_boolean_from_string(stp_attr
)
1209 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1210 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1211 if not mcsnoop
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1212 return self
._vxlan
_bridge
_default
_igmp
_snooping
1215 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1223 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1225 if not callable(translate_func
):
1229 user_config
= policymanager
.policymanager_api
.get_iface_default(
1230 module_name
=self
.__class
__.__name
__,
1235 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1236 if old_cache_key
and not link_just_created
:
1237 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1238 if not cached_value
:
1239 # the link already exists but we don't have any value
1240 # cached for this attr, it probably means that the
1241 # capability is not available on this system (i.e old kernel)
1242 self
.logger
.debug('%s: ignoring %s %s: capability '
1243 'probably not supported on this system'
1244 % (ifname
, attr_name
, user_config
))
1246 # we need to convert the cache value to "netlink" format
1247 cached_value
= translate_func(cached_value
.lower())
1251 if not user_config
and not link_just_created
and cached_value
is not None:
1252 # there is no user configuration for this attribute
1253 # if the bridge existed before we need to check if
1254 # this attribute needs to be reset to default value
1255 default_value
= self
.get_attr_default_value(attr_name
)
1258 # the attribute has a default value, we need to convert it to
1259 # netlink format to compare it with the cache value
1260 default_value_nl
= translate_func(default_value
) # default_value.lower()
1262 if default_value_nl
!= cached_value
:
1263 # the running value difers from the default value
1264 # but the user didn't specify any config
1265 # resetting attribute to default
1266 ifla_info_data
[nl_attr
] = default_value_nl
1267 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1269 user_config_nl
= translate_func(user_config
) # user_config.lower()
1271 if user_config_nl
!= cached_value
:
1272 ifla_info_data
[nl_attr
] = user_config_nl
1274 if cached_value
is not None:
1275 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1277 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1278 except Exception as e
:
1279 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1281 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1282 ifla_info_data
= dict()
1283 ifname
= ifaceobj
.name
1285 self
.logger
.info('%s: apply bridge settings' % ifname
)
1287 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1288 self
.fill_ifla_info_data_with_ifla_br_attribute(
1289 ifla_info_data
=ifla_info_data
,
1290 link_just_created
=link_just_created
,
1293 attr_name
=attr_name
,
1294 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1298 self
.fill_ifla_info_data_with_ifla_br_attribute(
1299 ifla_info_data
=ifla_info_data
,
1300 link_just_created
=link_just_created
,
1302 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1303 attr_name
='bridge-mcsnoop',
1304 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1308 if bridge_vlan_aware
:
1309 self
.fill_ifla_info_data_with_ifla_br_attribute(
1310 ifla_info_data
=ifla_info_data
,
1311 link_just_created
=link_just_created
,
1313 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1314 attr_name
='bridge-vlan-stats',
1315 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1319 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1320 if not self
._is
_running
_stp
_state
_on
(ifname
):
1321 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1322 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1323 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1324 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1325 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1327 # If stp not specified and running stp state on, set it to off
1328 if self
._is
_running
_stp
_state
_on
(ifname
):
1329 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1330 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1331 except Exception as e
:
1332 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1335 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1337 def _check_vids(self
, ifaceobj
, vids
):
1342 va
, vb
= v
.split('-')
1343 va
, vb
= int(va
), int(vb
)
1344 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1347 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1348 except exceptions
.ReservedVlanException
as e
:
1351 self
.logger
.warn('%s: unable to parse vid \'%s\''
1352 %(ifaceobj
.name
, v
))
1355 def _get_running_pvid(self
, ifacename
):
1358 running_vidinfo
= self
._get
_running
_vidinfo
()
1359 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1360 v
= vinfo
.get('vlan')
1361 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1366 def _get_running_vids_n_pvid_str(self
, ifacename
):
1370 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1373 ret_vids
= self
._compress
_into
_ranges
(vids
)
1378 ret_pvid
= '%s' %pvid
1381 return (ret_vids
, ret_pvid
)
1383 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1385 """ This method is a combination of methods _apply_bridge_vids and
1386 _apply_bridge_port_pvids above. A combined function is
1387 found necessary to do the deletes first and the adds later
1388 because kernel does honor vid info flags during deletes.
1391 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1392 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1393 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1394 bportifaceobj
.upperifaces
[0])
1397 vids_int
= self
._ranges
_to
_ints
(vids
)
1399 pvid_int
= int(pvid
) if pvid
else 0
1401 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1402 %(bportifaceobj
.name
, pvid
))
1407 vids_to_add
= vids_int
1409 pvid_to_add
= pvid_int
1412 if not self
._check
_vids
(bportifaceobj
, vids
):
1415 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1418 if not running_vids
and not running_pvid
:
1419 # There cannot be a no running pvid.
1420 # It might just not be in our cache:
1421 # this can happen if at the time we were
1422 # creating the bridge vlan cache, the port
1423 # was not part of the bridge. And we need
1424 # to make sure both vids and pvid is not in
1425 # the cache, to declare that our cache may
1431 (vids_to_del
, vids_to_add
) = \
1432 self
._diff
_vids
(vids_to_add
, running_vids
)
1435 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1436 pvid_to_del
= running_pvid
1438 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1439 (pvid_to_del
not in vids_to_add
)):
1440 # kernel deletes dont take into account
1441 # bridge vid flags and its possible that
1442 # the pvid deletes we do end up deleting
1443 # the vids. Be proactive and add the pvid
1444 # to the vid add list if it is in the vids
1445 # and not already part of vids_to_add.
1446 # This helps with a small corner case:
1450 # - new change is going to move the state to
1453 vids_to_add
.add(pvid_to_del
)
1454 except exceptions
.ReservedVlanException
as e
:
1456 except Exception, e
:
1457 self
.log_error('%s: failed to process vids/pvids'
1458 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1459 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1460 bportifaceobj
, raise_error
=False)
1463 if pvid_to_add
in vids_to_del
:
1464 vids_to_del
.remove(pvid_to_add
)
1465 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1466 self
._compress
_into
_ranges
(
1467 vids_to_del
), isbridge
)
1468 except Exception, e
:
1469 self
.log_warn('%s: failed to del vid `%s` (%s)'
1470 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1474 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1476 except Exception, e
:
1477 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1478 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1482 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1483 self
._compress
_into
_ranges
(
1484 vids_to_add
), isbridge
)
1485 except Exception, e
:
1486 self
.log_error('%s: failed to set vid `%s` (%s)'
1487 %(bportifaceobj
.name
, str(vids_to_add
),
1488 str(e
)), bportifaceobj
, raise_error
=False)
1491 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1492 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1494 except Exception, e
:
1495 self
.log_error('%s: failed to set pvid `%s` (%s)'
1496 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1499 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1506 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1508 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1510 allow_untagged
= 'yes'
1511 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1513 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1515 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1517 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1519 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1521 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1526 vids_final
= bridge_vids
1528 if allow_untagged
== 'yes':
1530 pvid_final
= pvids
[0]
1532 pvid_final
= bridge_pvid
1538 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1541 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1544 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1545 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1546 # Old style bridge port vid info
1547 # skip new style setting on ports
1549 self
.logger
.info('%s: applying bridge configuration '
1550 %ifaceobj
.name
+ 'specific to ports')
1552 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1554 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1558 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1560 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1564 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1565 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1566 port_processed_override
= True
1568 port_processed_override
= False
1570 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1572 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1574 self
.ipcmd
.batch_start()
1575 for bport
in bridgeports
:
1576 # Use the brctlcmd bulk set method: first build a dictionary
1578 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1579 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1580 ' for port %s (missing port)' %bport
)
1582 self
.logger
.info('%s: processing bridge config for port %s'
1583 %(ifaceobj
.name
, bport
))
1584 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1585 if not bportifaceobjlist
:
1587 for bportifaceobj
in bportifaceobjlist
:
1588 # Dont process bridge port if it already has been processed
1589 # and there is no override on port_processed
1590 if (not port_processed_override
and
1591 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1592 bridgeFlags
.PORT_PROCESSED
)):
1595 # Add attributes specific to the vlan aware bridge
1596 if bridge_vlan_aware
:
1597 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1598 bportifaceobj
, bridge_vids
, bridge_pvid
)
1599 elif self
.warn_on_untagged_bridge_absence
:
1600 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1601 except exceptions
.ReservedVlanException
as e
:
1603 except Exception, e
:
1605 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1607 self
.ipcmd
.bridge_batch_commit()
1609 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1611 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1612 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1613 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1614 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1615 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1616 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1617 self
.warn_on_untagged_bridge_absence
= False
1619 def bridge_port_get_bridge_name(self
, ifaceobj
):
1620 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1622 # bridge port is not enslaved to a bridge we need to find
1623 # the bridge in it's upper ifaces then enslave it
1624 for u
in ifaceobj
.upperifaces
:
1625 if self
.ipcmd
.is_bridge(u
):
1628 # return should_enslave port, bridgename
1629 return False, bridgename
1631 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1632 if should_enslave_port
:
1633 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1634 self
.handle_ipv6([ifaceobj
.name
], '1')
1636 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1637 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1639 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1640 except Exception as e
:
1641 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1644 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1645 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1648 # bridge doesn't exist
1651 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1652 if vlan_aware_bridge
:
1653 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1656 should_enslave_port
)
1658 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1660 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1661 ifaceobj
=bridge_ifaceobj
,
1662 ifaceobj_getfunc
=ifaceobj_getfunc
,
1663 bridge_vlan_aware
=vlan_aware_bridge
)
1665 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1667 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1668 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1669 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1672 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1677 def parse_interface_list_value(user_config
):
1679 for entry
in user_config
.split():
1680 ifname
, value
= entry
.split('=')
1681 config
[ifname
] = value
1684 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1685 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1687 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1689 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1691 Checks are not performed in this function and must be verified
1692 before. This is done this way to avoid calling this method on
1693 non vlan & bridge port interfaces thus wasting a bit less time
1699 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1700 # if the user explicitly defined vxlan-learning we need to honor his config
1701 # and not sync vxlan-learning with bridge-learning
1703 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1705 # if BRIDGE_LEARNING is in the desired configuration
1706 # and differs from the running vxlan configuration
1707 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1709 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1710 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1711 % (bridge_name
, brport_name
, brport_learning
))
1713 elif brport_learning
is None and bridge_vlan_aware
:
1714 # is bridge-learning is not configured but the bridge is vlan-aware
1716 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1717 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1719 if default_value
!= running_value
:
1720 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1722 if not brport_vxlan_learning_config
:
1724 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1725 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1726 % (bridge_name
, brport_name
, default_value
))
1728 # if kind and ifla_info_data are set they will be added to the
1729 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1730 return kind
, ifla_info_data
1732 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1734 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1735 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1736 'is not supported on a non-vxlan port'
1737 % (ifaceobj
.name
, brport_name
))
1739 elif (bridge_vlan_aware
and
1740 (not self
.arp_nd_suppress_only_on_vxlan
or
1741 (self
.arp_nd_suppress_only_on_vxlan
and
1742 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1743 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1746 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1747 ifname
= ifaceobj
.name
1750 brports_ifla_info_slave_data
= dict()
1751 brport_ifaceobj_dict
= dict()
1753 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1757 for brport_name
in target_ports
:
1758 if brport_name
not in running_brports
:
1759 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1761 new_targets
.append(brport_name
)
1762 running_brports
= new_targets
1764 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1766 # If target_ports is specified we want to configure only this
1767 # sub-list of port we need to check if these ports are already
1768 # enslaved, if not they will be ignored.
1769 # If target_ports is not populated we will apply the brport
1770 # attributes on all running brport.
1772 for port
in running_brports
:
1773 brport_list
= ifaceobj_getfunc(port
)
1775 brport_ifaceobj_dict
[port
] = brport_list
[0]
1776 brports_ifla_info_slave_data
[port
] = dict()
1778 bridge_ports_learning
= {}
1780 # we iterate through all IFLA_BRPORT supported attributes
1781 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1782 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1783 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1785 if not translate_func
:
1786 # if no translation function is found,
1787 # we ignore this attribute and continue
1791 # user didn't specify any value for this attribute
1792 # looking at policy overrides
1793 br_config
= policymanager
.policymanager_api
.get_iface_default(
1794 module_name
=self
.__class
__.__name
__,
1800 #if bridge_vlan_aware:
1801 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1802 # 'should be configured under the ports'
1803 # % (ifname, attr_name, br_config))
1805 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1806 # brport_name: { attr: value }
1808 # bridge-portprios swp1=5 swp2=32
1809 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1810 if '=' in br_config
:
1812 br_config
= self
.parse_interface_list_value(br_config
)
1814 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1817 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1818 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1819 brport_name
= brport_ifaceobj
.name
1821 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1822 # if the port has just been enslaved, info_slave_data is not cached yet
1823 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1827 if not brport_config
:
1828 # if a brport attribute was specified under the bridge and not under the port
1829 # we assign the bridge value to the port. If an attribute is both defined under
1830 # the bridge and the brport we keep the value of the port and ignore the br val.
1831 if type(br_config
) == dict:
1832 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1833 # br_config is a dictionary, example:
1834 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1835 brport_config
= br_config
.get(brport_name
)
1837 brport_config
= br_config
1839 if not brport_config
:
1840 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1841 module_name
=self
.__class
__.__name
__,
1846 user_config
= brport_config
1848 # attribute specific work
1849 # This shouldn't be here but we don't really have a choice otherwise this
1850 # will require too much code duplication and will make the code very complex
1851 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1853 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1859 user_config
= arp_suppress
1862 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1863 # special handking for group_fwd_mask because Cisco proprietary
1864 # protocol needs to be set via a private netlink attribute
1865 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1866 brports_ifla_info_slave_data
,
1867 user_config
, cached_value
)
1871 # if not bridge_vlan_aware:
1872 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1873 # 'should be configured under the bridge'
1874 # % (ifname, brport_name,
1875 # attr_name, brport_config))
1878 user_config_nl
= translate_func(user_config
)
1879 # check config value against running value
1880 if user_config_nl
!= cached_value
:
1881 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1882 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1883 self
.logger
.debug('(cache %s)' % cached_value
)
1885 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1886 # for vxlan-learning sync purposes we need to save the user config for each brports.
1887 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1888 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1889 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1890 # the brport since it might go out of sync for X and Y reasons.
1891 bridge_ports_learning
[brport_name
] = user_config_nl
1893 elif cached_value
is not None:
1894 # no config found, do we need to reset to default?
1895 default
= self
.get_attr_default_value(attr_name
)
1897 default_netlink
= translate_func(default
)
1899 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1900 and not ifupdownflags
.flags
.PERFMODE
1901 and brport_name
not in newly_enslaved_ports
):
1903 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1904 if default_netlink
!= cached_value
:
1905 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1906 % (ifname
, brport_name
))
1908 bridge_ports_learning
[brport_name
] = default_netlink
1909 except Exception as e
:
1910 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1912 if default_netlink
!= cached_value
:
1913 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1914 % (ifname
, brport_name
, attr_name
, default
))
1915 self
.logger
.debug('(cache %s)' % cached_value
)
1916 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1918 # applying bridge port configuration via netlink
1919 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1921 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1923 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1924 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1925 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1926 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1927 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1931 brport_ifla_info_slave_data
,
1932 bridge_ports_learning
.get(brport_name
))
1937 if brport_ifla_info_slave_data
or ifla_info_data
:
1939 netlink
.link_add_set(ifname
=brport_name
,
1941 ifla_info_data
=ifla_info_data
,
1942 slave_kind
='bridge',
1943 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1944 except Exception as e
:
1945 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1947 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1948 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1949 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1951 except Exception as e
:
1952 self
.log_error(str(e
), ifaceobj
)
1954 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1956 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1957 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1958 field we need to have special handling for that.
1960 ifla_brport_group_fwd_mask
= 0
1961 ifla_brport_group_fwd_maskhi
= 0
1963 for group
in re
.split(',|\s*', user_config
):
1967 callback
= self
.l2protocol_tunnel_callback
.get(group
)
1969 if not callable(callback
):
1970 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
1972 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
1974 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
1975 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
1977 log_mask_change
= True
1978 # if user specify bridge-l2protocol-tunnel stp cdp
1979 # we need to set both MASK and MASKHI but we only want to log once
1981 if cached_ifla_brport_group_fwd_mask
is None:
1982 cached_ifla_brport_group_fwd_mask
= 0
1983 if cached_ifla_brport_group_fwd_maskhi
is None:
1984 cached_ifla_brport_group_fwd_maskhi
= 0
1986 # if the cache value is None it means that the kernel doesn't support this attribute
1987 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
1989 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
1991 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
1992 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
1993 log_mask_change
= False
1994 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
1996 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
1998 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
1999 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2000 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2002 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2003 ifname
= ifaceobj
.name
2005 if ifupdownflags
.flags
.PERFMODE
:
2006 link_just_created
= True
2009 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2010 link_just_created
= not link_exists
2013 netlink
.link_add_bridge(ifname
)
2015 self
.logger
.info('%s: bridge already exists' % ifname
)
2017 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2019 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2022 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2023 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2024 newly_enslaved_ports
=newly_enslaved_ports
)
2025 except Exception as e
:
2026 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2030 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2031 if not running_ports
:
2033 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2034 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2035 ifaceobj_getfunc
=ifaceobj_getfunc
,
2036 bridge_vlan_aware
=bridge_vlan_aware
)
2037 except exceptions
.ReservedVlanException
as e
:
2039 except Exception as e
:
2040 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2042 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2043 for p
in running_ports
:
2044 if (ifaceobj_getfunc(p
)[0].link_privflags
&
2045 ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2046 netlink
.link_set_updown(p
, "down")
2049 netlink
.link_set_updown(p
, "up")
2050 except Exception, e
:
2051 self
.logger
.debug('%s: %s: link set up (%s)'
2052 % (ifaceobj
.name
, p
, str(e
)))
2056 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2057 except Exception as e
:
2058 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2060 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2061 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2062 return self
.bridge_mac_iface
2064 if self
.bridge_mac_iface_list
:
2065 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2067 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2068 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2072 for obj
in ifaceobj_list
:
2073 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2074 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2075 if iface_user_configured_hwaddress
:
2076 iface_mac
= iface_user_configured_hwaddress
2078 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2082 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2083 # if hwaddress attribute is not configured we use the running mac addr
2085 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2086 return self
.bridge_mac_iface
2087 elif self
.bridge_set_static_mac_from_port
:
2088 # no policy was provided, we need to get the first physdev or bond ports
2089 # and use its hwaddress to set the bridge mac
2090 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2091 # iterate through the bridge-port list
2092 for port_obj
in ifaceobj_getfunc(port
) or []:
2093 # check if the port is a physdev (link_kind is null) or a bon
2094 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2095 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2096 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2097 if iface_user_configured_hwaddress
:
2098 iface_mac
= iface_user_configured_hwaddress
.lower()
2099 # we need to "normalize" the user provided MAC so it can match with
2100 # what we have in the cache (data retrieved via a netlink dump by
2101 # nlmanager). nlmanager return all macs in lower-case
2103 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2106 self
.bridge_mac_iface
= (port
, iface_mac
)
2107 return self
.bridge_mac_iface
2111 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2112 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2113 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2115 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2117 We have a day one bridge mac changing problem with changing ports
2118 (basically bridge mac changes when the port it inherited the mac from
2121 We have discussed this problem many times before and tabled it.
2122 The issue has aggravated with vxlan bridge ports having auto-generated
2123 random macs...which change on every reboot.
2125 ifupdown2 extract from policy files an iface to select a mac from and
2126 configure it automatically.
2128 if ifaceobj
.get_attr_value('hwaddress'):
2129 # if the user configured a static hwaddress
2130 # there is no need to assign one
2133 ifname
= ifaceobj
.name
2134 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2135 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2136 %(ifname
, mac_intf
, bridge_mac
))
2139 # if an interface is configured with the following attribute:
2140 # hwaddress 08:00:27:42:42:4
2141 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2142 # from the kernel. The only way to counter that is to convert all mac to int
2143 # and compare the ints, it will increase perfs and be safer.
2144 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2145 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2146 if cached_value
and cached_value
== bridge_mac
:
2147 # the bridge mac is already set to the bridge_mac_intf's mac
2150 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2152 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2153 except Exception as e
:
2154 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2155 # log info this error because the user didn't explicitly configured this
2157 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2159 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2160 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2161 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2163 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2164 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2167 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2169 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2170 if ifaceobj_config_attr
in bridge_attributes
:
2171 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2172 % (ifaceobj
.name
, ifaceobj_config_attr
))
2174 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2175 if not self
._is
_bridge
(ifaceobj
):
2177 ifname
= ifaceobj
.name
2178 if not self
.ipcmd
.link_exists(ifname
):
2181 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2183 self
.handle_ipv6(running_ports
, '0')
2184 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2185 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2186 except Exception as e
:
2187 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2189 netlink
.link_del(ifname
)
2190 except Exception as e
:
2191 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2192 self
.logger
.error(str(e
))
2193 # netlink exception already contains the ifname
2195 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2198 running_bridge_port_vids
= ''
2201 running_vids
= self
._get
_runing
_vids
(p
)
2203 running_bridge_port_vids
+= ' %s=%s' %(p
,
2204 ','.join(running_vids
))
2207 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2209 running_bridge_port_pvid
= ''
2212 running_pvid
= self
._get
_runing
_pvid
(p
)
2214 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2218 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2220 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2221 if running_bridge_vids
:
2222 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2223 return running_attrs
2225 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2229 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2230 # so query the ports
2231 running_bridgeport_vids
= []
2232 running_bridgeport_pvids
= []
2233 for bport
in bridgeports
:
2234 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2236 running_bridgeport_vids
.append(' '.join(vids
))
2238 running_bridgeport_pvids
.append(pvid
)
2241 if running_bridgeport_vids
:
2242 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2243 if freq
== len(bridgeports
):
2244 running_attrs
['bridge-vids'] = vidval
2245 bridge_vids
= vidval
.split()
2248 if running_bridgeport_pvids
:
2249 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2250 if freq
== len(bridgeports
) and vidval
!= '1':
2251 running_attrs
['bridge-pvid'] = vidval
2252 bridge_pvid
= vidval
.split()[0]
2254 # Go through all bridge ports and find their vids
2255 for bport
in bridgeports
:
2256 bportifaceobj
= ifaceobj_getfunc(bport
)
2257 if not bportifaceobj
:
2261 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2262 if vids
and vids
!= bridge_vids
:
2264 if pvid
and pvid
!= bridge_pvid
:
2266 if bport_vids
and bport_pvid
in bport_vids
:
2267 bport_vids
.remove(bport_pvid
)
2268 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2269 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2270 bportifaceobj
[0].delete_config('bridge-pvid')
2271 bportifaceobj
[0].delete_config('bridge-vids')
2273 if bport_pvid
and bport_pvid
!= '1':
2274 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2276 # delete any stale bridge-vids under ports
2277 bportifaceobj
[0].delete_config('bridge-pvid')
2279 bportifaceobj
[0].replace_config('bridge-vids',
2280 ' '.join(bport_vids
))
2282 # delete any stale bridge-vids under ports
2283 bportifaceobj
[0].delete_config('bridge-vids')
2284 return running_attrs
2286 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2287 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobjrunning
.name
)
2288 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2290 mcq
= ' '.join(mcqs
)
2293 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2294 bridge_vlan_aware
=False):
2298 skip_kernel_stp_attrs
= 0
2301 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2303 except Exception as e
:
2304 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2306 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2307 if not tmpbridgeattrdict
:
2308 self
.logger
.warn('%s: unable to get bridge attrs'
2309 %ifaceobjrunning
.name
)
2310 return bridgeattrdict
2312 # Fill bridge_ports and bridge stp attributes first
2313 ports
= tmpbridgeattrdict
.get('ports')
2315 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2316 stp
= tmpbridgeattrdict
.get('stp', 'no')
2317 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2318 bridgeattrdict
['bridge-stp'] = [stp
]
2320 if stp
== 'yes' and userspace_stp
:
2321 skip_kernel_stp_attrs
= 1
2323 vlan_stats
= utils
.get_onff_from_onezero(
2324 tmpbridgeattrdict
.get('vlan-stats', None))
2326 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2327 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2329 bool2str
= {'0': 'no', '1': 'yes'}
2330 # pick all other attributes
2331 for k
,v
in tmpbridgeattrdict
.items():
2334 if k
== 'ports' or k
== 'stp':
2337 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2338 # only include igmp attributes if kernel stp is off
2340 attrname
= 'bridge-' + k
2341 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2342 if v
!= mod_default
:
2343 # convert '0|1' running values to 'no|yes'
2344 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2346 bridgeattrdict
[attrname
] = [v
]
2348 if bridge_vlan_aware
:
2351 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2355 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2358 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2361 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2363 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2365 if skip_kernel_stp_attrs
:
2366 return bridgeattrdict
2368 # Do this only for vlan-UNAWARE-bridge
2369 if ports
and not bridge_vlan_aware
:
2370 portconfig
= {'bridge-pathcosts' : '',
2371 'bridge-portprios' : '',
2372 'bridge-learning' : '',
2373 'bridge-unicast-flood' : '',
2374 'bridge-multicast-flood' : '',
2375 'bridge-arp-nd-suppress' : '',
2377 for p
, v
in ports
.items():
2378 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2379 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2381 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2383 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2384 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2386 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2388 v
= utils
.get_onff_from_onezero(
2389 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2392 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2393 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2395 v
= utils
.get_onff_from_onezero(
2396 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2397 p
, 'unicast-flood'))
2399 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2401 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2403 v
= utils
.get_onff_from_onezero(
2404 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2405 p
, 'multicast-flood'))
2407 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2409 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2411 v
= utils
.get_onff_from_onezero(
2412 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2413 p
, 'arp-nd-suppress'))
2415 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2417 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2419 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2422 return bridgeattrdict
2424 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2425 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2426 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2428 mcqs
= attrval
.split()
2430 mcqsout
= ' '.join(mcqs
)
2431 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2432 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2434 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2436 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2438 running_bridge_port_vids
= ''
2439 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2441 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2442 %(ifaceobj
.name
, attrval
))
2447 (port
, val
) = p
.split('=')
2448 vids
= val
.split(',')
2449 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2451 if not self
._compare
_vids
(vids
, running_vids
):
2453 running_bridge_port_vids
+= ' %s=%s' %(port
,
2454 ','.join(running_vids
))
2456 running_bridge_port_vids
+= ' %s' %p
2459 except Exception, e
:
2460 self
.log_warn('%s: failure checking vid %s (%s)'
2461 %(ifaceobj
.name
, p
, str(e
)))
2463 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2464 running_bridge_port_vids
, 1)
2466 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2469 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2471 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2473 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2474 %(ifaceobj
.name
, attrval
))
2476 running_bridge_port_pvids
= ''
2480 (port
, pvid
) = p
.split('=')
2481 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2482 if running_pvid
and running_pvid
== pvid
:
2483 running_bridge_port_pvids
+= ' %s' %p
2486 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2488 except Exception, e
:
2489 self
.log_warn('%s: failure checking pvid %s (%s)'
2490 %(ifaceobj
.name
, pvid
, str(e
)))
2492 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2493 running_bridge_port_pvids
, 1)
2495 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2496 running_bridge_port_pvids
, 0)
2498 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2500 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2502 def _query_check_snooping_wdefault(self
, ifaceobj
):
2503 if (ifupdownflags
.flags
.WITHDEFAULTS
2504 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2505 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2506 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2508 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2509 ifaceobj_getfunc
=None):
2510 if not self
._is
_bridge
(ifaceobj
):
2512 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2513 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2516 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2518 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2519 self
.get_mod_attrs())
2520 #Add default attributes if --with-defaults is set
2521 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2522 ifaceattrs
.append('bridge-stp')
2526 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2527 if not runningattrs
:
2528 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2531 except Exception, e
:
2532 self
.logger
.warn(str(e
))
2535 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2537 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2538 'bridge-port-pvids']
2540 diff
= Set(ifaceattrs
).difference(filterattrs
)
2542 if 'bridge-l2protocol-tunnel' in diff
:
2543 diff
.remove('bridge-l2protocol-tunnel')
2544 # bridge-l2protocol-tunnel requires separate handling
2546 if 'bridge-ports' in diff
:
2547 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2548 diff
.remove('bridge-ports')
2551 # get the corresponding ifaceobj attr
2552 v
= ifaceobj
.get_attr_value_first(k
)
2554 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2555 v
= 'on' if self
.default_stp_on
else 'off'
2558 rv
= runningattrs
.get(k
[7:])
2559 if k
== 'bridge-mcqv4src':
2561 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2562 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2564 if k
== 'bridge-vlan-aware':
2565 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2566 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2567 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2570 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2572 elif k
== 'bridge-stp':
2573 # special case stp compare because it may
2574 # contain more than one valid values
2575 stp_on_vals
= ['on', 'yes']
2576 stp_off_vals
= ['off', 'no']
2577 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2578 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2579 ifaceobjcurr
.update_config_with_status('bridge-stp',
2582 ifaceobjcurr
.update_config_with_status('bridge-stp',
2584 elif k
in ['bridge-pathcosts',
2586 'bridge-portmcrouter',
2589 'bridge-unicast-flood',
2590 'bridge-multicast-flood',
2591 'bridge-arp-nd-suppress',
2593 if k
== 'bridge-arp-nd-suppress':
2594 brctlcmdattrname
= k
[7:]
2596 brctlcmdattrname
= k
[7:].rstrip('s')
2597 # for port attributes, the attributes are in a list
2598 # <portname>=<portattrvalue>
2601 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2604 for vlistitem
in vlist
:
2606 (p
, v
) = vlistitem
.split('=')
2607 if k
in ['bridge-learning',
2608 'bridge-unicast-flood',
2609 'bridge-multicast-flood',
2610 'bridge-arp-nd-suppress',
2612 currv
= utils
.get_onoff_bool(
2613 self
.brctlcmd
.get_bridgeport_attr(
2617 currv
= self
.brctlcmd
.get_bridgeport_attr(
2621 currstr
+= ' %s=%s' %(p
, currv
)
2623 currstr
+= ' %s=%s' %(p
, 'None')
2625 if k
== 'bridge-portmcrouter':
2626 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2630 except Exception, e
:
2631 self
.log_warn(str(e
))
2633 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2634 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2635 rv
= utils
.get_onff_from_onezero(rv
)
2637 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2639 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2641 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2642 # bridge-pvid and bridge-vids on a bridge does
2643 # not correspond directly to a running config
2644 # on the bridge. They correspond to default
2645 # values for the bridge ports. And they are
2646 # already checked against running config of the
2647 # bridge port and reported against a bridge port.
2648 # So, ignore these attributes under the bridge.
2649 # Use '2' for ignore today. XXX: '2' will be
2650 # mapped to a defined value in subsequent patches.
2651 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2653 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2655 elif v
.upper() != rv
.upper():
2656 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2658 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2660 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2662 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2663 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2665 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2666 bridge_all_ports
= []
2667 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2668 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2670 if not running_port_list
and not bridge_all_ports
:
2673 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2676 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2677 # we want to display the same bridge-ports list as provided
2678 # in the interfaces file but if this list contains regexes or
2679 # globs, for now, we won't try to change it.
2680 if 'regex' in port_list
or 'glob' in port_list
:
2681 port_list
= running_port_list
2684 for i
in range(0, len(port_list
)):
2685 if port_list
[i
] in running_port_list
:
2686 ordered
.append(port_list
[i
])
2689 port_list
= running_port_list
2690 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2692 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2693 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2695 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2698 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2699 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2701 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2702 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2703 for ifaceobj
in ifaceobjs
:
2704 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2705 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2708 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2709 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2711 for ifaceobj
in ifaceobjs
:
2712 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2717 def _get_bridge_name(self
, ifaceobj
):
2718 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2720 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2721 ifaceobj_getfunc
, bridgename
):
2722 attr_name
= 'bridge-access'
2723 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2725 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2727 if (not running_pvid
or running_pvid
!= vid
or
2728 (running_vids
and running_vids
[0] != vid
)):
2729 ifaceobjcurr
.update_config_with_status(attr_name
,
2732 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2735 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2737 attr_name
= 'bridge-pvid'
2738 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2740 if running_pvid
and running_pvid
== pvid
:
2741 ifaceobjcurr
.update_config_with_status(attr_name
,
2744 ifaceobjcurr
.update_config_with_status(attr_name
,
2746 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2747 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2748 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2749 # if the interface has multiple iface sections,
2750 # we check the below only for the oldest sibling
2751 # or the last iface section
2752 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2754 if not running_pvid
or running_pvid
!= pvid
:
2755 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2756 ifaceobjcurr
.status_str
= 'bridge pvid error'
2757 elif not running_pvid
or running_pvid
!= '1':
2758 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2759 ifaceobjcurr
.status_str
= 'bridge pvid error'
2761 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2763 vids
= re
.split(r
'[\s\t]\s*', vids
)
2764 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2766 ifaceobjcurr
.update_config_with_status(attr_name
,
2767 ' '.join(running_vids
), 1)
2769 ifaceobjcurr
.update_config_with_status(attr_name
,
2771 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2772 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2773 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2774 # if the interface has multiple iface sections,
2775 # we check the below only for the oldest sibling
2776 # or the last iface section
2778 # check if it matches the bridge vids
2779 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2780 if (bridge_vids
and (not running_vids
or
2781 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2782 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2783 ifaceobjcurr
.status_str
= 'bridge vid error'
2785 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2787 if not self
._is
_bridge
_port
(ifaceobj
):
2788 # Mark all bridge attributes as failed
2789 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2790 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2791 'bridge-pathcosts', 'bridge-portprios',
2792 'bridge-portmcrouter',
2794 'bridge-portmcfl', 'bridge-unicast-flood',
2795 'bridge-multicast-flood',
2796 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2799 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2801 self
.logger
.warn('%s: unable to determine bridge name'
2805 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2806 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2809 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2810 'bridge-portprios' : 'portprio',
2811 'bridge-portmcrouter' : 'portmcrouter',
2812 'bridge-portmcfl' : 'portmcfl',
2813 'bridge-learning' : 'learning',
2814 'bridge-unicast-flood' : 'unicast-flood',
2815 'bridge-multicast-flood' : 'multicast-flood',
2816 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2818 attrval
= ifaceobj
.get_attr_value_first(attr
)
2823 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2824 bridgename
, ifaceobj
.name
, dstattr
)
2826 if dstattr
== 'portmcfl':
2827 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2828 running_attrval
= utils
.get_yesno_boolean(
2829 utils
.get_boolean_from_string(running_attrval
))
2830 elif dstattr
== 'portmcrouter':
2831 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2832 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2834 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2836 elif dstattr
in ['learning',
2841 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2842 running_attrval
= utils
.get_onff_from_onezero(
2845 if running_attrval
!= attrval
:
2846 ifaceobjcurr
.update_config_with_status(attr
,
2849 ifaceobjcurr
.update_config_with_status(attr
,
2851 except Exception, e
:
2852 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2854 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2856 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2857 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2859 if user_config_l2protocol_tunnel
:
2862 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2863 except Exception as e
:
2864 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2866 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2868 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2870 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2871 We need to make sure that all ports comply with the mask given under the bridge
2873 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2875 if user_config_l2protocol_tunnel
:
2876 if '=' in user_config_l2protocol_tunnel
:
2878 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2879 brport_list
= config_per_port_dict
.keys()
2881 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2884 config_per_port_dict
= {}
2885 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2888 for brport_name
in brport_list
:
2889 self
._query
_check
_l2protocol
_tunnel
(
2891 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2894 except Exception as e
:
2895 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2897 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2899 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2900 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2901 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2903 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2904 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2906 if callable(callback
):
2907 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2908 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2909 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2911 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2912 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2913 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2914 running_protocols
= []
2915 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2916 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2917 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2918 running_protocols
.remove('all')
2920 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2921 running_protocols
.append(protocol_name
)
2922 if running_protocols
:
2924 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2925 elif bridge_ifaceobj
:
2926 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2929 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2931 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2933 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2934 if self
._is
_bridge
(ifaceobj
):
2935 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
2937 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2940 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2941 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2942 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2943 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2946 bridge_vlan_aware
=True))
2948 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2949 ifaceobjrunning
, None))
2951 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2952 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2955 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2956 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2957 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2959 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2960 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
2961 ifaceobjrunning
.update_config('bridge-portprios', v
)
2963 def _query_running_bridge_port(self
, ifaceobjrunning
,
2964 ifaceobj_getfunc
=None):
2966 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
2967 ifaceobjrunning
.name
)
2971 self
.logger
.warn('%s: unable to find bridgename'
2972 %ifaceobjrunning
.name
)
2975 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2977 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
2978 except Exception as e
:
2979 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
2982 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
2984 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2985 ifaceobjrunning
.name
)
2986 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
2987 bridge_port_vids
.remove(bridge_port_pvid
)
2989 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
2990 if bridgeifaceobjlist
:
2991 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
2992 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
2994 if not bridge_port_vids
and bridge_port_pvid
:
2995 # must be an access port
2996 if bridge_port_pvid
!= '1':
2997 ifaceobjrunning
.update_config('bridge-access',
3000 if bridge_port_vids
:
3001 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3002 ifaceobjrunning
.update_config('bridge-vids',
3003 ' '.join(bridge_port_vids
))
3004 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3005 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3006 ifaceobjrunning
.update_config('bridge-pvid',
3009 v
= utils
.get_onff_from_onezero(
3010 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3011 ifaceobjrunning
.name
,
3013 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3014 ifaceobjrunning
.update_config('bridge-learning', v
)
3016 v
= utils
.get_onff_from_onezero(
3017 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3018 ifaceobjrunning
.name
,
3020 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3021 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3023 v
= utils
.get_onff_from_onezero(
3024 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3025 ifaceobjrunning
.name
,
3027 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3028 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3030 v
= utils
.get_onff_from_onezero(
3031 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3032 ifaceobjrunning
.name
,
3034 # Display running 'arp-nd-suppress' only on vxlan ports
3035 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3036 # otherwise, display on all bridge-ports
3038 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3040 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3041 (not self
.arp_nd_suppress_only_on_vxlan
or
3042 (self
.arp_nd_suppress_only_on_vxlan
and
3043 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3044 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3046 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3048 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3050 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3051 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3052 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3053 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3054 except Exception as e
:
3055 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3057 def _query(self
, ifaceobj
, **kwargs
):
3058 """ add default policy attributes supported by the module """
3059 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3060 ifaceobj
.get_attr_value_first('bridge-stp')):
3062 if self
.default_stp_on
:
3063 ifaceobj
.update_config('bridge-stp', 'yes')
3065 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3066 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3067 ['mcquerier', 'bridge-mcquerier'],
3068 ['mcsnoop', 'bridge-mcsnoop']]:
3069 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3070 if value
and not utils
.is_binary_bool(value
):
3071 if attrl
[0] in runningattrs
:
3072 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3073 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3075 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3076 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3077 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3078 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3079 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3080 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3082 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3084 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3086 if 'mcrouter' in running_attrs
:
3087 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3092 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3094 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3096 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3100 (port
, val
) = p
.split('=')
3101 if not utils
.is_binary_bool(val
):
3102 to_convert
.append(port
)
3103 for port
in to_convert
:
3104 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3105 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3110 'query-checkcurr': _query_check
,
3111 'query-running': _query_running
,
3116 """ returns list of ops supported by this module """
3117 return self
._run
_ops
.keys()
3119 def _init_command_handlers(self
):
3121 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3123 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3124 """ run bridge configuration on the interface object passed as
3125 argument. Can create bridge interfaces if they dont exist already
3128 **ifaceobj** (object): iface object
3130 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3134 **query_ifaceobj** (object): query check ifaceobject. This is only
3135 valid when op is 'query-checkcurr'. It is an object same as
3136 ifaceobj, but contains running attribute values and its config
3137 status. The modules can use it to return queried running state
3138 of interfaces. status is success if the running state is same
3139 as user required state in ifaceobj. error otherwise.
3141 op_handler
= self
._run
_ops
.get(operation
)
3144 self
._init
_command
_handlers
()
3146 if (not LinkUtils
.bridge_utils_is_installed
3147 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3148 and LinkUtils
.bridge_utils_missing_warning
):
3149 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3150 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3151 LinkUtils
.bridge_utils_missing_warning
= False
3153 if operation
== 'query-checkcurr':
3154 op_handler(self
, ifaceobj
, query_ifaceobj
,
3155 ifaceobj_getfunc
=ifaceobj_getfunc
)
3157 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)