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 ifupdown2
.ifupdown
.ifupdownconfig
as ifupdownconfig
31 import ifupdown
.exceptions
as exceptions
32 import ifupdown
.policymanager
as policymanager
33 import ifupdown
.ifupdownflags
as ifupdownflags
35 from nlmanager
.nlmanager
import Link
37 from ifupdown
.iface
import *
38 from ifupdown
.utils
import utils
39 from ifupdown
.netlink
import netlink
41 from ifupdownaddons
.cache
import *
42 from ifupdownaddons
.LinkUtils
import LinkUtils
43 from ifupdownaddons
.modulebase
import moduleBase
45 import ifupdown
.ifupdownconfig
as ifupdownconfig
50 PORT_PROCESSED_OVERRIDE
= 0x2
53 class bridge(moduleBase
):
54 """ ifupdown2 addon module to configure linux bridges """
56 _modinfo
= { 'mhelp' : 'Bridge configuration module. Supports both ' +
57 'vlan aware and non vlan aware bridges. For the vlan ' +
58 'aware bridge, the port specific attributes must be ' +
59 'specified under the port. And for vlan unaware bridge ' +
60 'port specific attributes must be specified under the ' +
64 {'help' : 'vlan aware bridge. Setting this ' +
65 'attribute to yes enables vlan filtering' +
67 'validvals' : ['yes', 'no'],
68 'example' : ['bridge-vlan-aware yes/no'],
72 {'help' : 'bridge ports',
75 'validvals': ['<interface-list>', 'none'],
76 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
77 'bridge-ports glob swp1-3.100',
78 'bridge-ports regex (swp[1|2|3].100)']},
80 {'help': 'bridge-stp yes/no',
81 'example' : ['bridge-stp no'],
82 'validvals' : ['yes', 'on', 'off', 'no'],
85 {'help': 'bridge priority',
86 'validrange' : ['0', '65535'],
87 'example' : ['bridge-bridgeprio 32768'],
90 {'help': 'bridge ageing',
91 'validrange' : ['0', '65535'],
92 'example' : ['bridge-ageing 300'],
95 { 'help' : 'bridge forward delay',
96 'validrange' : ['0', '255'],
97 'example' : ['bridge-fd 15'],
100 # XXX: recheck values
101 { 'help' : 'bridge garbage collection interval in secs',
102 'validrange' : ['0', '255'],
103 'example' : ['bridge-gcint 4'],
108 { 'help' : 'bridge set hello time',
109 'validrange' : ['0', '255'],
110 'example' : ['bridge-hello 2'],
113 { 'help' : 'bridge set maxage',
114 'validrange' : ['0', '255'],
115 'example' : ['bridge-maxage 20'],
118 { 'help' : 'bridge set port path costs',
119 'validvals': ['<interface-range-list>'],
120 'validrange' : ['0', '65535'],
121 'example' : ['under the port (for vlan aware bridge): bridge-pathcosts 100',
122 'under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100'],
125 { 'help' : 'bridge port prios',
126 'validvals': ['<interface-range-list>'],
127 'validrange' : ['0', '65535'],
128 'example' : ['under the port (for vlan aware bridge): bridge-portprios 32',
129 'under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32'],
132 { 'help' : 'set multicast last member count',
133 'validrange' : ['0', '255'],
134 'example' : ['bridge-mclmc 2'],
137 { 'help': 'Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes',
138 'validvals' : ['yes', 'no', '0', '1', '2'],
139 'example' : ['bridge-mcrouter 1'],
143 { 'help' : 'set multicast snooping',
144 'validvals' : ['yes', 'no', '0', '1'],
146 'example' : ['bridge-mcsnoop yes']},
148 { 'help' : 'set multicast startup query count',
149 'validrange' : ['0', '255'],
151 'example' : ['bridge-mcsqc 2']},
153 { 'help' : 'set multicast query to use ifaddr',
154 'validvals' : ['yes', 'no', '0', '1'],
156 'example' : ['bridge-mcqifaddr no']},
158 { 'help' : 'set multicast querier',
159 'validvals' : ['yes', 'no', '0', '1'],
161 'example' : ['bridge-mcquerier no']},
163 { 'help' : 'set hash elasticity',
164 'validrange' : ['0', '4096'],
166 'example' : ['bridge-hashel 4096']},
168 { 'help' : 'set hash max',
169 'validrange' : ['0', '4096'],
171 'example' : ['bridge-hashmax 4096']},
173 { 'help' : 'set multicast last member interval (in secs)',
174 'validrange' : ['0', '255'],
176 'example' : ['bridge-mclmi 1']},
178 { 'help' : 'set multicast membership interval (in secs)',
179 'validrange' : ['0', '255'],
181 'example' : ['bridge-mcmi 260']},
183 { 'help' : 'set multicast querier interval (in secs)',
184 'validrange' : ['0', '255'],
186 'example' : ['bridge-mcqpi 255']},
188 { 'help' : 'set multicast query interval (in secs)',
189 'validrange' : ['0', '255'],
191 'example' : ['bridge-mcqi 125']},
193 { 'help' : 'set multicast query response interval (in secs)',
194 'validrange' : ['0', '255'],
196 'example' : ['bridge-mcqri 10']},
198 { 'help' : 'set multicast startup query interval (in secs)',
199 'validrange' : ['0', '255'],
201 'example' : ['bridge-mcsqi 31']},
203 { 'help' : 'set per VLAN v4 multicast querier source address',
204 'validvals' : ['<number-ipv4-list>', ],
207 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
208 'bridge-portmcrouter':
210 'help': 'Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled',
211 'validvals': ['<interface-disabled-automatic-enabled>'],
213 'under the port (for vlan aware bridge): bridge-portmcrouter 0',
214 'under the port (for vlan aware bridge): bridge-portmcrouter 1',
215 'under the port (for vlan aware bridge): bridge-portmcrouter 2',
216 'under the port (for vlan aware bridge): bridge-portmcrouter disabled',
217 'under the port (for vlan aware bridge): bridge-portmcrouter automatic',
218 'under the port (for vlan aware bridge): bridge-portmcrouter enabled',
219 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2',
220 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled',
221 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1',
225 { 'help' : 'port multicast fast leave.',
226 'validvals': ['<interface-yes-no-0-1-list>'],
228 'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
229 'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
231 { 'help' : 'wait for a max of time secs for the' +
232 ' specified ports to become available,' +
233 'if no ports are specified then those' +
234 ' specified on bridge-ports will be' +
235 ' used here. Specifying no ports here ' +
236 'should not be used if we are using ' +
237 'regex or \"all\" on bridge_ports,' +
238 'as it wouldnt work.',
240 'validvals': ['<number-interface-list>'],
241 'example' : ['bridge-waitport 4 swp1 swp2']},
243 { 'help' : 'forces to time seconds the maximum time ' +
244 'that the Debian bridge setup scripts will ' +
245 'wait for the bridge ports to get to the ' +
246 'forwarding status, doesn\'t allow factional ' +
247 'part. If it is equal to 0 then no waiting' +
249 'validrange' : ['0', '255'],
251 'example' : ['bridge-maxwait 3']},
253 { 'help' : 'bridge port vids. Can be specified ' +
254 'under the bridge or under the port. ' +
255 'If specified under the bridge the ports ' +
256 'inherit it unless overridden by a ' +
257 'bridge-vids attribute under the port',
259 'validvals': ['<number-comma-range-list>'],
260 'example' : ['bridge-vids 4000',
261 'bridge-vids 2000 2200-3000'],
262 'aliases': ['bridge-trunk']},
264 { 'help' : 'bridge port pvid. Must be specified under' +
266 'validrange' : ['0', '4096'],
267 'example' : ['bridge-pvid 1']},
269 { 'help' : 'bridge port access vlan. Must be ' +
270 'specified under the bridge port',
271 'validrange' : ['1', '4094'],
272 'example' : ['bridge-access 300']},
273 'bridge-allow-untagged' :
274 { 'help' : 'indicate if the bridge port accepts ' +
275 'untagged packets or not. Must be ' +
276 'specified under the bridge port. ' +
277 'Default is \'yes\'',
278 'validvals' : ['yes', 'no'],
279 'example' : ['bridge-allow-untagged yes'],
282 { 'help' : 'bridge vlans',
284 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
285 'bridge-port-pvids' :
286 { 'help' : 'bridge port vlans',
288 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
290 { 'help' : 'bridge port learning flag',
291 'validvals': ['on', 'off', '<interface-on-off-list>'],
293 'example' : ['bridge-learning off']},
294 'bridge-igmp-version' :
295 { 'help' : 'mcast igmp version',
296 'validvals': ['2', '3'],
298 'example' : ['bridge-igmp-version 2']},
299 'bridge-mld-version':
300 { 'help' : 'mcast mld version',
301 'validvals': ['1', '2'],
303 'example' : ['bridge-mld-version 1']},
304 'bridge-unicast-flood' :
305 { 'help' : 'bridge port unicast flood flag',
306 'validvals': ['on', 'off', '<interface-on-off-list>'],
308 'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
309 'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
310 'bridge-multicast-flood' :
311 { 'help' : 'bridge port multicast flood flag',
312 'validvals': ['on', 'off', '<interface-on-off-list>'],
314 'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
315 'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
316 'bridge-vlan-protocol' :
317 { 'help' : 'bridge vlan protocol',
318 'default' : '802.1q',
319 'validvals': ['802.1q', '802.1ad'],
320 'example' : ['bridge-vlan-protocol 802.1q']},
321 'bridge-vlan-stats' :
322 { 'help' : 'bridge vlan stats',
324 'validvals': ['on', 'off'],
325 'example' : ['bridge-vlan-stats off']},
326 'bridge-arp-nd-suppress' :
327 { 'help' : 'bridge port arp nd suppress flag',
328 'validvals': ['on', 'off', '<interface-on-off-list>'],
330 'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
331 'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
333 { 'help' : 'bridge multicast stats',
335 'validvals': ['on', 'off'],
336 'example' : ['bridge-mcstats off']},
337 'bridge-l2protocol-tunnel': {
338 'help': 'layer 2 protocol tunneling',
339 'validvals': [ # XXX: lists all combinations, should move to
340 # a better representation
345 'cdp lacp lldp pvst',
360 'lacp lldp pvst stp',
372 '<interface-l2protocol-tunnel-list>'],
374 'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
375 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
376 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
377 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
378 'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
383 # Netlink attributes not associated with ifupdown2
384 # attributes are left commented-out for a future use
385 # and kept in order :)
386 _ifla_br_attributes_map
= (
387 # Link.IFLA_BR_UNSPEC,
388 ('bridge-fd', Link
.IFLA_BR_FORWARD_DELAY
),
389 ('bridge-hello', Link
.IFLA_BR_HELLO_TIME
),
390 ('bridge-maxage', Link
.IFLA_BR_MAX_AGE
),
391 ('bridge-ageing', Link
.IFLA_BR_AGEING_TIME
),
392 ('bridge-stp', Link
.IFLA_BR_STP_STATE
),
393 ('bridge-bridgeprio', Link
.IFLA_BR_PRIORITY
),
394 ('bridge-vlan-aware', Link
.IFLA_BR_VLAN_FILTERING
),
395 ('bridge-vlan-protocol', Link
.IFLA_BR_VLAN_PROTOCOL
),
396 # Link.IFLA_BR_GROUP_FWD_MASK,
397 # Link.IFLA_BR_ROOT_ID,
398 # Link.IFLA_BR_BRIDGE_ID,
399 # Link.IFLA_BR_ROOT_PORT,
400 # (Link.IFLA_BR_ROOT_PATH_COST,,
401 # Link.IFLA_BR_TOPOLOGY_CHANGE,
402 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
403 # Link.IFLA_BR_HELLO_TIMER,
404 # Link.IFLA_BR_TCN_TIMER,
405 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
406 # Link.IFLA_BR_GC_TIMER,
407 # Link.IFLA_BR_GROUP_ADDR,
408 # Link.IFLA_BR_FDB_FLUSH,
409 ('bridge-mcrouter', Link
.IFLA_BR_MCAST_ROUTER
),
410 #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
411 ('bridge-mcqifaddr', Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
),
412 ('bridge-mcquerier', Link
.IFLA_BR_MCAST_QUERIER
),
413 ('bridge-hashel', Link
.IFLA_BR_MCAST_HASH_ELASTICITY
),
414 ('bridge-hashmax', Link
.IFLA_BR_MCAST_HASH_MAX
),
415 ('bridge-mclmc', Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
),
416 ('bridge-mcsqc', Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
),
417 ('bridge-mclmi', Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
),
418 ('bridge-mcmi', Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
),
419 ('bridge-mcqpi', Link
.IFLA_BR_MCAST_QUERIER_INTVL
),
420 ('bridge-mcqi', Link
.IFLA_BR_MCAST_QUERY_INTVL
),
421 ('bridge-mcqri', Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
),
422 ('bridge-mcsqi', Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
),
423 # Link.IFLA_BR_NF_CALL_IPTABLES,
424 # Link.IFLA_BR_NF_CALL_IP6TABLES,
425 # Link.IFLA_BR_NF_CALL_ARPTABLES,
426 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
428 # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
429 ('bridge-igmp-version', Link
.IFLA_BR_MCAST_IGMP_VERSION
, ),
430 ('bridge-mcstats', Link
.IFLA_BR_MCAST_STATS_ENABLED
),
431 ('bridge-mld-version', Link
.IFLA_BR_MCAST_MLD_VERSION
)
433 # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
434 # they are supported. It is done this way because this dictionary is used
435 # in a loop, but these attributes require additional work. Thus they are
436 # excluded from this loop without overhead.
438 # we are still using the old linkCache we need an easy way
439 # to use this cache with the new full-netlink approach
440 _ifla_br_attributes_old_cache_key_map
= dict(
442 (Link
.IFLA_BR_FORWARD_DELAY
, 'fd'),
443 (Link
.IFLA_BR_HELLO_TIME
, 'hello'),
444 (Link
.IFLA_BR_MAX_AGE
, 'maxage'),
445 (Link
.IFLA_BR_AGEING_TIME
, 'ageing'),
446 (Link
.IFLA_BR_STP_STATE
, 'stp'),
447 (Link
.IFLA_BR_PRIORITY
, 'bridgeprio'),
448 (Link
.IFLA_BR_VLAN_FILTERING
, 'vlan_filtering'),
449 (Link
.IFLA_BR_VLAN_PROTOCOL
, 'vlan-protocol'),
450 (Link
.IFLA_BR_MCAST_ROUTER
, 'mcrouter'),
451 (Link
.IFLA_BR_MCAST_SNOOPING
, 'mcsnoop'),
452 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, 'mcqifaddr'),
453 (Link
.IFLA_BR_MCAST_QUERIER
, 'mcquerier'),
454 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, 'hashel'),
455 (Link
.IFLA_BR_MCAST_HASH_MAX
, 'hashmax'),
456 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, 'mclmc'),
457 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, 'mcsqc'),
458 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, 'mclmi'),
459 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, 'mcmi'),
460 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, 'mcqpi'),
461 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, 'mcqi'),
462 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, 'mcqri'),
463 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, 'mcsqi'),
464 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, 'vlan-stats'),
465 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, 'mcstats'),
466 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, 'igmp-version'),
467 (Link
.IFLA_BR_MCAST_MLD_VERSION
, 'mld-version')
471 _ifla_br_attributes_translate_user_config_to_netlink_map
= dict(
473 # Link.IFLA_BR_UNSPEC,
474 (Link
.IFLA_BR_FORWARD_DELAY
, lambda x
: int(x
) * 100),
475 (Link
.IFLA_BR_HELLO_TIME
, lambda x
: int(x
) * 100),
476 (Link
.IFLA_BR_MAX_AGE
, lambda x
: int(x
) * 100),
477 (Link
.IFLA_BR_AGEING_TIME
, lambda x
: int(x
) * 100),
478 # Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
479 (Link
.IFLA_BR_PRIORITY
, int),
480 (Link
.IFLA_BR_VLAN_FILTERING
, utils
.get_boolean_from_string
),
481 (Link
.IFLA_BR_VLAN_PROTOCOL
, str),
482 # Link.IFLA_BR_GROUP_FWD_MASK,
483 # Link.IFLA_BR_ROOT_ID,
484 # Link.IFLA_BR_BRIDGE_ID,
485 # Link.IFLA_BR_ROOT_PORT,
486 # Link.IFLA_BR_ROOT_PATH_COST,
487 # Link.IFLA_BR_TOPOLOGY_CHANGE,
488 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
489 # Link.IFLA_BR_HELLO_TIMER,
490 # Link.IFLA_BR_TCN_TIMER,
491 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
492 # Link.IFLA_BR_GC_TIMER,
493 # Link.IFLA_BR_GROUP_ADDR,
494 # Link.IFLA_BR_FDB_FLUSH,
495 (Link
.IFLA_BR_MCAST_ROUTER
, utils
.get_int_from_boolean_and_string
),
496 (Link
.IFLA_BR_MCAST_SNOOPING
, utils
.get_boolean_from_string
),
497 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, utils
.get_boolean_from_string
),
498 (Link
.IFLA_BR_MCAST_QUERIER
, utils
.get_boolean_from_string
),
499 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, int),
500 (Link
.IFLA_BR_MCAST_HASH_MAX
, int),
501 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, int),
502 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, int),
503 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, lambda x
: int(x
) * 100),
504 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, lambda x
: int(x
) * 100),
505 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, lambda x
: int(x
) * 100),
506 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, lambda x
: int(x
) * 100),
507 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, lambda x
: int(x
) * 100),
508 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, lambda x
: int(x
) * 100),
509 # Link.IFLA_BR_NF_CALL_IPTABLES,
510 # Link.IFLA_BR_NF_CALL_IP6TABLES,
511 # Link.IFLA_BR_NF_CALL_ARPTABLES,
512 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
514 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, utils
.get_boolean_from_string
),
515 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, int),
516 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, utils
.get_boolean_from_string
),
517 (Link
.IFLA_BR_MCAST_MLD_VERSION
, int)
521 _ifla_brport_attributes_map
= (
522 # Link.IFLA_BRPORT_UNSPEC,
523 # Link.IFLA_BRPORT_STATE,
524 ('bridge-portprios', Link
.IFLA_BRPORT_PRIORITY
),
525 ('bridge-pathcosts', Link
.IFLA_BRPORT_COST
),
526 # Link.IFLA_BRPORT_MODE,
527 # Link.IFLA_BRPORT_GUARD,
528 # Link.IFLA_BRPORT_PROTECT,
529 ('bridge-portmcfl', Link
.IFLA_BRPORT_FAST_LEAVE
),
530 ('bridge-learning', Link
.IFLA_BRPORT_LEARNING
),
531 ('bridge-unicast-flood', Link
.IFLA_BRPORT_UNICAST_FLOOD
),
532 # Link.IFLA_BRPORT_PROXYARP,
533 # Link.IFLA_BRPORT_LEARNING_SYNC,
534 # Link.IFLA_BRPORT_PROXYARP_WIFI,
535 # Link.IFLA_BRPORT_ROOT_ID,
536 # Link.IFLA_BRPORT_BRIDGE_ID,
537 # Link.IFLA_BRPORT_DESIGNATED_PORT,
538 # Link.IFLA_BRPORT_DESIGNATED_COST,
539 # Link.IFLA_BRPORT_ID,
540 # Link.IFLA_BRPORT_NO,
541 # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
542 # Link.IFLA_BRPORT_CONFIG_PENDING,
543 # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
544 # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
545 # Link.IFLA_BRPORT_HOLD_TIMER,
546 # Link.IFLA_BRPORT_FLUSH,
547 ('bridge-portmcrouter', Link
.IFLA_BRPORT_MULTICAST_ROUTER
),
548 # Link.IFLA_BRPORT_PAD,
549 ('bridge-multicast-flood', Link
.IFLA_BRPORT_MCAST_FLOOD
),
550 # Link.IFLA_BRPORT_MCAST_TO_UCAST,
551 # Link.IFLA_BRPORT_VLAN_TUNNEL,
552 # Link.IFLA_BRPORT_BCAST_FLOOD
553 ('bridge-l2protocol-tunnel', Link
.IFLA_BRPORT_GROUP_FWD_MASK
),
554 # Link.IFLA_BRPORT_PEER_LINK,
555 # Link.IFLA_BRPORT_DUAL_LINK,
556 ('bridge-arp-nd-suppress', Link
.IFLA_BRPORT_ARP_SUPPRESS
),
559 _ifla_brport_multicast_router_dict_to_int
= {
570 # callable to translate <interface-yes-no-0-1-list> to netlink value
571 _ifla_brport_attributes_translate_user_config_to_netlink_map
= dict(
573 (Link
.IFLA_BRPORT_PRIORITY
, int),
574 (Link
.IFLA_BRPORT_COST
, int),
575 (Link
.IFLA_BRPORT_MULTICAST_ROUTER
, lambda x
: bridge
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(x
, 0)),
576 (Link
.IFLA_BRPORT_FAST_LEAVE
, utils
.get_boolean_from_string
),
577 (Link
.IFLA_BRPORT_LEARNING
, utils
.get_boolean_from_string
),
578 (Link
.IFLA_BRPORT_UNICAST_FLOOD
, utils
.get_boolean_from_string
),
579 (Link
.IFLA_BRPORT_MCAST_FLOOD
, utils
.get_boolean_from_string
),
580 (Link
.IFLA_BRPORT_GROUP_FWD_MASK
, lambda x
: x
),
581 (Link
.IFLA_BRPORT_ARP_SUPPRESS
, utils
.get_boolean_from_string
)
585 def __init__(self
, *args
, **kargs
):
586 moduleBase
.__init
__(self
, *args
, **kargs
)
588 self
.name
= self
.__class
__.__name
__
590 self
._running
_vidinfo
= {}
591 self
._running
_vidinfo
_valid
= False
592 self
._resv
_vlan
_range
= self
._get
_reserved
_vlan
_range
()
593 self
.logger
.debug('%s: using reserved vlan range %s' % (self
.__class
__.__name
__, str(self
._resv
_vlan
_range
)))
595 self
.default_stp_on
= utils
.get_boolean_from_string(
596 policymanager
.policymanager_api
.get_attr_default(
597 module_name
=self
.__class
__.__name
__,
602 self
.default_vlan_stats
= policymanager
.policymanager_api
.get_attr_default(
603 module_name
=self
.__class
__.__name
__,
604 attr
='bridge-vlan-stats'
607 self
.warn_on_untagged_bridge_absence
= utils
.get_boolean_from_string(
608 policymanager
.policymanager_api
.get_module_globals(
609 module_name
=self
.__class
__.__name
__,
610 attr
='warn_on_untagged_bridge_absence'
613 self
.logger
.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
614 % self
.warn_on_untagged_bridge_absence
)
616 self
._vxlan
_bridge
_default
_igmp
_snooping
= policymanager
.policymanager_api
.get_module_globals(
617 self
.__class
__.__name
__,
618 'vxlan_bridge_default_igmp_snooping'
620 self
.logger
.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
621 % self
._vxlan
_bridge
_default
_igmp
_snooping
)
623 self
.arp_nd_suppress_only_on_vxlan
= utils
.get_boolean_from_string(
624 policymanager
.policymanager_api
.get_module_globals(
625 module_name
=self
.__class
__.__name
__,
626 attr
='allow_arp_nd_suppress_only_on_vxlan'
629 self
.logger
.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self
.arp_nd_suppress_only_on_vxlan
)
632 self
.bridge_allow_multiple_vlans
= utils
.get_boolean_from_string(
633 self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
636 # Cumulus Linux specific variable. Failure probably means that
637 # ifupdown2 is running a a different system.
638 self
.bridge_allow_multiple_vlans
= True
639 self
.logger
.debug('bridge: init: multiple vlans allowed %s' % self
.bridge_allow_multiple_vlans
)
641 self
.bridge_mac_iface_list
= policymanager
.policymanager_api
.get_module_globals(self
.__class
__.__name
__, 'bridge_mac_iface') or []
642 self
.bridge_mac_iface
= None, None # ifname, mac
644 self
.bridge_set_static_mac_from_port
= utils
.get_boolean_from_string(
645 policymanager
.policymanager_api
.get_module_globals(
646 self
.__class
__.__name
__, 'bridge_set_static_mac_from_port'
650 self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
= utils
.get_boolean_from_string(
651 policymanager
.policymanager_api
.get_module_globals(
652 module_name
=self
.__class
__.__name
__,
653 attr
="vxlan_bridge_igmp_snooping_enable_port_mcrouter"
658 self
.l2protocol_tunnel_callback
= {
659 'all': self
._l2protocol
_tunnel
_set
_all
,
660 'stp': self
._l2protocol
_tunnel
_set
_stp
,
661 'cdp': self
._l2protocol
_tunnel
_set
_cdp
,
662 'pvst': self
._l2protocol
_tunnel
_set
_pvst
,
663 'lldp': self
._l2protocol
_tunnel
_set
_lldp
,
664 'lacp': self
._l2protocol
_tunnel
_set
_lacp
667 self
.query_check_l2protocol_tunnel_callback
= {
668 'all': self
._query
_check
_l2protocol
_tunnel
_all
,
669 'stp': self
._query
_check
_l2protocol
_tunnel
_stp
,
670 'cdp': self
._query
_check
_l2protocol
_tunnel
_cdp
,
671 'pvst': self
._query
_check
_l2protocol
_tunnel
_pvst
,
672 'lldp': self
._query
_check
_l2protocol
_tunnel
_lldp
,
673 'lacp': self
._query
_check
_l2protocol
_tunnel
_lacp
677 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
678 if not ifla_brport_group_maskhi
:
679 ifla_brport_group_maskhi
= 0x1
681 ifla_brport_group_maskhi |
= 0x1
682 return ifla_brport_group_mask
, ifla_brport_group_maskhi
685 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
686 if not ifla_brport_group_maskhi
:
687 ifla_brport_group_maskhi
= 0x2
689 ifla_brport_group_maskhi |
= 0x2
690 return ifla_brport_group_mask
, ifla_brport_group_maskhi
693 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
694 if not ifla_brport_group_mask
:
695 ifla_brport_group_mask
= 0x1
697 ifla_brport_group_mask |
= 0x1
698 return ifla_brport_group_mask
, ifla_brport_group_maskhi
701 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
702 if not ifla_brport_group_mask
:
703 ifla_brport_group_mask
= 0x4
705 ifla_brport_group_mask |
= 0x4
706 return ifla_brport_group_mask
, ifla_brport_group_maskhi
709 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
710 if not ifla_brport_group_mask
:
711 ifla_brport_group_mask
= 0x4000
713 ifla_brport_group_mask |
= 0x4000
714 return ifla_brport_group_mask
, ifla_brport_group_maskhi
717 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
718 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
719 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
722 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
723 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x1
726 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
727 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x2
730 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
731 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x1
734 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
735 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4000
738 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
739 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4
742 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
743 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
745 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
746 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
747 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
748 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
750 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
751 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
752 return retval
and c1
#and c2
754 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
756 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
758 for brport_name
in ifaceobj
.lowerifaces
:
759 for obj
in ifaceobj_getfunc(brport_name
) or []:
760 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
761 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
762 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
763 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
764 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
765 % (ifaceobj
.name
, brport_name
))
768 vlan_id
= sub_intf_vlan_id
771 def check_bridge_port_vid_attrs(self
, ifaceobj
):
772 if (ifaceobj
.get_attr_value('bridge-access') and
773 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
774 ifaceobj
.get_attr_value('bridge-pvid'))):
775 self
.logger
.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
776 'will be ignored' % ifaceobj
.name
)
780 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
781 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
782 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
786 for port_name
in ports
:
787 port_obj_l
= ifaceobj_getfunc(port_name
)
788 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
789 self
.logger
.error('%s: %s: vlan sub-interface is not '
790 'supported in a vlan-aware bridge'
791 % (ifaceobj
.name
, port_name
))
794 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
795 self
.arp_nd_suppress_only_on_vxlan
and
796 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
797 self
.log_error('\'bridge-arp-nd-suppress\' is not '
798 'supported on a non-vxlan port %s'
804 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
805 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
806 'device (%s) is part of vlan aware bridge (%s)'
807 % (ifaceobj
.name
, bridgename
), ifaceobj
)
809 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
810 if not ifaceobj_getfunc
:
812 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
813 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
814 if ifaceobj
.get_attr_value('bridge-access'):
816 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
817 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
818 if not ifaceobj_upper_list
:
820 ifaceobj_upper
= ifaceobj_upper_list
[0]
821 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
822 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
823 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
824 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
827 or not self
._compare
_vids
(bridge_vids
,
830 self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
,
836 def _is_bridge(ifaceobj
):
837 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
838 ifaceobj
.get_attr_value_first('bridge-ports') or
839 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
841 def _get_ifaceobj_bridge_ports(self
, ifaceobj
):
844 for brport
in ifaceobj
.get_attr_value('bridge-ports') or []:
846 bridge_ports
.extend(brport
.split())
848 return ' '.join(bridge_ports
)
850 def _is_bridge_port(self
, ifaceobj
):
851 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
855 def check_valid_bridge(self
, ifaceobj
, ifname
):
856 if LinkUtils
.link_exists_nodryrun(ifname
) and not LinkUtils
.is_bridge(ifname
):
857 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
861 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
862 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
864 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
865 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
866 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
867 # for special vlan aware bridges, we need to add another bit
868 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
869 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
870 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
871 ifaceobj
.role |
= ifaceRole
.MASTER
872 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
873 return self
.parse_port_list(ifaceobj
.name
,
874 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
877 def get_dependent_ifacenames_running(self
, ifaceobj
):
878 self
._init
_command
_handlers
()
879 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
881 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
883 def _get_bridge_port_list(self
, ifaceobj
):
885 # port list is also available in the previously
886 # parsed dependent list. Use that if available, instead
887 # of parsing port expr again
888 port_list
= ifaceobj
.lowerifaces
891 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
893 return self
.parse_port_list(ifaceobj
.name
, ports
)
897 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
898 # When enslaving bridge-ports we need to return the exact user
899 # configured bridge ports list (bridge will inherit the mac of the
901 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
902 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
904 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
905 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
906 if not waitport_value
: return
908 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
909 if not waitportvals
: return
911 waitporttime
= int(waitportvals
[0])
913 self
.log_warn('%s: invalid waitport value \'%s\''
914 %(ifaceobj
.name
, waitportvals
[0]))
916 if waitporttime
<= 0: return
918 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
920 except IndexError, e
:
921 # ignore error and use all bridge ports
922 waitportlist
= portlist
924 if not waitportlist
: return
925 self
.logger
.info('%s: waiting for ports %s to exist ...'
926 %(ifaceobj
.name
, str(waitportlist
)))
927 starttime
= time
.time()
928 while ((time
.time() - starttime
) < waitporttime
):
929 if all([False for p
in waitportlist
930 if not self
.ipcmd
.link_exists(p
)]):
934 self
.log_warn('%s: unable to process waitport: %s'
935 %(ifaceobj
.name
, str(e
)))
937 def _enable_disable_ipv6(self
, port
, enable
='1'):
939 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
941 self
.logger
.info(str(e
))
943 def handle_ipv6(self
, ports
, state
, ifaceobj
=None):
945 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
) and
946 not ifaceobj
.get_attr_value('address') and not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
):
947 self
._enable
_disable
_ipv
6(ifaceobj
.name
, state
)
949 self
._enable
_disable
_ipv
6(p
, state
)
951 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
952 """ pretty print bridge port add errors.
953 since the commands are batched and the kernel only returns error
954 codes, this function tries to interpret some error codes
955 and prints clearer errors """
957 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
958 # Cumulus Linux specific error checks
960 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
962 for bport
in bridgeports
:
963 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
965 if currvlanid
!= vlanid
:
966 self
.log_error('%s: ' %bridgeifaceobj
.name
+
967 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
971 except Exception as e
:
972 errstr
+= '\n%s' % str(e
)
973 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
975 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
976 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
977 runningbridgeports
= []
979 self
.ipcmd
.batch_start()
980 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
981 self
.ipcmd
.batch_start()
982 # Delete active ports not in the new port list
983 if not ifupdownflags
.flags
.PERFMODE
:
984 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
985 if runningbridgeports
:
986 for bport
in runningbridgeports
:
987 if not bridgeports
or bport
not in bridgeports
:
988 self
.ipcmd
.link_set(bport
, 'nomaster')
989 # set admin DOWN on all removed ports
990 # that don't have config outside bridge
991 if not ifaceobj_getfunc(bport
):
992 netlink
.link_set_updown(bport
, "down")
993 # enable ipv6 for ports that were removed
994 self
.handle_ipv6([bport
], '0')
996 runningbridgeports
= []
998 self
.ipcmd
.batch_commit()
1002 newbridgeports
= Set(bridgeports
).difference(Set(runningbridgeports
))
1003 newly_enslaved_ports
= []
1005 newbridgeports_ordered
= []
1006 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
1007 if br_port
in newbridgeports
:
1008 newbridgeports_ordered
.append(br_port
)
1010 for bridgeport
in newbridgeports_ordered
:
1012 if (not ifupdownflags
.flags
.DRYRUN
and
1013 not self
.ipcmd
.link_exists(bridgeport
)):
1014 self
.log_error('%s: bridge port %s does not exist'
1015 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
1018 hwaddress
= self
.ipcmd
.link_get_hwaddress(bridgeport
)
1019 if not self
._valid
_ethaddr
(hwaddress
):
1020 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
1021 bridgeport
) + 'invalid ether addr %s'
1024 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
1025 newly_enslaved_ports
.append(bridgeport
)
1026 self
.handle_ipv6([bridgeport
], '1')
1027 self
.ipcmd
.addr_flush(bridgeport
)
1031 self
.ipcmd
.batch_commit()
1032 self
.ipcmd
.batch_start()
1033 except Exception, e
:
1034 self
.logger
.error(str(e
))
1037 self
.ipcmd
.batch_commit()
1038 except Exception, e
:
1039 self
._pretty
_print
_add
_ports
_error
(str(e
), ifaceobj
,
1044 self
.log_error('bridge configuration failed (missing ports)')
1046 return newly_enslaved_ports
1048 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1049 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1050 if not maxwait
: return
1052 maxwait
= int(maxwait
)
1054 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1057 if not maxwait
: return
1058 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1061 starttime
= time
.time()
1062 while ((time
.time() - starttime
) < maxwait
):
1063 if all([False for p
in portlist
1064 if self
.read_file_oneline(
1065 '/sys/class/net/%s/brif/%s/state'
1066 %(ifaceobj
.name
, p
)) != '3']):
1069 except Exception, e
:
1070 self
.log_warn('%s: unable to process maxwait: %s'
1071 %(ifaceobj
.name
, str(e
)))
1073 def _ints_to_ranges(self
, ints
):
1074 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
1076 yield b
[0][1], b
[-1][1]
1078 def _ranges_to_ints(self
, rangelist
):
1079 """ returns expanded list of integers given set of string ranges
1080 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
1084 for part
in rangelist
:
1086 a
, b
= part
.split('-')
1087 a
, b
= int(a
), int(b
)
1088 result
.extend(range(a
, b
+ 1))
1093 self
.logger
.warn('unable to parse vids \'%s\''
1094 %''.join(rangelist
))
1098 def _compress_into_ranges(self
, vids_ints
):
1099 return ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
1100 for start
, end
in self
._ints
_to
_ranges
(vids_ints
)]
1102 def _diff_vids(self
, vids1_ints
, vids2_ints
):
1103 return Set(vids2_ints
).difference(vids1_ints
), Set(vids1_ints
).difference(vids2_ints
)
1105 def _compare_vids(self
, vids1
, vids2
, pvid
=None):
1106 """ Returns true if the vids are same else return false """
1108 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
1109 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
1110 set_diff
= Set(vids1_ints
).symmetric_difference(vids2_ints
)
1111 if pvid
and int(pvid
) in set_diff
:
1112 set_diff
.remove(int(pvid
))
1118 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1120 # Sets old style igmp querier
1122 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1124 running_mcqv4src
= {}
1125 if not ifupdownflags
.flags
.PERFMODE
:
1126 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobj
.name
)
1128 srclist
= attrval
.split()
1133 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
1135 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1136 for v
in mcqs
.keys():
1137 self
.brctlcmd
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1138 elif not ifupdownflags
.flags
.PERFMODE
:
1139 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobj
.name
)
1140 if running_mcqv4src
:
1141 for v
in running_mcqv4src
.keys():
1142 self
.brctlcmd
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1144 def _get_running_vidinfo(self
):
1145 if self
._running
_vidinfo
_valid
:
1146 return self
._running
_vidinfo
1147 self
._running
_vidinfo
= {}
1149 # Removed check for PERFMODE. Need the get in all cases
1150 # including reboot, so that we can configure the pvid correctly.
1151 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all_json()
1152 self
._running
_vidinfo
_valid
= True
1153 return self
._running
_vidinfo
1155 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1157 # Supports old style vlan vid info format
1160 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1161 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1162 if not bridge_port_pvids
and not bridge_port_vids
:
1165 # Handle bridge vlan attrs
1167 if bridge_port_pvids
:
1168 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1170 self
.log_warn('%s: could not parse \'%s %s\''
1171 %(ifaceobj
.name
, 'bridge-port-pvids',
1176 (port
, pvid
) = p
.split('=')
1178 running_pvid
= self
._get
_running
_pvid
(port
)
1180 if running_pvid
== pvid
:
1183 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
1184 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
1185 except Exception, e
:
1186 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1187 %(ifaceobj
.name
, p
, str(e
)))
1190 if bridge_port_vids
:
1191 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1193 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1194 'bridge-port-vids', bridge_port_vids
))
1198 (port
, val
) = p
.split('=')
1199 vids
= val
.split(',')
1200 vids_int
= self
._ranges
_to
_ints
(vids
)
1201 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
1203 (vids_to_del
, vids_to_add
) = \
1204 self
._diff
_vids
(vids_int
, running_vids
)
1206 self
.ipcmd
.bridge_port_vids_del(port
,
1207 self
._compress
_into
_ranges
(vids_to_del
))
1209 self
.ipcmd
.bridge_port_vids_add(port
,
1210 self
._compress
_into
_ranges
(vids_to_add
))
1212 self
.ipcmd
.bridge_port_vids_add(port
, vids_int
)
1213 except Exception, e
:
1214 self
.log_warn('%s: failed to set vid `%s` (%s)'
1215 %(ifaceobj
.name
, p
, str(e
)))
1217 def _is_running_stp_state_on(self
, bridgename
):
1218 """ Returns True if running stp state is on, else False """
1220 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1222 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1223 return running_stp_state
and running_stp_state
!= '0'
1227 def _is_config_stp_state_on(self
, ifaceobj
):
1228 """ Returns true if user specified stp state is on, else False """
1230 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1232 return self
.default_stp_on
1233 return utils
.get_boolean_from_string(stp_attr
)
1235 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1236 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1241 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1242 if self
._vxlan
_bridge
_default
_igmp
_snooping
is not None:
1243 return self
._vxlan
_bridge
_default
_igmp
_snooping
1245 return self
.get_attr_default_value("bridge-mcsnoop")
1247 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1255 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1257 if not callable(translate_func
):
1261 user_config
= policymanager
.policymanager_api
.get_iface_default(
1262 module_name
=self
.__class
__.__name
__,
1267 old_cache_key
= self
._ifla
_br
_attributes
_old
_cache
_key
_map
.get(nl_attr
)
1268 if old_cache_key
and not link_just_created
:
1269 cached_value
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', old_cache_key
])
1270 if not cached_value
or cached_value
== "None":
1271 # the link already exists but we don't have any value
1272 # cached for this attr, it probably means that the
1273 # capability is not available on this system (i.e old kernel)
1274 self
.logger
.debug('%s: ignoring %s %s: capability '
1275 'probably not supported on this system'
1276 % (ifname
, attr_name
, user_config
))
1278 # we need to convert the cache value to "netlink" format
1279 cached_value
= translate_func(cached_value
.lower())
1283 if not user_config
and not link_just_created
and cached_value
is not None:
1284 # there is no user configuration for this attribute
1285 # if the bridge existed before we need to check if
1286 # this attribute needs to be reset to default value
1287 default_value
= self
.get_attr_default_value(attr_name
)
1290 # the attribute has a default value, we need to convert it to
1291 # netlink format to compare it with the cache value
1292 default_value_nl
= translate_func(default_value
) # default_value.lower()
1294 if default_value_nl
!= cached_value
:
1295 # the running value difers from the default value
1296 # but the user didn't specify any config
1297 # resetting attribute to default
1298 ifla_info_data
[nl_attr
] = default_value_nl
1299 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1301 user_config_nl
= translate_func(user_config
) # user_config.lower()
1303 if user_config_nl
!= cached_value
:
1304 ifla_info_data
[nl_attr
] = user_config_nl
1306 if cached_value
is not None:
1307 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1309 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1310 except Exception as e
:
1311 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1313 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1314 ifla_info_data
= dict()
1315 ifname
= ifaceobj
.name
1317 self
.logger
.info('%s: apply bridge settings' % ifname
)
1319 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
:
1320 self
.fill_ifla_info_data_with_ifla_br_attribute(
1321 ifla_info_data
=ifla_info_data
,
1322 link_just_created
=link_just_created
,
1325 attr_name
=attr_name
,
1326 user_config
=ifaceobj
.get_attr_value_first(attr_name
)
1330 self
.fill_ifla_info_data_with_ifla_br_attribute(
1331 ifla_info_data
=ifla_info_data
,
1332 link_just_created
=link_just_created
,
1334 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1335 attr_name
='bridge-mcsnoop',
1336 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
)
1340 if bridge_vlan_aware
:
1341 self
.fill_ifla_info_data_with_ifla_br_attribute(
1342 ifla_info_data
=ifla_info_data
,
1343 link_just_created
=link_just_created
,
1345 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1346 attr_name
='bridge-vlan-stats',
1347 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
1351 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1352 if not self
._is
_running
_stp
_state
_on
(ifname
):
1353 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1354 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1355 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1356 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1357 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1359 # If stp not specified and running stp state on, set it to off
1360 if self
._is
_running
_stp
_state
_on
(ifname
):
1361 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1362 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1363 except Exception as e
:
1364 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1367 netlink
.link_add_set(ifname
=ifname
, kind
='bridge', ifla_info_data
=ifla_info_data
, link_exists
=True)
1369 def _check_vids(self
, ifaceobj
, vids
):
1374 va
, vb
= v
.split('-')
1375 va
, vb
= int(va
), int(vb
)
1376 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1379 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1380 except exceptions
.ReservedVlanException
as e
:
1383 self
.logger
.warn('%s: unable to parse vid \'%s\''
1384 %(ifaceobj
.name
, v
))
1387 def _get_running_pvid(self
, ifacename
):
1390 running_vidinfo
= self
._get
_running
_vidinfo
()
1391 for vinfo
in running_vidinfo
.get(ifacename
, {}):
1392 v
= vinfo
.get('vlan')
1393 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1398 def _get_running_vids_n_pvid_str(self
, ifacename
):
1402 (vids
, pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(ifacename
)
1405 ret_vids
= self
._compress
_into
_ranges
(vids
)
1410 ret_pvid
= '%s' %pvid
1413 return (ret_vids
, ret_pvid
)
1415 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1417 """ This method is a combination of methods _apply_bridge_vids and
1418 _apply_bridge_port_pvids above. A combined function is
1419 found necessary to do the deletes first and the adds later
1420 because kernel does honor vid info flags during deletes.
1423 if not isbridge
and bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1424 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1425 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1426 bportifaceobj
.upperifaces
[0])
1429 vids_int
= self
._ranges
_to
_ints
(vids
)
1431 pvid_int
= int(pvid
) if pvid
else 0
1433 self
.logger
.warn('%s: unable to parse pvid \'%s\''
1434 %(bportifaceobj
.name
, pvid
))
1439 vids_to_add
= vids_int
1441 pvid_to_add
= pvid_int
1444 if not self
._check
_vids
(bportifaceobj
, vids
):
1447 (running_vids
, running_pvid
) = self
.ipcmd
.bridge_vlan_get_vids_n_pvid(
1450 if not running_vids
and not running_pvid
:
1451 # There cannot be a no running pvid.
1452 # It might just not be in our cache:
1453 # this can happen if at the time we were
1454 # creating the bridge vlan cache, the port
1455 # was not part of the bridge. And we need
1456 # to make sure both vids and pvid is not in
1457 # the cache, to declare that our cache may
1463 (vids_to_del
, vids_to_add
) = \
1464 self
._diff
_vids
(vids_to_add
, running_vids
)
1467 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1468 pvid_to_del
= running_pvid
1470 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1471 (pvid_to_del
not in vids_to_add
)):
1472 # kernel deletes dont take into account
1473 # bridge vid flags and its possible that
1474 # the pvid deletes we do end up deleting
1475 # the vids. Be proactive and add the pvid
1476 # to the vid add list if it is in the vids
1477 # and not already part of vids_to_add.
1478 # This helps with a small corner case:
1482 # - new change is going to move the state to
1485 vids_to_add
.add(pvid_to_del
)
1486 except exceptions
.ReservedVlanException
as e
:
1488 except Exception, e
:
1489 self
.log_error('%s: failed to process vids/pvids'
1490 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1491 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1492 bportifaceobj
, raise_error
=False)
1495 if pvid_to_add
in vids_to_del
:
1496 vids_to_del
.remove(pvid_to_add
)
1497 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
1498 self
._compress
_into
_ranges
(
1499 vids_to_del
), isbridge
)
1500 except Exception, e
:
1501 self
.log_warn('%s: failed to del vid `%s` (%s)'
1502 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1506 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
1508 except Exception, e
:
1509 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1510 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1514 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
1515 self
._compress
_into
_ranges
(
1516 vids_to_add
), isbridge
)
1517 except Exception, e
:
1518 self
.log_error('%s: failed to set vid `%s` (%s)'
1519 %(bportifaceobj
.name
, str(vids_to_add
),
1520 str(e
)), bportifaceobj
, raise_error
=False)
1523 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1524 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
,
1526 except Exception, e
:
1527 self
.log_error('%s: failed to set pvid `%s` (%s)'
1528 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1531 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1538 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1540 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1542 allow_untagged
= 'yes'
1543 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1545 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1547 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1549 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1551 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1553 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1558 vids_final
= bridge_vids
1560 if allow_untagged
== 'yes':
1562 pvid_final
= pvids
[0]
1564 pvid_final
= bridge_pvid
1570 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1573 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1576 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1577 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1578 # Old style bridge port vid info
1579 # skip new style setting on ports
1581 self
.logger
.info('%s: applying bridge configuration '
1582 %ifaceobj
.name
+ 'specific to ports')
1584 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1586 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1590 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1592 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1596 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1597 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1598 port_processed_override
= True
1600 port_processed_override
= False
1602 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1604 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1606 self
.ipcmd
.batch_start()
1607 for bport
in bridgeports
:
1608 # Use the brctlcmd bulk set method: first build a dictionary
1610 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
1611 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1612 ' for port %s (missing port)' %bport
)
1614 self
.logger
.info('%s: processing bridge config for port %s'
1615 %(ifaceobj
.name
, bport
))
1616 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1617 if not bportifaceobjlist
:
1619 for bportifaceobj
in bportifaceobjlist
:
1620 # Dont process bridge port if it already has been processed
1621 # and there is no override on port_processed
1622 if (not port_processed_override
and
1623 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1624 bridgeFlags
.PORT_PROCESSED
)):
1627 # Add attributes specific to the vlan aware bridge
1628 if bridge_vlan_aware
:
1629 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1630 bportifaceobj
, bridge_vids
, bridge_pvid
)
1631 elif self
.warn_on_untagged_bridge_absence
:
1632 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1633 except exceptions
.ReservedVlanException
as e
:
1635 except Exception, e
:
1637 self
.logger
.warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1639 self
.ipcmd
.bridge_batch_commit()
1641 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1643 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1644 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1645 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1646 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1647 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1648 self
.logger
.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1649 self
.warn_on_untagged_bridge_absence
= False
1651 def bridge_port_get_bridge_name(self
, ifaceobj
):
1652 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1654 # bridge port is not enslaved to a bridge we need to find
1655 # the bridge in it's upper ifaces then enslave it
1656 for u
in ifaceobj
.upperifaces
:
1657 if self
.ipcmd
.is_bridge(u
):
1660 # return should_enslave port, bridgename
1661 return False, bridgename
1663 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1664 if should_enslave_port
:
1665 netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1666 self
.handle_ipv6([ifaceobj
.name
], '1')
1668 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1669 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1671 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1672 except Exception as e
:
1673 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1676 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1677 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1680 # bridge doesn't exist
1683 vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridge_name
)
1684 if vlan_aware_bridge
:
1685 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1688 should_enslave_port
)
1690 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1692 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1693 ifaceobj
=bridge_ifaceobj
,
1694 ifaceobj_getfunc
=ifaceobj_getfunc
,
1695 bridge_vlan_aware
=vlan_aware_bridge
)
1697 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1699 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_exists
):
1700 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1701 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1704 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1709 def parse_interface_list_value(user_config
):
1711 for entry
in user_config
.split():
1712 ifname
, value
= entry
.split('=')
1713 config
[ifname
] = value
1716 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, bridge_vlan_aware
, brport_ifaceobj
,
1717 brport_name
, brport_ifla_info_slave_data
, brport_learning
):
1719 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1721 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1723 Checks are not performed in this function and must be verified
1724 before. This is done this way to avoid calling this method on
1725 non vlan & bridge port interfaces thus wasting a bit less time
1731 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first('vxlan-learning')
1732 # if the user explicitly defined vxlan-learning we need to honor his config
1733 # and not sync vxlan-learning with bridge-learning
1735 brport_vxlan_learning
= self
.ipcmd
.get_vxlandev_learning(brport_name
)
1737 # if BRIDGE_LEARNING is in the desired configuration
1738 # and differs from the running vxlan configuration
1739 if brport_learning
is not None and brport_learning
!= brport_vxlan_learning
and not brport_vxlan_learning_config
:
1741 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_learning
}
1742 self
.logger
.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
1743 % (bridge_name
, brport_name
, brport_learning
))
1745 elif brport_learning
is None and bridge_vlan_aware
:
1746 # is bridge-learning is not configured but the bridge is vlan-aware
1748 running_value
= self
.ipcmd
.get_brport_learning_bool(brport_name
)
1749 default_value
= utils
.get_boolean_from_string(self
.get_mod_subattr('bridge-learning', 'default'))
1751 if default_value
!= running_value
:
1752 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] = default_value
1754 if not brport_vxlan_learning_config
:
1756 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: default_value
}
1757 self
.logger
.info('%s: %s: reset brport learning to %s and sync vxlan learning'
1758 % (bridge_name
, brport_name
, default_value
))
1760 # if kind and ifla_info_data are set they will be added to the
1761 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
1762 return kind
, ifla_info_data
1764 def check_vxlan_brport_arp_suppress(self
, ifaceobj
, bridge_vlan_aware
, brport_ifaceobj
, brport_name
, user_config
):
1766 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1767 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
1768 'is not supported on a non-vxlan port'
1769 % (ifaceobj
.name
, brport_name
))
1771 elif (bridge_vlan_aware
and
1772 (not self
.arp_nd_suppress_only_on_vxlan
or
1773 (self
.arp_nd_suppress_only_on_vxlan
and
1774 brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
1775 return self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
1778 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
1779 ifname
= ifaceobj
.name
1782 brports_ifla_info_slave_data
= dict()
1783 brport_ifaceobj_dict
= dict()
1785 running_brports
= self
.brctlcmd
.get_bridge_ports(ifname
)
1789 for brport_name
in target_ports
:
1790 if brport_name
not in running_brports
:
1791 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
1793 new_targets
.append(brport_name
)
1794 running_brports
= new_targets
1796 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, running_brports
))
1798 # If target_ports is specified we want to configure only this
1799 # sub-list of port we need to check if these ports are already
1800 # enslaved, if not they will be ignored.
1801 # If target_ports is not populated we will apply the brport
1802 # attributes on all running brport.
1804 for port
in running_brports
:
1805 brport_list
= ifaceobj_getfunc(port
)
1807 brport_ifaceobj_dict
[port
] = brport_list
[0]
1808 brports_ifla_info_slave_data
[port
] = dict()
1810 bridge_ports_learning
= {}
1812 # we iterate through all IFLA_BRPORT supported attributes
1813 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
:
1814 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
1815 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1817 if not translate_func
:
1818 # if no translation function is found,
1819 # we ignore this attribute and continue
1823 # user didn't specify any value for this attribute
1824 # looking at policy overrides
1825 br_config
= policymanager
.policymanager_api
.get_iface_default(
1826 module_name
=self
.__class
__.__name
__,
1832 #if bridge_vlan_aware:
1833 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
1834 # 'should be configured under the ports'
1835 # % (ifname, attr_name, br_config))
1837 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
1838 # brport_name: { attr: value }
1840 # bridge-portprios swp1=5 swp2=32
1841 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
1842 if '=' in br_config
:
1844 br_config
= self
.parse_interface_list_value(br_config
)
1846 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
1849 for brport_ifaceobj
in brport_ifaceobj_dict
.values():
1850 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
1851 brport_name
= brport_ifaceobj
.name
1853 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
1854 # if the port has just been enslaved, info_slave_data is not cached yet
1855 cached_value
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', nl_attr
])
1859 if not brport_config
:
1860 # if a brport attribute was specified under the bridge and not under the port
1861 # we assign the bridge value to the port. If an attribute is both defined under
1862 # the bridge and the brport we keep the value of the port and ignore the br val.
1863 if type(br_config
) == dict:
1864 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
1865 # br_config is a dictionary, example:
1866 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
1867 brport_config
= br_config
.get(brport_name
)
1869 brport_config
= br_config
1871 if not brport_config
:
1872 brport_config
= policymanager
.policymanager_api
.get_iface_default(
1873 module_name
=self
.__class
__.__name
__,
1878 user_config
= brport_config
1880 # attribute specific work
1881 # This shouldn't be here but we don't really have a choice otherwise this
1882 # will require too much code duplication and will make the code very complex
1883 if nl_attr
== Link
.IFLA_BRPORT_ARP_SUPPRESS
:
1885 arp_suppress
= self
.check_vxlan_brport_arp_suppress(ifaceobj
,
1891 user_config
= arp_suppress
1894 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
1895 # special handking for group_fwd_mask because Cisco proprietary
1896 # protocol needs to be set via a private netlink attribute
1897 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
1898 brports_ifla_info_slave_data
,
1899 user_config
, cached_value
)
1903 # if not bridge_vlan_aware:
1904 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
1905 # 'should be configured under the bridge'
1906 # % (ifname, brport_name,
1907 # attr_name, brport_config))
1910 user_config_nl
= translate_func(user_config
)
1911 # check config value against running value
1912 if user_config_nl
!= cached_value
:
1913 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
1914 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
1915 self
.logger
.debug('(cache %s)' % cached_value
)
1917 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
1918 # for vxlan-learning sync purposes we need to save the user config for each brports.
1919 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
1920 # IFLA_BRPORT_LEARNING if the user value is already configured and running
1921 # nevertheless we still need to check if the vxlan-learning is rightly synced with
1922 # the brport since it might go out of sync for X and Y reasons.
1923 bridge_ports_learning
[brport_name
] = user_config_nl
1925 elif cached_value
is not None:
1926 # no config found, do we need to reset to default?
1927 default
= self
.get_attr_default_value(attr_name
)
1929 default_netlink
= translate_func(default
)
1931 if (nl_attr
== Link
.IFLA_BRPORT_LEARNING
1932 and not ifupdownflags
.flags
.PERFMODE
1933 and brport_name
not in newly_enslaved_ports
):
1935 if self
.ipcmd
.get_brport_peer_link(brport_name
):
1936 if default_netlink
!= cached_value
:
1937 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
1938 % (ifname
, brport_name
))
1940 bridge_ports_learning
[brport_name
] = default_netlink
1941 except Exception as e
:
1942 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
1944 if default_netlink
!= cached_value
:
1945 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
1946 % (ifname
, brport_name
, attr_name
, default
))
1947 self
.logger
.debug('(cache %s)' % cached_value
)
1948 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
1950 # applying bridge port configuration via netlink
1951 for brport_name
, brport_ifla_info_slave_data
in brports_ifla_info_slave_data
.items():
1953 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
1955 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
1956 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1957 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
1958 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
1959 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
1963 brport_ifla_info_slave_data
,
1964 bridge_ports_learning
.get(brport_name
))
1966 cached_bridge_mcsnoop
= self
.brctlcmd
.link_cache_get([ifname
, 'linkinfo', Link
.IFLA_BR_MCAST_SNOOPING
])
1968 if (self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
1969 self
.get_bridge_mcsnoop_value(ifaceobj
)
1970 )) or cached_bridge_mcsnoop
:
1971 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
1972 # is on and mcsnoop is on (or mcsnoop is already enabled on the
1973 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
1974 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
):
1975 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
1976 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
1981 if brport_ifla_info_slave_data
or ifla_info_data
:
1983 netlink
.link_add_set(ifname
=brport_name
,
1985 ifla_info_data
=ifla_info_data
,
1986 slave_kind
='bridge',
1987 ifla_info_slave_data
=brport_ifla_info_slave_data
)
1988 except Exception as e
:
1989 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
1991 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
1992 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
1993 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
1995 except Exception as e
:
1996 self
.log_error(str(e
), ifaceobj
)
1998 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
2000 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
2001 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
2002 field we need to have special handling for that.
2004 ifla_brport_group_fwd_mask
= 0
2005 ifla_brport_group_fwd_maskhi
= 0
2007 for group
in re
.split(',|\s*', user_config
):
2011 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2013 if not callable(callback
):
2014 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2016 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2018 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2019 cached_ifla_brport_group_fwd_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2021 log_mask_change
= True
2022 # if user specify bridge-l2protocol-tunnel stp cdp
2023 # we need to set both MASK and MASKHI but we only want to log once
2025 if cached_ifla_brport_group_fwd_mask
is None:
2026 cached_ifla_brport_group_fwd_mask
= 0
2027 if cached_ifla_brport_group_fwd_maskhi
is None:
2028 cached_ifla_brport_group_fwd_maskhi
= 0
2030 # if the cache value is None it means that the kernel doesn't support this attribute
2031 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2033 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2035 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2036 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2037 log_mask_change
= False
2038 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2040 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2042 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2043 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2044 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2046 def get_bridge_mtu(self
, ifaceobj
):
2047 user_config_mtu
= ifaceobj
.get_attr_value_first("mtu")
2049 if not user_config_mtu
:
2050 user_config_mtu
= policymanager
.policymanager_api
.get_attr_default(
2051 module_name
=self
.__class
__.__name
__,
2057 mtu
= int(user_config_mtu
)
2058 self
.logger
.info("%s: set bridge mtu %s" % (ifaceobj
.name
, mtu
))
2060 except Exception as e
:
2061 self
.logger
.warning("%s: invalid bridge mtu %s: %s" % (ifaceobj
.name
, user_config_mtu
, str(e
)))
2064 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2065 ifname
= ifaceobj
.name
2067 if ifupdownflags
.flags
.PERFMODE
:
2068 link_just_created
= True
2071 link_exists
= self
.ipcmd
.link_exists(ifaceobj
.name
)
2072 link_just_created
= not link_exists
2075 netlink
.link_add_bridge(ifname
, self
.get_bridge_mtu(ifaceobj
))
2077 self
.logger
.info('%s: bridge already exists' % ifname
)
2079 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, not link_just_created
)
2081 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2084 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2085 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2086 newly_enslaved_ports
=newly_enslaved_ports
)
2087 except Exception as e
:
2088 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2092 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
2093 if not running_ports
:
2095 self
.handle_ipv6([], '1', ifaceobj
=ifaceobj
)
2096 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2097 ifaceobj_getfunc
=ifaceobj_getfunc
,
2098 bridge_vlan_aware
=bridge_vlan_aware
)
2099 except exceptions
.ReservedVlanException
as e
:
2101 except Exception as e
:
2102 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2104 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2105 for p
in running_ports
:
2106 ifaceobj_list
= ifaceobj_getfunc(p
)
2107 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2108 netlink
.link_set_updown(p
, "down")
2111 netlink
.link_set_updown(p
, "up")
2112 except Exception, e
:
2113 self
.logger
.debug('%s: %s: link set up (%s)'
2114 % (ifaceobj
.name
, p
, str(e
)))
2118 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2119 except Exception as e
:
2120 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2122 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2123 if self
.bridge_mac_iface
and self
.bridge_mac_iface
[0] and self
.bridge_mac_iface
[1]:
2124 return self
.bridge_mac_iface
2126 if self
.bridge_mac_iface_list
:
2127 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2129 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2130 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2134 for obj
in ifaceobj_list
:
2135 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2136 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2137 if iface_user_configured_hwaddress
:
2138 iface_mac
= iface_user_configured_hwaddress
2140 if not iface_mac
and not self
.ipcmd
.link_exists(bridge_mac_intf
):
2144 iface_mac
= self
.ipcmd
.cache_get('link', [bridge_mac_intf
, 'hwaddress'])
2145 # if hwaddress attribute is not configured we use the running mac addr
2147 self
.bridge_mac_iface
= (bridge_mac_intf
, iface_mac
)
2148 return self
.bridge_mac_iface
2149 elif self
.bridge_set_static_mac_from_port
:
2150 # no policy was provided, we need to get the first physdev or bond ports
2151 # and use its hwaddress to set the bridge mac
2152 for port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
) or []:
2153 # iterate through the bridge-port list
2154 for port_obj
in ifaceobj_getfunc(port
) or []:
2155 # check if the port is a physdev (link_kind is null) or a bon
2156 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2157 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2158 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2159 if iface_user_configured_hwaddress
:
2160 iface_mac
= iface_user_configured_hwaddress
.lower()
2161 # we need to "normalize" the user provided MAC so it can match with
2162 # what we have in the cache (data retrieved via a netlink dump by
2163 # nlmanager). nlmanager return all macs in lower-case
2165 iface_mac
= self
.ipcmd
.link_get_hwaddress(port
)
2168 self
.bridge_mac_iface
= (port
, iface_mac
)
2169 return self
.bridge_mac_iface
2173 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2174 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2175 self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2177 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2179 We have a day one bridge mac changing problem with changing ports
2180 (basically bridge mac changes when the port it inherited the mac from
2183 We have discussed this problem many times before and tabled it.
2184 The issue has aggravated with vxlan bridge ports having auto-generated
2185 random macs...which change on every reboot.
2187 ifupdown2 extract from policy files an iface to select a mac from and
2188 configure it automatically.
2190 if ifaceobj
.get_attr_value('hwaddress'):
2191 # if the user configured a static hwaddress
2192 # there is no need to assign one
2195 ifname
= ifaceobj
.name
2196 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2197 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2198 %(ifname
, mac_intf
, bridge_mac
))
2201 # if an interface is configured with the following attribute:
2202 # hwaddress 08:00:27:42:42:4
2203 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2204 # from the kernel. The only way to counter that is to convert all mac to int
2205 # and compare the ints, it will increase perfs and be safer.
2206 cached_value
= self
.ipcmd
.cache_get('link', [ifname
, 'hwaddress'])
2207 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2208 if cached_value
and self
.ipcmd
.mac_str_to_int(cached_value
) == self
.ipcmd
.mac_str_to_int(bridge_mac
):
2209 # the bridge mac is already set to the bridge_mac_intf's mac
2212 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2214 self
.ipcmd
.link_set(ifname
, 'address', value
=bridge_mac
, force
=True)
2215 except Exception as e
:
2216 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2217 # log info this error because the user didn't explicitly configured this
2219 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.ipcmd
.link_get_hwaddress(ifname
))
2221 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2222 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2223 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2225 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2226 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2229 bridge_attributes
= self
._modinfo
.get('attrs', {}).keys()
2231 for ifaceobj_config_attr
in ifaceobj
.config
.keys():
2232 if ifaceobj_config_attr
in bridge_attributes
:
2233 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2234 % (ifaceobj
.name
, ifaceobj_config_attr
))
2236 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2237 if not self
._is
_bridge
(ifaceobj
):
2239 ifname
= ifaceobj
.name
2240 if not self
.ipcmd
.link_exists(ifname
):
2243 running_ports
= self
.brctlcmd
.get_bridge_ports(ifname
)
2245 self
.handle_ipv6(running_ports
, '0')
2246 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2247 map(lambda p
: netlink
.link_set_updown(p
, 'down'), running_ports
)
2248 except Exception as e
:
2249 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2251 netlink
.link_del(ifname
)
2253 if utils
.get_boolean_from_string(ifupdownconfig
.config
.get("ifreload_down_changed")):
2254 self
.ipcmd
.del_cache_entry(ifname
)
2255 for upper
in ifaceobj
.upperifaces
or []:
2257 self
.ipcmd
.del_cache_entry(upper
)
2260 except Exception as e
:
2261 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2262 self
.logger
.error(str(e
))
2263 # netlink exception already contains the ifname
2265 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2268 running_bridge_port_vids
= ''
2271 running_vids
= self
._get
_runing
_vids
(p
)
2273 running_bridge_port_vids
+= ' %s=%s' %(p
,
2274 ','.join(running_vids
))
2277 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2279 running_bridge_port_pvid
= ''
2282 running_pvid
= self
._get
_runing
_pvid
(p
)
2284 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2288 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2290 running_bridge_vids
= self
.ipcmd
.bridge_vlan_get_vids(ifaceobjrunning
.name
)
2291 if running_bridge_vids
:
2292 running_attrs
['bridge-vids'] = ','.join(self
._compress
_into
_ranges
(running_bridge_vids
))
2293 return running_attrs
2295 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2299 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2300 # so query the ports
2301 running_bridgeport_vids
= []
2302 running_bridgeport_pvids
= []
2303 for bport
in bridgeports
:
2304 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2306 running_bridgeport_vids
.append(' '.join(vids
))
2308 running_bridgeport_pvids
.append(pvid
)
2311 if running_bridgeport_vids
:
2312 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2313 if freq
== len(bridgeports
):
2314 running_attrs
['bridge-vids'] = vidval
2315 bridge_vids
= vidval
.split()
2318 if running_bridgeport_pvids
:
2319 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2320 if freq
== len(bridgeports
) and vidval
!= '1':
2321 running_attrs
['bridge-pvid'] = vidval
2322 bridge_pvid
= vidval
.split()[0]
2324 # Go through all bridge ports and find their vids
2325 for bport
in bridgeports
:
2326 bportifaceobj
= ifaceobj_getfunc(bport
)
2327 if not bportifaceobj
:
2331 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2332 if vids
and vids
!= bridge_vids
:
2334 if pvid
and pvid
!= bridge_pvid
:
2336 if bport_vids
and bport_pvid
in bport_vids
:
2337 bport_vids
.remove(bport_pvid
)
2338 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2339 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2340 bportifaceobj
[0].delete_config('bridge-pvid')
2341 bportifaceobj
[0].delete_config('bridge-vids')
2343 if bport_pvid
and bport_pvid
!= '1':
2344 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2346 # delete any stale bridge-vids under ports
2347 bportifaceobj
[0].delete_config('bridge-pvid')
2349 bportifaceobj
[0].replace_config('bridge-vids',
2350 ' '.join(bport_vids
))
2352 # delete any stale bridge-vids under ports
2353 bportifaceobj
[0].delete_config('bridge-vids')
2354 return running_attrs
2356 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2357 running_mcqv4src
= self
.brctlcmd
.bridge_get_mcqv4src_sysfs(ifaceobjrunning
.name
)
2358 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
2360 mcq
= ' '.join(mcqs
)
2363 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2364 bridge_vlan_aware
=False):
2368 skip_kernel_stp_attrs
= 0
2371 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2373 except Exception as e
:
2374 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2376 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
2377 if not tmpbridgeattrdict
:
2378 self
.logger
.warn('%s: unable to get bridge attrs'
2379 %ifaceobjrunning
.name
)
2380 return bridgeattrdict
2382 # Fill bridge_ports and bridge stp attributes first
2383 ports
= tmpbridgeattrdict
.get('ports')
2385 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
2386 stp
= tmpbridgeattrdict
.get('stp', 'no')
2387 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
2388 bridgeattrdict
['bridge-stp'] = [stp
]
2390 if stp
== 'yes' and userspace_stp
:
2391 skip_kernel_stp_attrs
= 1
2393 vlan_stats
= utils
.get_onff_from_onezero(
2394 tmpbridgeattrdict
.get('vlan-stats', None))
2396 vlan_stats
!= self
.get_mod_subattr('bridge-vlan-stats', 'default')):
2397 bridgeattrdict
['bridge-vlan-stats'] = [vlan_stats
]
2399 bool2str
= {'0': 'no', '1': 'yes'}
2400 # pick all other attributes
2401 for k
,v
in tmpbridgeattrdict
.items():
2404 if k
== 'ports' or k
== 'stp':
2407 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
2408 # only include igmp attributes if kernel stp is off
2410 attrname
= 'bridge-' + k
2411 mod_default
= self
.get_mod_subattr(attrname
, 'default')
2412 if v
!= mod_default
:
2413 # convert '0|1' running values to 'no|yes'
2414 if v
in bool2str
.keys() and bool2str
[v
] == mod_default
:
2416 bridgeattrdict
[attrname
] = [v
]
2418 if bridge_vlan_aware
:
2421 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
2425 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
2428 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
2431 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
2433 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
2435 if skip_kernel_stp_attrs
:
2436 return bridgeattrdict
2438 # Do this only for vlan-UNAWARE-bridge
2439 if ports
and not bridge_vlan_aware
:
2440 portconfig
= {'bridge-pathcosts' : '',
2441 'bridge-portprios' : '',
2442 'bridge-learning' : '',
2443 'bridge-unicast-flood' : '',
2444 'bridge-multicast-flood' : '',
2445 'bridge-arp-nd-suppress' : '',
2447 for p
, v
in ports
.items():
2448 v
= self
.brctlcmd
.bridge_get_pathcost(ifaceobjrunning
.name
, p
)
2449 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
2451 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
2453 v
= self
.brctlcmd
.bridge_get_portprio(ifaceobjrunning
.name
, p
)
2454 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
2456 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
2458 v
= utils
.get_onff_from_onezero(
2459 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2462 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
2463 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
2465 v
= utils
.get_onff_from_onezero(
2466 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2467 p
, 'unicast-flood'))
2469 v
!= self
.get_mod_subattr('bridge-unicast-flood',
2471 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
2473 v
= utils
.get_onff_from_onezero(
2474 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2475 p
, 'multicast-flood'))
2477 v
!= self
.get_mod_subattr('bridge-multicast-flood',
2479 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
2481 v
= utils
.get_onff_from_onezero(
2482 self
.brctlcmd
.get_bridgeport_attr(ifaceobjrunning
.name
,
2483 p
, 'arp-nd-suppress'))
2485 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
2487 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
2489 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
2492 return bridgeattrdict
2494 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
2495 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
2496 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
2498 mcqs
= attrval
.split()
2500 mcqsout
= ' '.join(mcqs
)
2501 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
2502 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
2504 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
2506 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
2508 running_bridge_port_vids
= ''
2509 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2511 self
.log_warn('%s: could not parse \'bridge-port-vids %s\''
2512 %(ifaceobj
.name
, attrval
))
2517 (port
, val
) = p
.split('=')
2518 vids
= val
.split(',')
2519 running_vids
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2521 if not self
._compare
_vids
(vids
, running_vids
):
2523 running_bridge_port_vids
+= ' %s=%s' %(port
,
2524 ','.join(running_vids
))
2526 running_bridge_port_vids
+= ' %s' %p
2529 except Exception, e
:
2530 self
.log_warn('%s: failure checking vid %s (%s)'
2531 %(ifaceobj
.name
, p
, str(e
)))
2533 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2534 running_bridge_port_vids
, 1)
2536 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
2539 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
2541 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
2543 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
2544 %(ifaceobj
.name
, attrval
))
2546 running_bridge_port_pvids
= ''
2550 (port
, pvid
) = p
.split('=')
2551 running_pvid
= self
.ipcmd
.bridge_vlan_get_vids(port
)
2552 if running_pvid
and running_pvid
== pvid
:
2553 running_bridge_port_pvids
+= ' %s' %p
2556 running_bridge_port_pvids
+= ' %s=%s' %(port
,
2558 except Exception, e
:
2559 self
.log_warn('%s: failure checking pvid %s (%s)'
2560 %(ifaceobj
.name
, pvid
, str(e
)))
2562 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2563 running_bridge_port_pvids
, 1)
2565 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
2566 running_bridge_port_pvids
, 0)
2568 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2570 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
2572 def _query_check_snooping_wdefault(self
, ifaceobj
):
2573 if (ifupdownflags
.flags
.WITHDEFAULTS
2574 and not self
._vxlan
_bridge
_default
_igmp
_snooping
2575 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
2576 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
2578 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
2579 ifaceobj_getfunc
=None):
2580 if not self
._is
_bridge
(ifaceobj
):
2582 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
2583 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
2586 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
2588 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
2589 self
.get_mod_attrs())
2590 #Add default attributes if --with-defaults is set
2591 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in ifaceattrs
:
2592 ifaceattrs
.append('bridge-stp')
2596 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
2597 if not runningattrs
:
2598 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
2601 except Exception, e
:
2602 self
.logger
.warn(str(e
))
2605 self
._query
_check
_support
_yesno
_attrs
(runningattrs
, ifaceobj
)
2607 filterattrs
= ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
2608 'bridge-port-pvids']
2610 diff
= Set(ifaceattrs
).difference(filterattrs
)
2612 if 'bridge-l2protocol-tunnel' in diff
:
2613 diff
.remove('bridge-l2protocol-tunnel')
2614 # bridge-l2protocol-tunnel requires separate handling
2616 if 'bridge-ports' in diff
:
2617 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, runningattrs
.get('ports', {}).keys(), ifaceobj_getfunc
)
2618 diff
.remove('bridge-ports')
2621 # get the corresponding ifaceobj attr
2622 v
= ifaceobj
.get_attr_value_first(k
)
2624 if ifupdownflags
.flags
.WITHDEFAULTS
and k
== 'bridge-stp':
2625 v
= 'on' if self
.default_stp_on
else 'off'
2628 rv
= runningattrs
.get(k
[7:])
2629 if k
== 'bridge-mcqv4src':
2631 if k
== 'bridge-maxwait' or k
== 'bridge-waitport':
2632 ifaceobjcurr
.update_config_with_status(k
, v
, 0)
2634 if k
== 'bridge-vlan-aware':
2635 rv
= self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
)
2636 if (rv
and v
== 'yes') or (not rv
and v
== 'no'):
2637 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2640 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
2642 elif k
== 'bridge-stp':
2643 # special case stp compare because it may
2644 # contain more than one valid values
2645 stp_on_vals
= ['on', 'yes']
2646 stp_off_vals
= ['off', 'no']
2647 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
2648 (v
in stp_off_vals
and rv
in stp_off_vals
)):
2649 ifaceobjcurr
.update_config_with_status('bridge-stp',
2652 ifaceobjcurr
.update_config_with_status('bridge-stp',
2654 elif k
in ['bridge-pathcosts',
2656 'bridge-portmcrouter',
2659 'bridge-unicast-flood',
2660 'bridge-multicast-flood',
2661 'bridge-arp-nd-suppress',
2663 if k
== 'bridge-arp-nd-suppress':
2664 brctlcmdattrname
= k
[7:]
2666 brctlcmdattrname
= k
[7:].rstrip('s')
2667 # for port attributes, the attributes are in a list
2668 # <portname>=<portattrvalue>
2671 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
2674 for vlistitem
in vlist
:
2676 (p
, v
) = vlistitem
.split('=')
2677 if k
in ['bridge-learning',
2678 'bridge-unicast-flood',
2679 'bridge-multicast-flood',
2680 'bridge-arp-nd-suppress',
2682 currv
= utils
.get_onoff_bool(
2683 self
.brctlcmd
.get_bridgeport_attr(
2687 currv
= self
.brctlcmd
.get_bridgeport_attr(
2691 currstr
+= ' %s=%s' %(p
, currv
)
2693 currstr
+= ' %s=%s' %(p
, 'None')
2695 if k
== 'bridge-portmcrouter':
2696 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(v
) != int(currv
):
2700 except Exception, e
:
2701 self
.log_warn(str(e
))
2703 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
2704 elif k
== 'bridge-vlan-stats' or k
== 'bridge-mcstats':
2705 rv
= utils
.get_onff_from_onezero(rv
)
2707 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2709 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2711 if k
== 'bridge-pvid' or k
== 'bridge-vids' or k
== 'bridge-trunk' or k
== 'bridge-allow-untagged':
2712 # bridge-pvid and bridge-vids on a bridge does
2713 # not correspond directly to a running config
2714 # on the bridge. They correspond to default
2715 # values for the bridge ports. And they are
2716 # already checked against running config of the
2717 # bridge port and reported against a bridge port.
2718 # So, ignore these attributes under the bridge.
2719 # Use '2' for ignore today. XXX: '2' will be
2720 # mapped to a defined value in subsequent patches.
2721 ifaceobjcurr
.update_config_with_status(k
, v
, 2)
2723 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
2725 elif v
.upper() != rv
.upper():
2726 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
2728 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
2730 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
2732 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
2733 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifaceobj
, ifaceobjcurr
, runningattrs
)
2735 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
2736 bridge_all_ports
= []
2737 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
2738 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
2740 if not running_port_list
and not bridge_all_ports
:
2743 ports_list_status
= 0 if not set(running_port_list
).symmetric_difference(bridge_all_ports
) else 1
2746 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
2747 # we want to display the same bridge-ports list as provided
2748 # in the interfaces file but if this list contains regexes or
2749 # globs, for now, we won't try to change it.
2750 if 'regex' in port_list
or 'glob' in port_list
:
2751 port_list
= running_port_list
2754 for i
in range(0, len(port_list
)):
2755 if port_list
[i
] in running_port_list
:
2756 ordered
.append(port_list
[i
])
2759 port_list
= running_port_list
2760 ifaceobjcurr
.update_config_with_status('bridge-ports', (' '.join(port_list
) if port_list
else ''), ports_list_status
)
2762 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
2763 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
2765 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
2768 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
2769 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
2771 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
2772 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2773 for ifaceobj
in ifaceobjs
:
2774 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
2775 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
2778 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
2779 ifaceobjs
= ifaceobj_getfunc(bridgename
)
2781 for ifaceobj
in ifaceobjs
:
2782 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2787 def _get_bridge_name(self
, ifaceobj
):
2788 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
2790 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
2791 ifaceobj_getfunc
, bridgename
):
2792 attr_name
= 'bridge-access'
2793 vid
= ifaceobj
.get_attr_value_first(attr_name
)
2795 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2797 if (not running_pvid
or running_pvid
!= vid
or
2798 (running_vids
and running_vids
[0] != vid
)):
2799 ifaceobjcurr
.update_config_with_status(attr_name
,
2802 ifaceobjcurr
.update_config_with_status(attr_name
, vid
, 0)
2805 (running_vids
, running_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
2807 attr_name
= 'bridge-pvid'
2808 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
2810 if running_pvid
and running_pvid
== pvid
:
2811 ifaceobjcurr
.update_config_with_status(attr_name
,
2814 ifaceobjcurr
.update_config_with_status(attr_name
,
2816 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2817 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2818 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2819 # if the interface has multiple iface sections,
2820 # we check the below only for the oldest sibling
2821 # or the last iface section
2822 pvid
= self
._get
_bridge
_pvid
(bridgename
, ifaceobj_getfunc
)
2824 if not running_pvid
or running_pvid
!= pvid
:
2825 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2826 ifaceobjcurr
.status_str
= 'bridge pvid error'
2827 elif not running_pvid
or running_pvid
!= '1':
2828 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2829 ifaceobjcurr
.status_str
= 'bridge pvid error'
2831 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
2833 vids
= re
.split(r
'[\s\t]\s*', vids
)
2834 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
,
2836 ifaceobjcurr
.update_config_with_status(attr_name
,
2837 ' '.join(running_vids
), 1)
2839 ifaceobjcurr
.update_config_with_status(attr_name
,
2841 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
2842 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
2843 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
2844 # if the interface has multiple iface sections,
2845 # we check the below only for the oldest sibling
2846 # or the last iface section
2848 # check if it matches the bridge vids
2849 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
2850 if (bridge_vids
and (not running_vids
or
2851 not self
._compare
_vids
(bridge_vids
, running_vids
, running_pvid
))):
2852 ifaceobjcurr
.status
= ifaceStatus
.ERROR
2853 ifaceobjcurr
.status_str
= 'bridge vid error'
2855 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
2857 if not self
._is
_bridge
_port
(ifaceobj
):
2858 # Mark all bridge attributes as failed
2859 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
2860 ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
2861 'bridge-pathcosts', 'bridge-portprios',
2862 'bridge-portmcrouter',
2864 'bridge-portmcfl', 'bridge-unicast-flood',
2865 'bridge-multicast-flood',
2866 'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
2869 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
2871 self
.logger
.warn('%s: unable to determine bridge name'
2875 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
2876 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
2879 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
2880 'bridge-portprios' : 'portprio',
2881 'bridge-portmcrouter' : 'portmcrouter',
2882 'bridge-portmcfl' : 'portmcfl',
2883 'bridge-learning' : 'learning',
2884 'bridge-unicast-flood' : 'unicast-flood',
2885 'bridge-multicast-flood' : 'multicast-flood',
2886 'bridge-arp-nd-suppress' : 'arp-nd-suppress',
2888 attrval
= ifaceobj
.get_attr_value_first(attr
)
2893 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
2894 bridgename
, ifaceobj
.name
, dstattr
)
2896 if dstattr
== 'portmcfl':
2897 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2898 running_attrval
= utils
.get_yesno_boolean(
2899 utils
.get_boolean_from_string(running_attrval
))
2900 elif dstattr
== 'portmcrouter':
2901 if self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(attrval
) == int(running_attrval
):
2902 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 0)
2904 ifaceobjcurr
.update_config_with_status(attr
, attrval
, 1)
2906 elif dstattr
in ['learning',
2911 if not utils
.is_binary_bool(attrval
) and running_attrval
:
2912 running_attrval
= utils
.get_onff_from_onezero(
2915 if running_attrval
!= attrval
:
2916 ifaceobjcurr
.update_config_with_status(attr
,
2919 ifaceobjcurr
.update_config_with_status(attr
,
2921 except Exception, e
:
2922 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
2924 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
2926 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
2927 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2929 if user_config_l2protocol_tunnel
:
2932 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
2933 except Exception as e
:
2934 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2936 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2938 def _query_check_l2protocol_tunnel_on_bridge(self
, ifaceobj
, ifaceobjcurr
, bridge_running_attrs
):
2940 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
2941 We need to make sure that all ports comply with the mask given under the bridge
2943 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2945 if user_config_l2protocol_tunnel
:
2946 if '=' in user_config_l2protocol_tunnel
:
2948 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
2949 brport_list
= config_per_port_dict
.keys()
2951 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
2954 config_per_port_dict
= {}
2955 brport_list
= bridge_running_attrs
.get('ports', {}).keys()
2958 for brport_name
in brport_list
:
2959 self
._query
_check
_l2protocol
_tunnel
(
2961 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
2964 except Exception as e
:
2965 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
2967 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
2969 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
2970 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2971 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2973 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
2974 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
2976 if callable(callback
):
2977 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2978 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
2979 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
2981 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
2982 cached_ifla_brport_group_maskhi
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
])
2983 cached_ifla_brport_group_mask
= self
.ipcmd
.cache_get_info_slave([brport_name
, 'info_slave_data', Link
.IFLA_BRPORT_GROUP_FWD_MASK
])
2984 running_protocols
= []
2985 for protocol_name
, callback
in self
.query_check_l2protocol_tunnel_callback
.items():
2986 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2987 running_protocols
= self
.query_check_l2protocol_tunnel_callback
.keys()
2988 running_protocols
.remove('all')
2990 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
2991 running_protocols
.append(protocol_name
)
2992 if running_protocols
:
2994 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
2995 elif bridge_ifaceobj
:
2996 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
2999 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
3001 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
3003 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
3004 if self
._is
_bridge
(ifaceobj
):
3005 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
3007 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
3010 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
3011 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
3012 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
3013 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
3016 bridge_vlan_aware
=True))
3018 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
3019 ifaceobjrunning
, None))
3021 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
3022 if self
.systcl_get_net_bridge_stp_user_space() == '1':
3025 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
3026 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
3027 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
3029 v
= self
.brctlcmd
.bridge_get_pathcost(bridgename
, ifaceobjrunning
.name
)
3030 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
3031 ifaceobjrunning
.update_config('bridge-portprios', v
)
3033 def _query_running_bridge_port(self
, ifaceobjrunning
,
3034 ifaceobj_getfunc
=None):
3036 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
3037 ifaceobjrunning
.name
)
3041 self
.logger
.warn('%s: unable to find bridgename'
3042 %ifaceobjrunning
.name
)
3045 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
3047 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
3048 except Exception as e
:
3049 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
3052 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
3054 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3055 ifaceobjrunning
.name
)
3056 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3057 bridge_port_vids
.remove(bridge_port_pvid
)
3059 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3060 if bridgeifaceobjlist
:
3061 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3062 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3064 if not bridge_port_vids
and bridge_port_pvid
:
3065 # must be an access port
3066 if bridge_port_pvid
!= '1':
3067 ifaceobjrunning
.update_config('bridge-access',
3070 if bridge_port_vids
:
3071 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3072 ifaceobjrunning
.update_config('bridge-vids',
3073 ' '.join(bridge_port_vids
))
3074 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3075 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3076 ifaceobjrunning
.update_config('bridge-pvid',
3079 v
= utils
.get_onff_from_onezero(
3080 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3081 ifaceobjrunning
.name
,
3083 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3084 ifaceobjrunning
.update_config('bridge-learning', v
)
3086 v
= utils
.get_onff_from_onezero(
3087 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3088 ifaceobjrunning
.name
,
3090 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3091 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3093 v
= utils
.get_onff_from_onezero(
3094 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3095 ifaceobjrunning
.name
,
3097 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3098 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3100 v
= utils
.get_onff_from_onezero(
3101 self
.brctlcmd
.get_bridgeport_attr(bridgename
,
3102 ifaceobjrunning
.name
,
3104 # Display running 'arp-nd-suppress' only on vxlan ports
3105 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3106 # otherwise, display on all bridge-ports
3108 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3110 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3111 (not self
.arp_nd_suppress_only_on_vxlan
or
3112 (self
.arp_nd_suppress_only_on_vxlan
and
3113 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3114 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3116 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3118 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
3120 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
3121 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
3122 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
3123 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
3124 except Exception as e
:
3125 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3127 def _query(self
, ifaceobj
, **kwargs
):
3128 """ add default policy attributes supported by the module """
3129 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
3130 ifaceobj
.get_attr_value_first('bridge-stp')):
3132 if self
.default_stp_on
:
3133 ifaceobj
.update_config('bridge-stp', 'yes')
3135 def _query_check_support_yesno_attrs(self
, runningattrs
, ifaceobj
):
3136 for attrl
in [['mcqifaddr', 'bridge-mcqifaddr'],
3137 ['mcquerier', 'bridge-mcquerier'],
3138 ['mcsnoop', 'bridge-mcsnoop']]:
3139 value
= ifaceobj
.get_attr_value_first(attrl
[1])
3140 if value
and not utils
.is_binary_bool(value
):
3141 if attrl
[0] in runningattrs
:
3142 bool = utils
.get_boolean_from_string(runningattrs
[attrl
[0]])
3143 runningattrs
[attrl
[0]] = utils
.get_yesno_boolean(bool)
3145 self
._query
_check
_mcrouter
(ifaceobj
, runningattrs
)
3146 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'portmcfl', ifaceobj
.get_attr_value_first('bridge-portmcfl'))
3147 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'learning', ifaceobj
.get_attr_value_first('bridge-learning'))
3148 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'unicast-flood', ifaceobj
.get_attr_value_first('bridge-unicast-flood'))
3149 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'multicast-flood', ifaceobj
.get_attr_value_first('bridge-multicast-flood'))
3150 self
._query
_check
_support
_yesno
_attr
_port
(runningattrs
, ifaceobj
, 'arp-nd-suppress', ifaceobj
.get_attr_value_first('bridge-arp-nd-suppress'))
3152 def _query_check_mcrouter(self
, ifaceobj
, running_attrs
):
3154 bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
3156 if 'mcrouter' in running_attrs
:
3157 value
= ifaceobj
.get_attr_value_first('bridge-mcrouter')
3162 running_attrs
['mcrouter'] = 'yes' if utils
.get_boolean_from_string(running_attrs
['mcrouter']) else 'no'
3164 def _query_check_support_yesno_attr_port(self
, runningattrs
, ifaceobj
, attr
, attrval
):
3166 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3170 (port
, val
) = p
.split('=')
3171 if not utils
.is_binary_bool(val
):
3172 to_convert
.append(port
)
3173 for port
in to_convert
:
3174 runningattrs
['ports'][port
][attr
] = utils
.get_yesno_boolean(
3175 utils
.get_boolean_from_string(runningattrs
['ports'][port
][attr
]))
3180 'query-checkcurr': _query_check
,
3181 'query-running': _query_running
,
3186 """ returns list of ops supported by this module """
3187 return self
._run
_ops
.keys()
3189 def _init_command_handlers(self
):
3191 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
3193 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
3194 """ run bridge configuration on the interface object passed as
3195 argument. Can create bridge interfaces if they dont exist already
3198 **ifaceobj** (object): iface object
3200 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
3204 **query_ifaceobj** (object): query check ifaceobject. This is only
3205 valid when op is 'query-checkcurr'. It is an object same as
3206 ifaceobj, but contains running attribute values and its config
3207 status. The modules can use it to return queried running state
3208 of interfaces. status is success if the running state is same
3209 as user required state in ifaceobj. error otherwise.
3211 op_handler
= self
._run
_ops
.get(operation
)
3214 self
._init
_command
_handlers
()
3216 if (not LinkUtils
.bridge_utils_is_installed
3217 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
3218 and LinkUtils
.bridge_utils_missing_warning
):
3219 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
3220 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
3221 LinkUtils
.bridge_utils_missing_warning
= False
3223 if operation
== 'query-checkcurr':
3224 op_handler(self
, ifaceobj
, query_ifaceobj
,
3225 ifaceobj_getfunc
=ifaceobj_getfunc
)
3227 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)