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 if not ifla_brport_group_maskhi
:
668 ifla_brport_group_maskhi
= 0x1
670 ifla_brport_group_maskhi |
= 0x1
671 return ifla_brport_group_mask
, ifla_brport_group_maskhi
674 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
675 if not ifla_brport_group_maskhi
:
676 ifla_brport_group_maskhi
= 0x2
678 ifla_brport_group_maskhi |
= 0x2
679 return ifla_brport_group_mask
, ifla_brport_group_maskhi
682 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
683 if not ifla_brport_group_mask
:
684 ifla_brport_group_mask
= 0x1
686 ifla_brport_group_mask |
= 0x1
687 return ifla_brport_group_mask
, ifla_brport_group_maskhi
690 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
691 if not ifla_brport_group_mask
:
692 ifla_brport_group_mask
= 0x4
694 ifla_brport_group_mask |
= 0x4
695 return ifla_brport_group_mask
, ifla_brport_group_maskhi
698 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
699 if not ifla_brport_group_mask
:
700 ifla_brport_group_mask
= 0x4000
702 ifla_brport_group_mask |
= 0x4000
703 return ifla_brport_group_mask
, ifla_brport_group_maskhi
706 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
707 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
708 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
711 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
712 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x1
715 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
716 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x2
719 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
720 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x1
723 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
724 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4000
727 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
728 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4
731 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
732 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
734 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
735 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
736 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
737 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
739 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
740 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
741 return retval
and c1
#and c2
743 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
745 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
747 for brport_name
in ifaceobj
.lowerifaces
:
748 for obj
in ifaceobj_getfunc(brport_name
) or []:
749 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
750 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
751 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
752 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
753 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
754 % (ifaceobj
.name
, brport_name
))
757 vlan_id
= sub_intf_vlan_id
760 def check_bridge_port_vid_attrs(self
, ifaceobj
):
761 if (ifaceobj
.get_attr_value('bridge-access') and
762 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
763 ifaceobj
.get_attr_value('bridge-pvid'))):
764 self
.logger
.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
765 'will be ignored' % ifaceobj
.name
)
769 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
770 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
771 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
775 for port_name
in ports
:
776 port_obj_l
= ifaceobj_getfunc(port_name
)
777 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
778 self
.logger
.error('%s: %s: vlan sub-interface is not '
779 'supported in a vlan-aware bridge'
780 % (ifaceobj
.name
, port_name
))
783 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
784 self
.arp_nd_suppress_only_on_vxlan
and
785 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
786 self
.log_error('\'bridge-arp-nd-suppress\' is not '
787 'supported on a non-vxlan port %s'
793 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
794 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
795 'device (%s) is part of vlan aware bridge (%s)'
796 % (ifaceobj
.name
, bridgename
), ifaceobj
)
798 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
799 if not ifaceobj_getfunc
:
801 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
802 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
803 if ifaceobj
.get_attr_value('bridge-access'):
805 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
806 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
807 if not ifaceobj_upper_list
:
809 ifaceobj_upper
= ifaceobj_upper_list
[0]
810 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
811 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
812 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
813 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
816 or not self
._compare
_vids
(bridge_vids
,
819 self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
,
825 def _is_bridge(ifaceobj
):
826 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
827 ifaceobj
.get_attr_value_first('bridge-ports') or
828 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
830 def _get_ifaceobj_bridge_ports(self
, ifaceobj
):
833 for brport
in ifaceobj
.get_attr_value('bridge-ports') or []:
835 bridge_ports
.extend(brport
.split())
837 return ' '.join(bridge_ports
)
839 def _is_bridge_port(self
, ifaceobj
):
840 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
844 def check_valid_bridge(self
, ifaceobj
, ifname
):
845 if LinkUtils
.link_exists_nodryrun(ifname
) and not LinkUtils
.is_bridge(ifname
):
846 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
850 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
851 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
853 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
854 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
855 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
856 # for special vlan aware bridges, we need to add another bit
857 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
858 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
859 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
860 ifaceobj
.role |
= ifaceRole
.MASTER
861 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
862 return self
.parse_port_list(ifaceobj
.name
,
863 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
866 def get_dependent_ifacenames_running(self
, ifaceobj
):
867 self
._init
_command
_handlers
()
868 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
870 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
872 def _get_bridge_port_list(self
, ifaceobj
):
874 # port list is also available in the previously
875 # parsed dependent list. Use that if available, instead
876 # of parsing port expr again
877 port_list
= ifaceobj
.lowerifaces
880 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
882 return self
.parse_port_list(ifaceobj
.name
, ports
)
886 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
887 # When enslaving bridge-ports we need to return the exact user
888 # configured bridge ports list (bridge will inherit the mac of the
890 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
891 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
893 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
894 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
895 if not waitport_value
: return
897 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
898 if not waitportvals
: return
900 waitporttime
= int(waitportvals
[0])
902 self
.log_warn('%s: invalid waitport value \'%s\''
903 %(ifaceobj
.name
, waitportvals
[0]))
905 if waitporttime
<= 0: return
907 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
909 except IndexError, e
:
910 # ignore error and use all bridge ports
911 waitportlist
= portlist
913 if not waitportlist
: return
914 self
.logger
.info('%s: waiting for ports %s to exist ...'
915 %(ifaceobj
.name
, str(waitportlist
)))
916 starttime
= time
.time()
917 while ((time
.time() - starttime
) < waitporttime
):
918 if all([False for p
in waitportlist
919 if not self
.ipcmd
.link_exists(p
)]):
923 self
.log_warn('%s: unable to process waitport: %s'
924 %(ifaceobj
.name
, str(e
)))
926 def _enable_disable_ipv6(self
, port
, enable
='1'):
928 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
930 self
.logger
.info(str(e
))
932 def handle_ipv6(self
, ports
, state
, ifaceobj
=None):
934 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
) and
935 not ifaceobj
.get_attr_value('address')):
936 self
._enable
_disable
_ipv
6(ifaceobj
.name
, state
)
938 self
._enable
_disable
_ipv
6(p
, state
)
940 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
941 """ pretty print bridge port add errors.
942 since the commands are batched and the kernel only returns error
943 codes, this function tries to interpret some error codes
944 and prints clearer errors """
946 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
947 # Cumulus Linux specific error checks
949 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
951 for bport
in bridgeports
:
952 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
954 if currvlanid
!= vlanid
:
955 self
.log_error('%s: ' %bridgeifaceobj
.name
+
956 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
960 except Exception as e
:
961 errstr
+= '\n%s' % str(e
)
962 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
964 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
965 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
966 runningbridgeports
= []
968 self
.ipcmd
.batch_start()
969 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
970 self
.ipcmd
.batch_start()
971 # Delete active ports not in the new port list
972 if not ifupdownflags
.flags
.PERFMODE
:
973 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
974 if runningbridgeports
:
975 for bport
in runningbridgeports
:
976 if not bridgeports
or bport
not in bridgeports
:
977 self
.ipcmd
.link_set(bport
, 'nomaster')
978 # set admin DOWN on all removed ports
979 # that don't have config outside bridge
980 if not ifaceobj_getfunc(bport
):
981 netlink
.link_set_updown(bport
, "down")
982 # enable ipv6 for ports that were removed
983 self
.handle_ipv6([bport
], '0')
985 runningbridgeports
= []
987 self
.ipcmd
.batch_commit()
991 newbridgeports
= Set(bridgeports
).difference(Set(runningbridgeports
))
992 newly_enslaved_ports
= []
994 newbridgeports_ordered
= []
995 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
996 if br_port
in newbridgeports
:
997 newbridgeports_ordered
.append(br_port
)
999 for bridgeport
in newbridgeports_ordered
:
1001 if (not ifupdownflags
.flags
.DRYRUN
and
1002 not self
.ipcmd
.link_exists(bridgeport
)):
1003 self
.log_error('%s: bridge port %s does not exist'
1004 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
1007 hwaddress
= self
.ipcmd
.link_get_hwaddress(bridgeport
)
1008 if not self
._valid
_ethaddr
(hwaddress
):
1009 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
1010 bridgeport
) + 'invalid ether addr %s'
1013 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
1014 newly_enslaved_ports
.append(bridgeport
)
1015 self
.handle_ipv6([bridgeport
], '1')
1016 self
.ipcmd
.addr_flush(bridgeport
)
1020 self
.ipcmd
.batch_commit()
1021 self
.ipcmd
.batch_start()
1022 except Exception, e
:
1023 self
.logger
.error(str(e
))
1026 self
.ipcmd
.batch_commit()
1027 except Exception, e
:
1028 self
._pretty
_print
_add
_ports
_error
(str(e
), ifaceobj
,
1033 self
.log_error('bridge configuration failed (missing ports)')
1035 return newly_enslaved_ports
1037 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1038 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1039 if not maxwait
: return
1041 maxwait
= int(maxwait
)
1043 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1046 if not maxwait
: return
1047 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1050 starttime
= time
.time()
1051 while ((time
.time() - starttime
) < maxwait
):
1052 if all([False for p
in portlist
1053 if self
.read_file_oneline(
1054 '/sys/class/net/%s/brif/%s/state'
1055 %(ifaceobj
.name
, p
)) != '3']):
1058 except Exception, e
:
1059 self
.log_warn('%s: unable to process maxwait: %s'
1060 %(ifaceobj
.name
, str(e
)))
1062 def _ints_to_ranges(self
, ints
):
1063 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
1065 yield b
[0][1], b
[-1][1]
1067 def _ranges_to_ints(self
, rangelist
):
1068 """ returns expanded list of integers given set of string ranges
1069 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1073 for part
in rangelist
:
1075 a
, b
= part
.split('-')
1076 a
, b
= int(a
), int(b
)
1077 result
.extend(range(a
, b
+ 1))
1082 self
.logger
.warn('unable to parse vids \'%s\''
1083 %''.join(rangelist
))
1087 def _compress_into_ranges(self
, vids_ints
):
1088 return ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
1089 for start
, end
in self
._ints
_to
_ranges
(vids_ints
)]
1091 def _diff_vids(self
, vids1_ints
, vids2_ints
):
1092 return Set(vids2_ints
).difference(vids1_ints
), Set(vids1_ints
).difference(vids2_ints
)
1094 def _compare_vids(self
, vids1
, vids2
, pvid
=None):
1095 """ Returns true if the vids are same else return false """
1097 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
1098 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
1099 set_diff
= Set(vids1_ints
).symmetric_difference(vids2_ints
)
1100 if pvid
and int(pvid
) in set_diff
:
1101 set_diff
.remove(int(pvid
))
1107 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1109 # Sets old style igmp querier
1111 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1113 running_mcqv4src
= {}
1114 if not ifupdownflags
.flags
.PERFMODE
:
1115 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1117 srclist
= attrval
.split()
1122 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
1124 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1125 for v
in mcqs
.keys():
1126 self
.brctlcmd
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1127 elif not ifupdownflags
.flags
.PERFMODE
:
1128 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobj
.name
)
1129 if running_mcqv4src
:
1130 for v
in running_mcqv4src
.keys():
1131 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1133 def _get_running_vidinfo(self
):
1134 if self
._running
_vidinfo
_valid
:
1135 return self
._running
_vidinfo
1136 self
._running
_vidinfo
= {}
1138 # Removed check for PERFMODE. Need the get in all cases
1139 # including reboot, so that we can configure the pvid correctly.
1140 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all_json()
1141 self
._running
_vidinfo
_valid
= True
1142 return self
._running
_vidinfo
1144 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1146 # Supports old style vlan vid info format
1149 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1150 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1151 if not bridge_port_pvids
and not bridge_port_vids
:
1154 # Handle bridge vlan attrs
1156 if bridge_port_pvids
:
1157 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1159 self
.log_warn('%s: could not parse \'%s %s\''
1160 %(ifaceobj
.name
, 'bridge-port-pvids',
1165 (port
, pvid
) = p
.split('=')
1167 running_pvid
= self
._get
_running
_pvid
(port
)
1169 if running_pvid
== pvid
:
1172 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
1173 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
1174 except Exception, e
:
1175 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1176 %(ifaceobj
.name
, p
, str(e
)))
1179 if bridge_port_vids
:
1180 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1182 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1183 'bridge-port-vids', bridge_port_vids
))
1187 (port
, val
) = p
.split('=')
1188 vids
= val
.split(',')
1189 vids_int
= self
._ranges
_to
_ints
(vids
)
1190 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
1192 (vids_to_del
, vids_to_add
) = \
1193 self
._diff
_vids
(vids_int
, running_vids
)
1195 self
.ipcmd
.bridge_port_vids_del(port
,
1196 self
._compress
_into
_ranges
(vids_to_del
))
1198 self
.ipcmd
.bridge_port_vids_add(port
,
1199 self
._compress
_into
_ranges
(vids_to_add
))
1201 self
.ipcmd
.bridge_port_vids_add(port
, vids_int
)
1202 except Exception, e
:
1203 self
.log_warn('%s: failed to set vid `%s` (%s)'
1204 %(ifaceobj
.name
, p
, str(e
)))
1206 def _is_running_stp_state_on(self
, bridgename
):
1207 """ Returns True if running stp state is on, else False """
1209 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1211 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1212 return running_stp_state
and running_stp_state
!= '0'
1216 def _is_config_stp_state_on(self
, ifaceobj
):
1217 """ Returns true if user specified stp state is on, else False """
1219 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1221 return self
.default_stp_on
1222 return utils
.get_boolean_from_string(stp_attr
)
1224 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1225 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1226 if not mcsnoop
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1227 return self
._vxlan
_bridge
_default
_igmp
_snooping
1230 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1238 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1240 if not callable(translate_func
):
1244 user_config
= policymanager
.policymanager_api
.get_iface_default(
1245 module_name
=self
.__class
__.__name
__,
1250 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1251 if old_cache_key
and not link_just_created
:
1252 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1253 if not cached_value
:
1254 # the link already exists but we don't have any value
1255 # cached for this attr, it probably means that the
1256 # capability is not available on this system (i.e old kernel)
1257 self
.logger
.debug('%s: ignoring %s %s: capability '
1258 'probably not supported on this system'
1259 % (ifname
, attr_name
, user_config
))
1261 # we need to convert the cache value to "netlink" format
1262 cached_value
= translate_func(cached_value
.lower())
1266 if not user_config
and not link_just_created
and cached_value
is not None:
1267 # there is no user configuration for this attribute
1268 # if the bridge existed before we need to check if
1269 # this attribute needs to be reset to default value
1270 default_value
= self
.get_attr_default_value(attr_name
)
1273 # the attribute has a default value, we need to convert it to
1274 # netlink format to compare it with the cache value
1275 default_value_nl
= translate_func(default_value
) # default_value.lower()
1277 if default_value_nl
!= cached_value
:
1278 # the running value difers from the default value
1279 # but the user didn't specify any config
1280 # resetting attribute to default
1281 ifla_info_data
[nl_attr
] = default_value_nl
1282 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1284 user_config_nl
= translate_func(user_config
) # user_config.lower()
1286 if user_config_nl
!= cached_value
:
1287 ifla_info_data
[nl_attr
] = user_config_nl
1289 if cached_value
is not None:
1290 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1292 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1293 except Exception as e
:
1294 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1296 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1297 ifla_info_data
= dict()
1298 ifname
= ifaceobj
.name
1300 self
.logger
.info('%s: apply bridge settings' % ifname
)
1302 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1303 self
.fill_ifla_info_data_with_ifla_br_attribute(
1304 ifla_info_data
=ifla_info_data
,
1305 link_just_created
=link_just_created
,
1308 attr_name
=attr_name
,
1309 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1313 self
.fill_ifla_info_data_with_ifla_br_attribute(
1314 ifla_info_data
=ifla_info_data
,
1315 link_just_created
=link_just_created
,
1317 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1318 attr_name
='bridge-mcsnoop',
1319 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1323 if bridge_vlan_aware
:
1324 self
.fill_ifla_info_data_with_ifla_br_attribute(
1325 ifla_info_data
=ifla_info_data
,
1326 link_just_created
=link_just_created
,
1328 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1329 attr_name
='bridge-vlan-stats',
1330 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1334 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1335 if not self
._is
_running
_stp
_state
_on
(ifname
):
1336 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1337 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1338 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1339 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1340 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1342 # If stp not specified and running stp state on, set it to off
1343 if self
._is
_running
_stp
_state
_on
(ifname
):
1344 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1345 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1346 except Exception as e
:
1347 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1350 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1352 def _check_vids(self
, ifaceobj
, vids
):
1357 va
, vb
= v
.split('-')
1358 va
, vb
= int(va
), int(vb
)
1359 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1362 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1363 except exceptions
.ReservedVlanException
as e
:
1366 self
.logger
.warn('%s: unable to parse vid \'%s\''
1367 %(ifaceobj
.name
, v
))
1370 def _get_running_pvid(self
, ifacename
):
1373 running_vidinfo
= self
._get
_running
_vidinfo
()
1374 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1375 v
= vinfo
.get('vlan')
1376 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1381 def _get_running_vids_n_pvid_str(self
, ifacename
):
1385 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1388 ret_vids
= self
._compress
_into
_ranges
(vids
)
1393 ret_pvid
= '%s' %pvid
1396 return (ret_vids
, ret_pvid
)
1398 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1400 """ This method is a combination of methods _apply_bridge_vids and
1401 _apply_bridge_port_pvids above. A combined function is
1402 found necessary to do the deletes first and the adds later
1403 because kernel does honor vid info flags during deletes.
1406 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1407 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1408 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1409 bportifaceobj
.upperifaces
[0])
1412 vids_int
= self
._ranges
_to
_ints
(vids
)
1414 pvid_int
= int(pvid
) if pvid
else 0
1416 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1417 %(bportifaceobj
.name
, pvid
))
1422 vids_to_add
= vids_int
1424 pvid_to_add
= pvid_int
1427 if not self
._check
_vids
(bportifaceobj
, vids
):
1430 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1433 if not running_vids
and not running_pvid
:
1434 # There cannot be a no running pvid.
1435 # It might just not be in our cache:
1436 # this can happen if at the time we were
1437 # creating the bridge vlan cache, the port
1438 # was not part of the bridge. And we need
1439 # to make sure both vids and pvid is not in
1440 # the cache, to declare that our cache may
1446 (vids_to_del
, vids_to_add
) = \
1447 self
._diff
_vids
(vids_to_add
, running_vids
)
1450 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1451 pvid_to_del
= running_pvid
1453 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1454 (pvid_to_del
not in vids_to_add
)):
1455 # kernel deletes dont take into account
1456 # bridge vid flags and its possible that
1457 # the pvid deletes we do end up deleting
1458 # the vids. Be proactive and add the pvid
1459 # to the vid add list if it is in the vids
1460 # and not already part of vids_to_add.
1461 # This helps with a small corner case:
1465 # - new change is going to move the state to
1468 vids_to_add
.add(pvid_to_del
)
1469 except exceptions
.ReservedVlanException
as e
:
1471 except Exception, e
:
1472 self
.log_error('%s: failed to process vids/pvids'
1473 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1474 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1475 bportifaceobj
, raise_error
=False)
1478 if pvid_to_add
in vids_to_del
:
1479 vids_to_del
.remove(pvid_to_add
)
1480 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1481 self
._compress
_into
_ranges
(
1482 vids_to_del
), isbridge
)
1483 except Exception, e
:
1484 self
.log_warn('%s: failed to del vid `%s` (%s)'
1485 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1489 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1491 except Exception, e
:
1492 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1493 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1497 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1498 self
._compress
_into
_ranges
(
1499 vids_to_add
), isbridge
)
1500 except Exception, e
:
1501 self
.log_error('%s: failed to set vid `%s` (%s)'
1502 %(bportifaceobj
.name
, str(vids_to_add
),
1503 str(e
)), bportifaceobj
, raise_error
=False)
1506 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1507 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1509 except Exception, e
:
1510 self
.log_error('%s: failed to set pvid `%s` (%s)'
1511 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1514 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1521 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1523 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1525 allow_untagged
= 'yes'
1526 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1528 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1530 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1532 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1534 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1536 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1541 vids_final
= bridge_vids
1543 if allow_untagged
== 'yes':
1545 pvid_final
= pvids
[0]
1547 pvid_final
= bridge_pvid
1553 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1556 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1559 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1560 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1561 # Old style bridge port vid info
1562 # skip new style setting on ports
1564 self
.logger
.info('%s: applying bridge configuration '
1565 %ifaceobj
.name
+ 'specific to ports')
1567 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1569 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1573 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1575 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1579 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1580 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1581 port_processed_override
= True
1583 port_processed_override
= False
1585 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1587 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1589 self
.ipcmd
.batch_start()
1590 for bport
in bridgeports
:
1591 # Use the brctlcmd bulk set method: first build a dictionary
1593 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1594 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1595 ' for port %s (missing port)' %bport
)
1597 self
.logger
.info('%s: processing bridge config for port %s'
1598 %(ifaceobj
.name
, bport
))
1599 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1600 if not bportifaceobjlist
:
1602 for bportifaceobj
in bportifaceobjlist
:
1603 # Dont process bridge port if it already has been processed
1604 # and there is no override on port_processed
1605 if (not port_processed_override
and
1606 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1607 bridgeFlags
.PORT_PROCESSED
)):
1610 # Add attributes specific to the vlan aware bridge
1611 if bridge_vlan_aware
:
1612 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1613 bportifaceobj
, bridge_vids
, bridge_pvid
)
1614 elif self
.warn_on_untagged_bridge_absence
:
1615 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1616 except exceptions
.ReservedVlanException
as e
:
1618 except Exception, e
:
1620 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1622 self
.ipcmd
.bridge_batch_commit()
1624 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1626 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1627 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1628 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1629 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1630 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1631 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1632 self
.warn_on_untagged_bridge_absence
= False
1634 def bridge_port_get_bridge_name(self
, ifaceobj
):
1635 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1637 # bridge port is not enslaved to a bridge we need to find
1638 # the bridge in it's upper ifaces then enslave it
1639 for u
in ifaceobj
.upperifaces
:
1640 if self
.ipcmd
.is_bridge(u
):
1643 # return should_enslave port, bridgename
1644 return False, bridgename
1646 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1647 if should_enslave_port
:
1648 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1649 self
.handle_ipv6([ifaceobj
.name
], '1')
1651 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1652 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1654 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1655 except Exception as e
:
1656 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1659 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1660 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1663 # bridge doesn't exist
1666 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1667 if vlan_aware_bridge
:
1668 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1671 should_enslave_port
)
1673 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1675 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1676 ifaceobj
=bridge_ifaceobj
,
1677 ifaceobj_getfunc
=ifaceobj_getfunc
,
1678 bridge_vlan_aware
=vlan_aware_bridge
)
1680 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1682 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1683 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1684 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1687 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1692 def parse_interface_list_value(user_config
):
1694 for entry
in user_config
.split():
1695 ifname
, value
= entry
.split('=')
1696 config
[ifname
] = value
1699 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1700 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1702 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1704 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1706 Checks are not performed in this function and must be verified
1707 before. This is done this way to avoid calling this method on
1708 non vlan & bridge port interfaces thus wasting a bit less time
1714 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1715 # if the user explicitly defined vxlan-learning we need to honor his config
1716 # and not sync vxlan-learning with bridge-learning
1718 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1720 # if BRIDGE_LEARNING is in the desired configuration
1721 # and differs from the running vxlan configuration
1722 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1724 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1725 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1726 % (bridge_name
, brport_name
, brport_learning
))
1728 elif brport_learning
is None and bridge_vlan_aware
:
1729 # is bridge-learning is not configured but the bridge is vlan-aware
1731 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1732 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1734 if default_value
!= running_value
:
1735 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1737 if not brport_vxlan_learning_config
:
1739 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1740 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1741 % (bridge_name
, brport_name
, default_value
))
1743 # if kind and ifla_info_data are set they will be added to the
1744 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1745 return kind
, ifla_info_data
1747 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1749 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1750 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1751 'is not supported on a non-vxlan port'
1752 % (ifaceobj
.name
, brport_name
))
1754 elif (bridge_vlan_aware
and
1755 (not self
.arp_nd_suppress_only_on_vxlan
or
1756 (self
.arp_nd_suppress_only_on_vxlan
and
1757 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1758 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1761 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1762 ifname
= ifaceobj
.name
1765 brports_ifla_info_slave_data
= dict()
1766 brport_ifaceobj_dict
= dict()
1768 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1772 for brport_name
in target_ports
:
1773 if brport_name
not in running_brports
:
1774 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1776 new_targets
.append(brport_name
)
1777 running_brports
= new_targets
1779 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1781 # If target_ports is specified we want to configure only this
1782 # sub-list of port we need to check if these ports are already
1783 # enslaved, if not they will be ignored.
1784 # If target_ports is not populated we will apply the brport
1785 # attributes on all running brport.
1787 for port
in running_brports
:
1788 brport_list
= ifaceobj_getfunc(port
)
1790 brport_ifaceobj_dict
[port
] = brport_list
[0]
1791 brports_ifla_info_slave_data
[port
] = dict()
1793 bridge_ports_learning
= {}
1795 # we iterate through all IFLA_BRPORT supported attributes
1796 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1797 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1798 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1800 if not translate_func
:
1801 # if no translation function is found,
1802 # we ignore this attribute and continue
1806 # user didn't specify any value for this attribute
1807 # looking at policy overrides
1808 br_config
= policymanager
.policymanager_api
.get_iface_default(
1809 module_name
=self
.__class
__.__name
__,
1815 #if bridge_vlan_aware:
1816 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1817 # 'should be configured under the ports'
1818 # % (ifname, attr_name, br_config))
1820 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1821 # brport_name: { attr: value }
1823 # bridge-portprios swp1=5 swp2=32
1824 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1825 if '=' in br_config
:
1827 br_config
= self
.parse_interface_list_value(br_config
)
1829 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1832 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1833 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1834 brport_name
= brport_ifaceobj
.name
1836 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1837 # if the port has just been enslaved, info_slave_data is not cached yet
1838 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1842 if not brport_config
:
1843 # if a brport attribute was specified under the bridge and not under the port
1844 # we assign the bridge value to the port. If an attribute is both defined under
1845 # the bridge and the brport we keep the value of the port and ignore the br val.
1846 if type(br_config
) == dict:
1847 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1848 # br_config is a dictionary, example:
1849 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1850 brport_config
= br_config
.get(brport_name
)
1852 brport_config
= br_config
1854 if not brport_config
:
1855 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1856 module_name
=self
.__class
__.__name
__,
1861 user_config
= brport_config
1863 # attribute specific work
1864 # This shouldn't be here but we don't really have a choice otherwise this
1865 # will require too much code duplication and will make the code very complex
1866 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1868 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1874 user_config
= arp_suppress
1877 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1878 # special handking for group_fwd_mask because Cisco proprietary
1879 # protocol needs to be set via a private netlink attribute
1880 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1881 brports_ifla_info_slave_data
,
1882 user_config
, cached_value
)
1886 # if not bridge_vlan_aware:
1887 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1888 # 'should be configured under the bridge'
1889 # % (ifname, brport_name,
1890 # attr_name, brport_config))
1893 user_config_nl
= translate_func(user_config
)
1894 # check config value against running value
1895 if user_config_nl
!= cached_value
:
1896 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1897 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1898 self
.logger
.debug('(cache %s)' % cached_value
)
1900 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1901 # for vxlan-learning sync purposes we need to save the user config for each brports.
1902 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1903 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1904 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1905 # the brport since it might go out of sync for X and Y reasons.
1906 bridge_ports_learning
[brport_name
] = user_config_nl
1908 elif cached_value
is not None:
1909 # no config found, do we need to reset to default?
1910 default
= self
.get_attr_default_value(attr_name
)
1912 default_netlink
= translate_func(default
)
1914 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1915 and not ifupdownflags
.flags
.PERFMODE
1916 and brport_name
not in newly_enslaved_ports
):
1918 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1919 if default_netlink
!= cached_value
:
1920 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1921 % (ifname
, brport_name
))
1923 bridge_ports_learning
[brport_name
] = default_netlink
1924 except Exception as e
:
1925 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1927 if default_netlink
!= cached_value
:
1928 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1929 % (ifname
, brport_name
, attr_name
, default
))
1930 self
.logger
.debug('(cache %s)' % cached_value
)
1931 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1933 # applying bridge port configuration via netlink
1934 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1936 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1938 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1939 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1940 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1941 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1942 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1946 brport_ifla_info_slave_data
,
1947 bridge_ports_learning
.get(brport_name
))
1952 if brport_ifla_info_slave_data
or ifla_info_data
:
1954 netlink
.link_add_set(ifname
=brport_name
,
1956 ifla_info_data
=ifla_info_data
,
1957 slave_kind
='bridge',
1958 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1959 except Exception as e
:
1960 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1962 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1963 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1964 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1966 except Exception as e
:
1967 self
.log_error(str(e
), ifaceobj
)
1969 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
1971 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
1972 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
1973 field we need to have special handling for that.
1975 ifla_brport_group_fwd_mask
= 0
1976 ifla_brport_group_fwd_maskhi
= 0
1978 for group
in re
.split(',|\s*', user_config
):
1982 callback
= self
.l2protocol_tunnel_callback
.get(group
)
1984 if not callable(callback
):
1985 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
1987 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
1989 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
1990 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
1992 log_mask_change
= True
1993 # if user specify bridge-l2protocol-tunnel stp cdp
1994 # we need to set both MASK and MASKHI but we only want to log once
1996 if cached_ifla_brport_group_fwd_mask
is None:
1997 cached_ifla_brport_group_fwd_mask
= 0
1998 if cached_ifla_brport_group_fwd_maskhi
is None:
1999 cached_ifla_brport_group_fwd_maskhi
= 0
2001 # if the cache value is None it means that the kernel doesn't support this attribute
2002 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2004 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2006 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2007 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2008 log_mask_change
= False
2009 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2011 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2013 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2014 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2015 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2017 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2018 ifname
= ifaceobj
.name
2020 if ifupdownflags
.flags
.PERFMODE
:
2021 link_just_created
= True
2024 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2025 link_just_created
= not link_exists
2028 netlink
.link_add_bridge(ifname
)
2030 self
.logger
.info('%s: bridge already exists' % ifname
)
2032 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2034 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2037 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2038 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2039 newly_enslaved_ports
=newly_enslaved_ports
)
2040 except Exception as e
:
2041 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2045 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2046 if not running_ports
:
2048 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2049 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2050 ifaceobj_getfunc
=ifaceobj_getfunc
,
2051 bridge_vlan_aware
=bridge_vlan_aware
)
2052 except exceptions
.ReservedVlanException
as e
:
2054 except Exception as e
:
2055 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2057 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2058 for p
in running_ports
:
2059 if (ifaceobj_getfunc(p
)[0].link_privflags
&
2060 ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2061 netlink
.link_set_updown(p
, "down")
2064 netlink
.link_set_updown(p
, "up")
2065 except Exception, e
:
2066 self
.logger
.debug('%s: %s: link set up (%s)'
2067 % (ifaceobj
.name
, p
, str(e
)))
2071 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2072 except Exception as e
:
2073 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2075 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2076 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2077 return self
.bridge_mac_iface
2079 if self
.bridge_mac_iface_list
:
2080 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2082 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2083 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2087 for obj
in ifaceobj_list
:
2088 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2089 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2090 if iface_user_configured_hwaddress
:
2091 iface_mac
= iface_user_configured_hwaddress
2093 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2097 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2098 # if hwaddress attribute is not configured we use the running mac addr
2100 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2101 return self
.bridge_mac_iface
2102 elif self
.bridge_set_static_mac_from_port
:
2103 # no policy was provided, we need to get the first physdev or bond ports
2104 # and use its hwaddress to set the bridge mac
2105 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2106 # iterate through the bridge-port list
2107 for port_obj
in ifaceobj_getfunc(port
) or []:
2108 # check if the port is a physdev (link_kind is null) or a bon
2109 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2110 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2111 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2112 if iface_user_configured_hwaddress
:
2113 iface_mac
= iface_user_configured_hwaddress
.lower()
2114 # we need to "normalize" the user provided MAC so it can match with
2115 # what we have in the cache (data retrieved via a netlink dump by
2116 # nlmanager). nlmanager return all macs in lower-case
2118 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2121 self
.bridge_mac_iface
= (port
, iface_mac
)
2122 return self
.bridge_mac_iface
2126 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2127 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2128 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2130 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2132 We have a day one bridge mac changing problem with changing ports
2133 (basically bridge mac changes when the port it inherited the mac from
2136 We have discussed this problem many times before and tabled it.
2137 The issue has aggravated with vxlan bridge ports having auto-generated
2138 random macs...which change on every reboot.
2140 ifupdown2 extract from policy files an iface to select a mac from and
2141 configure it automatically.
2143 if ifaceobj
.get_attr_value('hwaddress'):
2144 # if the user configured a static hwaddress
2145 # there is no need to assign one
2148 ifname
= ifaceobj
.name
2149 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2150 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2151 %(ifname
, mac_intf
, bridge_mac
))
2154 # if an interface is configured with the following attribute:
2155 # hwaddress 08:00:27:42:42:4
2156 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2157 # from the kernel. The only way to counter that is to convert all mac to int
2158 # and compare the ints, it will increase perfs and be safer.
2159 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2160 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2161 if cached_value
and cached_value
== bridge_mac
:
2162 # the bridge mac is already set to the bridge_mac_intf's mac
2165 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2167 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2168 except Exception as e
:
2169 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2170 # log info this error because the user didn't explicitly configured this
2172 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2174 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2175 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2176 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2178 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2179 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2182 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2184 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2185 if ifaceobj_config_attr
in bridge_attributes
:
2186 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2187 % (ifaceobj
.name
, ifaceobj_config_attr
))
2189 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2190 if not self
._is
_bridge
(ifaceobj
):
2192 ifname
= ifaceobj
.name
2193 if not self
.ipcmd
.link_exists(ifname
):
2196 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2198 self
.handle_ipv6(running_ports
, '0')
2199 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2200 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2201 except Exception as e
:
2202 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2204 netlink
.link_del(ifname
)
2205 except Exception as e
:
2206 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2207 self
.logger
.error(str(e
))
2208 # netlink exception already contains the ifname
2210 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2213 running_bridge_port_vids
= ''
2216 running_vids
= self
._get
_runing
_vids
(p
)
2218 running_bridge_port_vids
+= ' %s=%s' %(p
,
2219 ','.join(running_vids
))
2222 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2224 running_bridge_port_pvid
= ''
2227 running_pvid
= self
._get
_runing
_pvid
(p
)
2229 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2233 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2235 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2236 if running_bridge_vids
:
2237 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2238 return running_attrs
2240 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2244 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2245 # so query the ports
2246 running_bridgeport_vids
= []
2247 running_bridgeport_pvids
= []
2248 for bport
in bridgeports
:
2249 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2251 running_bridgeport_vids
.append(' '.join(vids
))
2253 running_bridgeport_pvids
.append(pvid
)
2256 if running_bridgeport_vids
:
2257 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2258 if freq
== len(bridgeports
):
2259 running_attrs
['bridge-vids'] = vidval
2260 bridge_vids
= vidval
.split()
2263 if running_bridgeport_pvids
:
2264 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2265 if freq
== len(bridgeports
) and vidval
!= '1':
2266 running_attrs
['bridge-pvid'] = vidval
2267 bridge_pvid
= vidval
.split()[0]
2269 # Go through all bridge ports and find their vids
2270 for bport
in bridgeports
:
2271 bportifaceobj
= ifaceobj_getfunc(bport
)
2272 if not bportifaceobj
:
2276 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2277 if vids
and vids
!= bridge_vids
:
2279 if pvid
and pvid
!= bridge_pvid
:
2281 if bport_vids
and bport_pvid
in bport_vids
:
2282 bport_vids
.remove(bport_pvid
)
2283 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2284 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2285 bportifaceobj
[0].delete_config('bridge-pvid')
2286 bportifaceobj
[0].delete_config('bridge-vids')
2288 if bport_pvid
and bport_pvid
!= '1':
2289 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2291 # delete any stale bridge-vids under ports
2292 bportifaceobj
[0].delete_config('bridge-pvid')
2294 bportifaceobj
[0].replace_config('bridge-vids',
2295 ' '.join(bport_vids
))
2297 # delete any stale bridge-vids under ports
2298 bportifaceobj
[0].delete_config('bridge-vids')
2299 return running_attrs
2301 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2302 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src(ifaceobjrunning
.name
)
2303 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2305 mcq
= ' '.join(mcqs
)
2308 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2309 bridge_vlan_aware
=False):
2313 skip_kernel_stp_attrs
= 0
2316 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2318 except Exception as e
:
2319 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2321 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2322 if not tmpbridgeattrdict
:
2323 self
.logger
.warn('%s: unable to get bridge attrs'
2324 %ifaceobjrunning
.name
)
2325 return bridgeattrdict
2327 # Fill bridge_ports and bridge stp attributes first
2328 ports
= tmpbridgeattrdict
.get('ports')
2330 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2331 stp
= tmpbridgeattrdict
.get('stp', 'no')
2332 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2333 bridgeattrdict
['bridge-stp'] = [stp
]
2335 if stp
== 'yes' and userspace_stp
:
2336 skip_kernel_stp_attrs
= 1
2338 vlan_stats
= utils
.get_onff_from_onezero(
2339 tmpbridgeattrdict
.get('vlan-stats', None))
2341 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2342 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2344 bool2str
= {'0': 'no', '1': 'yes'}
2345 # pick all other attributes
2346 for k
,v
in tmpbridgeattrdict
.items():
2349 if k
== 'ports' or k
== 'stp':
2352 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2353 # only include igmp attributes if kernel stp is off
2355 attrname
= 'bridge-' + k
2356 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2357 if v
!= mod_default
:
2358 # convert '0|1' running values to 'no|yes'
2359 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2361 bridgeattrdict
[attrname
] = [v
]
2363 if bridge_vlan_aware
:
2366 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2370 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2373 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2376 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2378 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2380 if skip_kernel_stp_attrs
:
2381 return bridgeattrdict
2383 # Do this only for vlan-UNAWARE-bridge
2384 if ports
and not bridge_vlan_aware
:
2385 portconfig
= {'bridge-pathcosts' : '',
2386 'bridge-portprios' : '',
2387 'bridge-learning' : '',
2388 'bridge-unicast-flood' : '',
2389 'bridge-multicast-flood' : '',
2390 'bridge-arp-nd-suppress' : '',
2392 for p
, v
in ports
.items():
2393 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2394 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2396 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2398 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2399 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2401 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2403 v
= utils
.get_onff_from_onezero(
2404 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2407 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2408 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2410 v
= utils
.get_onff_from_onezero(
2411 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2412 p
, 'unicast-flood'))
2414 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2416 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2418 v
= utils
.get_onff_from_onezero(
2419 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2420 p
, 'multicast-flood'))
2422 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2424 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2426 v
= utils
.get_onff_from_onezero(
2427 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2428 p
, 'arp-nd-suppress'))
2430 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2432 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2434 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2437 return bridgeattrdict
2439 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2440 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2441 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2443 mcqs
= attrval
.split()
2445 mcqsout
= ' '.join(mcqs
)
2446 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2447 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2449 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2451 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2453 running_bridge_port_vids
= ''
2454 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2456 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2457 %(ifaceobj
.name
, attrval
))
2462 (port
, val
) = p
.split('=')
2463 vids
= val
.split(',')
2464 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2466 if not self
._compare
_vids
(vids
, running_vids
):
2468 running_bridge_port_vids
+= ' %s=%s' %(port
,
2469 ','.join(running_vids
))
2471 running_bridge_port_vids
+= ' %s' %p
2474 except Exception, e
:
2475 self
.log_warn('%s: failure checking vid %s (%s)'
2476 %(ifaceobj
.name
, p
, str(e
)))
2478 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2479 running_bridge_port_vids
, 1)
2481 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2484 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2486 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2488 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2489 %(ifaceobj
.name
, attrval
))
2491 running_bridge_port_pvids
= ''
2495 (port
, pvid
) = p
.split('=')
2496 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2497 if running_pvid
and running_pvid
== pvid
:
2498 running_bridge_port_pvids
+= ' %s' %p
2501 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2503 except Exception, e
:
2504 self
.log_warn('%s: failure checking pvid %s (%s)'
2505 %(ifaceobj
.name
, pvid
, str(e
)))
2507 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2508 running_bridge_port_pvids
, 1)
2510 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2511 running_bridge_port_pvids
, 0)
2513 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2515 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2517 def _query_check_snooping_wdefault(self
, ifaceobj
):
2518 if (ifupdownflags
.flags
.WITHDEFAULTS
2519 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2520 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2521 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2523 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2524 ifaceobj_getfunc
=None):
2525 if not self
._is
_bridge
(ifaceobj
):
2527 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2528 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2531 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2533 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2534 self
.get_mod_attrs())
2535 #Add default attributes if --with-defaults is set
2536 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2537 ifaceattrs
.append('bridge-stp')
2541 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2542 if not runningattrs
:
2543 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2546 except Exception, e
:
2547 self
.logger
.warn(str(e
))
2550 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2552 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2553 'bridge-port-pvids']
2555 diff
= Set(ifaceattrs
).difference(filterattrs
)
2557 if 'bridge-l2protocol-tunnel' in diff
:
2558 diff
.remove('bridge-l2protocol-tunnel')
2559 # bridge-l2protocol-tunnel requires separate handling
2561 if 'bridge-ports' in diff
:
2562 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2563 diff
.remove('bridge-ports')
2566 # get the corresponding ifaceobj attr
2567 v
= ifaceobj
.get_attr_value_first(k
)
2569 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2570 v
= 'on' if self
.default_stp_on
else 'off'
2573 rv
= runningattrs
.get(k
[7:])
2574 if k
== 'bridge-mcqv4src':
2576 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2577 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2579 if k
== 'bridge-vlan-aware':
2580 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2581 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2582 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2585 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2587 elif k
== 'bridge-stp':
2588 # special case stp compare because it may
2589 # contain more than one valid values
2590 stp_on_vals
= ['on', 'yes']
2591 stp_off_vals
= ['off', 'no']
2592 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2593 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2594 ifaceobjcurr
.update_config_with_status('bridge-stp',
2597 ifaceobjcurr
.update_config_with_status('bridge-stp',
2599 elif k
in ['bridge-pathcosts',
2601 'bridge-portmcrouter',
2604 'bridge-unicast-flood',
2605 'bridge-multicast-flood',
2606 'bridge-arp-nd-suppress',
2608 if k
== 'bridge-arp-nd-suppress':
2609 brctlcmdattrname
= k
[7:]
2611 brctlcmdattrname
= k
[7:].rstrip('s')
2612 # for port attributes, the attributes are in a list
2613 # <portname>=<portattrvalue>
2616 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2619 for vlistitem
in vlist
:
2621 (p
, v
) = vlistitem
.split('=')
2622 if k
in ['bridge-learning',
2623 'bridge-unicast-flood',
2624 'bridge-multicast-flood',
2625 'bridge-arp-nd-suppress',
2627 currv
= utils
.get_onoff_bool(
2628 self
.brctlcmd
.get_bridgeport_attr(
2632 currv
= self
.brctlcmd
.get_bridgeport_attr(
2636 currstr
+= ' %s=%s' %(p
, currv
)
2638 currstr
+= ' %s=%s' %(p
, 'None')
2640 if k
== 'bridge-portmcrouter':
2641 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2645 except Exception, e
:
2646 self
.log_warn(str(e
))
2648 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2649 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2650 rv
= utils
.get_onff_from_onezero(rv
)
2652 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2654 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2656 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2657 # bridge-pvid and bridge-vids on a bridge does
2658 # not correspond directly to a running config
2659 # on the bridge. They correspond to default
2660 # values for the bridge ports. And they are
2661 # already checked against running config of the
2662 # bridge port and reported against a bridge port.
2663 # So, ignore these attributes under the bridge.
2664 # Use '2' for ignore today. XXX: '2' will be
2665 # mapped to a defined value in subsequent patches.
2666 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2668 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2670 elif v
.upper() != rv
.upper():
2671 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2673 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2675 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2677 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2678 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2680 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2681 bridge_all_ports
= []
2682 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2683 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2685 if not running_port_list
and not bridge_all_ports
:
2688 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2691 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2692 # we want to display the same bridge-ports list as provided
2693 # in the interfaces file but if this list contains regexes or
2694 # globs, for now, we won't try to change it.
2695 if 'regex' in port_list
or 'glob' in port_list
:
2696 port_list
= running_port_list
2699 for i
in range(0, len(port_list
)):
2700 if port_list
[i
] in running_port_list
:
2701 ordered
.append(port_list
[i
])
2704 port_list
= running_port_list
2705 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2707 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2708 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2710 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2713 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2714 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2716 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2717 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2718 for ifaceobj
in ifaceobjs
:
2719 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2720 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2723 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2724 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2726 for ifaceobj
in ifaceobjs
:
2727 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2732 def _get_bridge_name(self
, ifaceobj
):
2733 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2735 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2736 ifaceobj_getfunc
, bridgename
):
2737 attr_name
= 'bridge-access'
2738 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2740 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2742 if (not running_pvid
or running_pvid
!= vid
or
2743 (running_vids
and running_vids
[0] != vid
)):
2744 ifaceobjcurr
.update_config_with_status(attr_name
,
2747 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2750 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2752 attr_name
= 'bridge-pvid'
2753 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2755 if running_pvid
and running_pvid
== pvid
:
2756 ifaceobjcurr
.update_config_with_status(attr_name
,
2759 ifaceobjcurr
.update_config_with_status(attr_name
,
2761 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2762 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2763 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2764 # if the interface has multiple iface sections,
2765 # we check the below only for the oldest sibling
2766 # or the last iface section
2767 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2769 if not running_pvid
or running_pvid
!= pvid
:
2770 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2771 ifaceobjcurr
.status_str
= 'bridge pvid error'
2772 elif not running_pvid
or running_pvid
!= '1':
2773 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2774 ifaceobjcurr
.status_str
= 'bridge pvid error'
2776 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2778 vids
= re
.split(r
'[\s\t]\s*', vids
)
2779 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2781 ifaceobjcurr
.update_config_with_status(attr_name
,
2782 ' '.join(running_vids
), 1)
2784 ifaceobjcurr
.update_config_with_status(attr_name
,
2786 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2787 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2788 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2789 # if the interface has multiple iface sections,
2790 # we check the below only for the oldest sibling
2791 # or the last iface section
2793 # check if it matches the bridge vids
2794 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2795 if (bridge_vids
and (not running_vids
or
2796 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2797 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2798 ifaceobjcurr
.status_str
= 'bridge vid error'
2800 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2802 if not self
._is
_bridge
_port
(ifaceobj
):
2803 # Mark all bridge attributes as failed
2804 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2805 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2806 'bridge-pathcosts', 'bridge-portprios',
2807 'bridge-portmcrouter',
2809 'bridge-portmcfl', 'bridge-unicast-flood',
2810 'bridge-multicast-flood',
2811 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2814 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2816 self
.logger
.warn('%s: unable to determine bridge name'
2820 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2821 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2824 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2825 'bridge-portprios' : 'portprio',
2826 'bridge-portmcrouter' : 'portmcrouter',
2827 'bridge-portmcfl' : 'portmcfl',
2828 'bridge-learning' : 'learning',
2829 'bridge-unicast-flood' : 'unicast-flood',
2830 'bridge-multicast-flood' : 'multicast-flood',
2831 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2833 attrval
= ifaceobj
.get_attr_value_first(attr
)
2838 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2839 bridgename
, ifaceobj
.name
, dstattr
)
2841 if dstattr
== 'portmcfl':
2842 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2843 running_attrval
= utils
.get_yesno_boolean(
2844 utils
.get_boolean_from_string(running_attrval
))
2845 elif dstattr
== 'portmcrouter':
2846 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2847 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2849 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2851 elif dstattr
in ['learning',
2856 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2857 running_attrval
= utils
.get_onff_from_onezero(
2860 if running_attrval
!= attrval
:
2861 ifaceobjcurr
.update_config_with_status(attr
,
2864 ifaceobjcurr
.update_config_with_status(attr
,
2866 except Exception, e
:
2867 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2869 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2871 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2872 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2874 if user_config_l2protocol_tunnel
:
2877 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2878 except Exception as e
:
2879 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2881 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2883 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2885 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2886 We need to make sure that all ports comply with the mask given under the bridge
2888 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2890 if user_config_l2protocol_tunnel
:
2891 if '=' in user_config_l2protocol_tunnel
:
2893 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2894 brport_list
= config_per_port_dict
.keys()
2896 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2899 config_per_port_dict
= {}
2900 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2903 for brport_name
in brport_list
:
2904 self
._query
_check
_l2protocol
_tunnel
(
2906 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2909 except Exception as e
:
2910 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2912 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2914 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2915 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2916 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2918 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2919 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2921 if callable(callback
):
2922 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2923 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2924 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2926 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2927 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2928 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2929 running_protocols
= []
2930 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2931 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2932 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2933 running_protocols
.remove('all')
2935 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2936 running_protocols
.append(protocol_name
)
2937 if running_protocols
:
2939 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2940 elif bridge_ifaceobj
:
2941 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2944 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
2946 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
2948 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
2949 if self
._is
_bridge
(ifaceobj
):
2950 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
2952 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
2955 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
2956 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
2957 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
2958 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2961 bridge_vlan_aware
=True))
2963 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
2964 ifaceobjrunning
, None))
2966 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
2967 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2970 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2971 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
2972 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
2974 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
2975 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
2976 ifaceobjrunning
.update_config('bridge-portprios', v
)
2978 def _query_running_bridge_port(self
, ifaceobjrunning
,
2979 ifaceobj_getfunc
=None):
2981 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
2982 ifaceobjrunning
.name
)
2986 self
.logger
.warn('%s: unable to find bridgename'
2987 %ifaceobjrunning
.name
)
2990 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2992 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
2993 except Exception as e
:
2994 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
2997 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
2999 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3000 ifaceobjrunning
.name
)
3001 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3002 bridge_port_vids
.remove(bridge_port_pvid
)
3004 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3005 if bridgeifaceobjlist
:
3006 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3007 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3009 if not bridge_port_vids
and bridge_port_pvid
:
3010 # must be an access port
3011 if bridge_port_pvid
!= '1':
3012 ifaceobjrunning
.update_config('bridge-access',
3015 if bridge_port_vids
:
3016 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3017 ifaceobjrunning
.update_config('bridge-vids',
3018 ' '.join(bridge_port_vids
))
3019 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3020 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3021 ifaceobjrunning
.update_config('bridge-pvid',
3024 v
= utils
.get_onff_from_onezero(
3025 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3026 ifaceobjrunning
.name
,
3028 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3029 ifaceobjrunning
.update_config('bridge-learning', v
)
3031 v
= utils
.get_onff_from_onezero(
3032 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3033 ifaceobjrunning
.name
,
3035 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3036 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3038 v
= utils
.get_onff_from_onezero(
3039 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3040 ifaceobjrunning
.name
,
3042 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3043 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3045 v
= utils
.get_onff_from_onezero(
3046 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3047 ifaceobjrunning
.name
,
3049 # Display running 'arp-nd-suppress' only on vxlan ports
3050 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3051 # otherwise, display on all bridge-ports
3053 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3055 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3056 (not self
.arp_nd_suppress_only_on_vxlan
or
3057 (self
.arp_nd_suppress_only_on_vxlan
and
3058 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3059 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3061 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3063 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3065 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3066 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3067 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3068 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3069 except Exception as e
:
3070 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3072 def _query(self
, ifaceobj
, **kwargs
):
3073 """ add default policy attributes supported by the module """
3074 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3075 ifaceobj
.get_attr_value_first('bridge-stp')):
3077 if self
.default_stp_on
:
3078 ifaceobj
.update_config('bridge-stp', 'yes')
3080 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3081 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3082 ['mcquerier', 'bridge-mcquerier'],
3083 ['mcsnoop', 'bridge-mcsnoop']]:
3084 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3085 if value
and not utils
.is_binary_bool(value
):
3086 if attrl
[0] in runningattrs
:
3087 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3088 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3090 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3091 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3092 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3093 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3094 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3095 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3097 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3099 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3101 if 'mcrouter' in running_attrs
:
3102 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3107 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3109 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3111 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3115 (port
, val
) = p
.split('=')
3116 if not utils
.is_binary_bool(val
):
3117 to_convert
.append(port
)
3118 for port
in to_convert
:
3119 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3120 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3125 'query-checkcurr': _query_check
,
3126 'query-running': _query_running
,
3131 """ returns list of ops supported by this module """
3132 return self
._run
_ops
.keys()
3134 def _init_command_handlers(self
):
3136 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3138 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3139 """ run bridge configuration on the interface object passed as
3140 argument. Can create bridge interfaces if they dont exist already
3143 **ifaceobj** (object): iface object
3145 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3149 **query_ifaceobj** (object): query check ifaceobject. This is only
3150 valid when op is 'query-checkcurr'. It is an object same as
3151 ifaceobj, but contains running attribute values and its config
3152 status. The modules can use it to return queried running state
3153 of interfaces. status is success if the running state is same
3154 as user required state in ifaceobj. error otherwise.
3156 op_handler
= self
._run
_ops
.get(operation
)
3159 self
._init
_command
_handlers
()
3161 if (not LinkUtils
.bridge_utils_is_installed
3162 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3163 and LinkUtils
.bridge_utils_missing_warning
):
3164 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3165 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3166 LinkUtils
.bridge_utils_missing_warning
= False
3168 if operation
== 'query-checkcurr':
3169 op_handler(self
, ifaceobj
, query_ifaceobj
,
3170 ifaceobj_getfunc
=ifaceobj_getfunc
)
3172 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)