3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
11 from collections
import Counter
14 from ifupdown2
.lib
.addon
import Bridge
16 import ifupdown2
.ifupdown
.exceptions
as exceptions
17 import ifupdown2
.ifupdown
.policymanager
as policymanager
18 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
20 from ifupdown2
.nlmanager
.nlmanager
import Link
22 from ifupdown2
.ifupdown
.iface
import *
23 from ifupdown2
.ifupdown
.utils
import utils
25 from ifupdown2
.ifupdownaddons
.cache
import *
26 from ifupdown2
.ifupdownaddons
.modulebase
import moduleBase
27 except (ImportError, ModuleNotFoundError
):
28 from lib
.addon
import Bridge
30 import ifupdown
.exceptions
as exceptions
31 import ifupdown
.policymanager
as policymanager
32 import ifupdown
.ifupdownflags
as ifupdownflags
34 from nlmanager
.nlmanager
import Link
36 from ifupdown
.iface
import *
37 from ifupdown
.utils
import utils
39 from ifupdownaddons
.cache
import *
40 from ifupdownaddons
.modulebase
import moduleBase
45 PORT_PROCESSED_OVERRIDE
= 0x2
48 class BridgeVlanVniMapError(Exception):
52 class bridge(Bridge
, moduleBase
):
53 """ ifupdown2 addon module to configure linux bridges """
56 "mhelp": "Bridge configuration module. Supports both vlan aware and non "
57 "vlan aware bridges. For the vlan aware bridge, the port "
58 "specific attributes must be specified under the port. And for "
59 "vlan unaware bridge port specific attributes must be specified "
62 "bridge-vlan-aware": {
63 "help": "vlan aware bridge. Setting this "
64 "attribute to yes enables vlan filtering"
66 "validvals": ["yes", "no"],
67 "example": ["bridge-vlan-aware yes/no"],
71 "help": "bridge ports",
74 "validvals": ["<interface-list>", "none"],
76 "bridge-ports swp1.100 swp2.100 swp3.100",
77 "bridge-ports glob swp1-3.100",
78 "bridge-ports regex (swp[1|2|3].100)"
82 "help": "bridge-stp yes/no",
83 "example": ["bridge-stp no"],
84 "validvals": ["yes", "on", "off", "no"],
87 "bridge-bridgeprio": {
88 "help": "bridge priority",
89 "validrange": ["0", "65535"],
90 "example": ["bridge-bridgeprio 32768"],
94 "help": "bridge ageing",
95 "validrange": ["0", "65535"],
96 "example": ["bridge-ageing 300"],
100 "help": "bridge forward delay",
101 "validrange": ["0", "255"],
102 "example": ["bridge-fd 15"],
105 # XXX: recheck values
107 "help": "bridge garbage collection interval in secs",
108 "validrange": ["0", "255"],
109 "example": ["bridge-gcint 4"],
115 "help": "bridge set hello time",
116 "validrange": ["0", "255"],
117 "example": ["bridge-hello 2"],
121 "help": "bridge set maxage",
122 "validrange": ["0", "255"],
123 "example": ["bridge-maxage 20"],
126 "bridge-pathcosts": {
127 "help": "bridge set port path costs",
128 "validvals": ["<interface-range-list>"],
129 "validrange": ["0", "65535"],
131 "under the port (for vlan aware bridge): bridge-pathcosts 100",
132 "under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100"
136 "bridge-portprios": {
137 "help": "bridge port prios",
138 "validvals": ["<interface-range-list>"],
139 "validrange": ["0", "65535"],
141 "under the port (for vlan aware bridge): bridge-portprios 32",
142 "under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32"
146 "help": "set multicast last member count",
147 "validrange": ["0", "255"],
148 "example": ["bridge-mclmc 2"],
152 "help": "Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes",
153 "validvals": ["yes", "no", "0", "1", "2"],
154 "example": ["bridge-mcrouter 1"],
158 "help": "set multicast snooping",
159 "validvals": ["yes", "no", "0", "1"],
161 "example": ["bridge-mcsnoop yes"]
164 "help": "set multicast startup query count",
165 "validrange": ["0", "255"],
167 "example": ["bridge-mcsqc 2"]
169 "bridge-mcqifaddr": {
170 "help": "set multicast query to use ifaddr",
171 "validvals": ["yes", "no", "0", "1"],
173 "example": ["bridge-mcqifaddr no"]
175 "bridge-mcquerier": {
176 "help": "set multicast querier",
177 "validvals": ["yes", "no", "0", "1"],
179 "example": ["bridge-mcquerier no"]
182 "help": "set hash elasticity",
183 "validrange": ["0", "4096"],
185 "example": ["bridge-hashel 4096"]
188 "help": "set hash max",
189 "validrange": ["0", "65536"],
191 "example": ["bridge-hashmax 4096"]
194 "help": "set multicast last member interval (in secs)",
195 "validrange": ["0", "255"],
197 "example": ["bridge-mclmi 1"]
200 "help": "set multicast membership interval (in secs)",
202 "example": ["bridge-mcmi 260"]
205 "help": "set multicast querier interval (in secs)",
206 "validrange": ["0", "255"],
208 "example": ["bridge-mcqpi 255"]
211 "help": "set multicast query interval (in secs)",
212 "validrange": ["0", "255"],
214 "example": ["bridge-mcqi 125"]
217 "help": "set multicast query response interval (in secs)",
218 "validrange": ["0", "255"],
220 "example": ["bridge-mcqri 10"]
223 "help": "set multicast startup query interval (in secs)",
224 "validrange": ["0", "255"],
226 "example": ["bridge-mcsqi 31"]
229 "help": "set per VLAN v4 multicast querier source address",
230 "validvals": ["<number-ipv4-list>", ],
233 "example": ["bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1"]
235 "bridge-portmcrouter": {
236 "help": "Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled",
237 "validvals": ["<interface-disabled-automatic-enabled>"],
240 "under the port (for vlan aware bridge): bridge-portmcrouter 0",
241 "under the port (for vlan aware bridge): bridge-portmcrouter 1",
242 "under the port (for vlan aware bridge): bridge-portmcrouter 2",
243 "under the port (for vlan aware bridge): bridge-portmcrouter disabled",
244 "under the port (for vlan aware bridge): bridge-portmcrouter automatic",
245 "under the port (for vlan aware bridge): bridge-portmcrouter enabled",
246 "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2",
247 "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled",
248 "under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1",
252 "help": "port multicast fast leave.",
253 "validvals": ["<interface-yes-no-0-1-list>"],
256 "under the port (for vlan aware bridge): bridge-portmcfl no",
257 "under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no"
261 "help": "wait for a max of time secs for the"
262 " specified ports to become available,"
263 "if no ports are specified then those"
264 " specified on bridge-ports will be"
265 " used here. Specifying no ports here "
266 "should not be used if we are using "
267 "regex or \"all\" on bridge_ports,"
268 "as it wouldnt work.",
270 "validvals": ["<number-interface-list>"],
271 "example": ["bridge-waitport 4 swp1 swp2"]
274 "help": "forces to time seconds the maximum time "
275 "that the Debian bridge setup scripts will "
276 "wait for the bridge ports to get to the "
277 "forwarding status, doesn\"t allow factional "
278 "part. If it is equal to 0 then no waiting"
280 "validrange": ["0", "255"],
282 "example": ["bridge-maxwait 3"]
285 "help": "bridge port vids. Can be specified "
286 "under the bridge or under the port. "
287 "If specified under the bridge the ports "
288 "inherit it unless overridden by a "
289 "bridge-vids attribute under the port",
291 "validvals": ["<number-comma-range-list>"],
294 "bridge-vids 2000 2200-3000"
296 "aliases": ["bridge-trunk"]
299 "help": "bridge port pvid. Must be specified under"
301 "validrange": ["0", "4096"],
302 "example": ["bridge-pvid 1"]
305 "help": "bridge port access vlan. Must be "
306 "specified under the bridge port",
307 "validrange": ["1", "4094"],
308 "example": ["bridge-access 300"]
310 "bridge-allow-untagged": {
311 "help": "indicate if the bridge port accepts "
312 "untagged packets or not. Must be "
313 "specified under the bridge port. "
314 "Default is \"yes\"",
315 "validvals": ["yes", "no"],
316 "example": ["bridge-allow-untagged yes"],
319 "bridge-port-vids": {
320 "help": "bridge vlans",
322 "example": ["bridge-port-vids bond0=1-1000,1010-1020"]
324 "bridge-port-pvids": {
325 "help": "bridge port vlans",
327 "example": ["bridge-port-pvids bond0=100 bond1=200"]
330 "help": "bridge port learning flag",
331 "validvals": ["on", "off", "<interface-on-off-list>"],
333 "example": ["bridge-learning off"]
335 "bridge-igmp-version": {
336 "help": "mcast igmp version",
337 "validvals": ["2", "3"],
339 "example": ["bridge-igmp-version 2"]
341 "bridge-mld-version": {
342 "help": "mcast mld version",
343 "validvals": ["1", "2"],
345 "example": ["bridge-mld-version 1"]
347 "bridge-unicast-flood": {
348 "help": "bridge port unicast flood flag",
349 "validvals": ["on", "off", "<interface-on-off-list>"],
351 "example": ["under the port (for vlan aware bridge): bridge-unicast-flood on",
352 "under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on"]
354 "bridge-multicast-flood": {
355 "help": "bridge port multicast flood flag",
356 "validvals": ["on", "off", "<interface-on-off-list>"],
359 "under the port (for vlan aware bridge): bridge-multicast-flood on",
360 "under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on"
363 "bridge-broadcast-flood": {
364 "help": "bridge port broadcast flood flag",
365 "validvals": ["on", "off", "<interface-on-off-list>"],
368 "under the port (for vlan aware bridge): bridge-broadcast-flood on",
369 "under the bridge (for vlan unaware bridge): bridge-broadcast-flood swp1=on swp2=on"
372 "bridge-vlan-protocol": {
373 "help": "bridge vlan protocol",
375 "validvals": ["802.1q", "802.1ad"],
376 "example": ["bridge-vlan-protocol 802.1q"]
378 "bridge-vlan-stats": {
379 "help": "bridge vlan stats",
381 "validvals": ["on", "off"],
382 "example": ["bridge-vlan-stats off"]
384 "bridge-arp-nd-suppress": {
385 "help": "bridge port arp nd suppress flag",
386 "validvals": ["on", "off", "<interface-on-off-list>"],
389 "under the port (for vlan aware bridge): bridge-arp-nd-suppress on",
390 "under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on"
394 "help": "bridge multicast stats",
396 "validvals": ["on", "off", "1", "0", "yes", "no"],
397 "example": ["bridge-mcstats off"]
399 "bridge-l2protocol-tunnel": {
400 "help": "layer 2 protocol tunneling",
401 "validvals": [ # XXX: lists all combinations, should move to
402 # a better representation
407 "cdp lacp lldp pvst",
422 "lacp lldp pvst stp",
434 "<interface-l2protocol-tunnel-list>"],
436 "under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all",
437 "under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst",
438 "under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst",
439 "under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp",
440 "under the port (for vlan aware bridge): bridge-l2protocol-tunnel all"
443 "bridge-ports-condone-regex": {
444 "help": "bridge ports to ignore/condone when reloading config / removing interfaces",
446 "example": ["bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$"]
448 "bridge-vlan-vni-map": {
449 "help": "Single vxlan support",
450 "example": ["bridge-vlan-vni-map 1000-1001=1000-1001"],
452 "bridge-always-up": {
453 "help": "Enabling this attribute on a bridge will enslave a dummy interface to the bridge",
455 "validvals": ["yes", "no", "on", "off"]
460 bridge_utils_missing_warning
= True
462 # Netlink attributes not associated with ifupdown2
463 # attributes are left commented-out for a future use
464 # and kept in order :)
465 _ifla_br_attributes_map
= {
466 # Link.IFLA_BR_UNSPEC,
467 'bridge-fd': Link
.IFLA_BR_FORWARD_DELAY
,
468 'bridge-hello': Link
.IFLA_BR_HELLO_TIME
,
469 'bridge-maxage': Link
.IFLA_BR_MAX_AGE
,
470 'bridge-ageing': Link
.IFLA_BR_AGEING_TIME
,
471 'bridge-stp': Link
.IFLA_BR_STP_STATE
,
472 # 'bridge-bridgeprio': Link.IFLA_BR_PRIORITY,
473 'bridge-vlan-aware': Link
.IFLA_BR_VLAN_FILTERING
,
474 'bridge-vlan-protocol': Link
.IFLA_BR_VLAN_PROTOCOL
,
475 # Link.IFLA_BR_GROUP_FWD_MASK,
476 # Link.IFLA_BR_ROOT_ID,
477 # Link.IFLA_BR_BRIDGE_ID,
478 # Link.IFLA_BR_ROOT_PORT,
479 # (Link.IFLA_BR_ROOT_PATH_COST,,
480 # Link.IFLA_BR_TOPOLOGY_CHANGE,
481 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
482 # Link.IFLA_BR_HELLO_TIMER,
483 # Link.IFLA_BR_TCN_TIMER,
484 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
485 # Link.IFLA_BR_GC_TIMER,
486 # Link.IFLA_BR_GROUP_ADDR,
487 # Link.IFLA_BR_FDB_FLUSH,
488 'bridge-mcrouter': Link
.IFLA_BR_MCAST_ROUTER
,
489 #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
490 'bridge-mcqifaddr': Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
,
491 'bridge-mcquerier': Link
.IFLA_BR_MCAST_QUERIER
,
492 'bridge-hashel': Link
.IFLA_BR_MCAST_HASH_ELASTICITY
,
493 'bridge-hashmax': Link
.IFLA_BR_MCAST_HASH_MAX
,
494 'bridge-mclmc': Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
,
495 'bridge-mcsqc': Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
,
496 'bridge-mclmi': Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
,
497 'bridge-mcmi': Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
,
498 'bridge-mcqpi': Link
.IFLA_BR_MCAST_QUERIER_INTVL
,
499 'bridge-mcqi': Link
.IFLA_BR_MCAST_QUERY_INTVL
,
500 'bridge-mcqri': Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
,
501 'bridge-mcsqi': Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
,
502 # Link.IFLA_BR_NF_CALL_IPTABLES,
503 # Link.IFLA_BR_NF_CALL_IP6TABLES,
504 # Link.IFLA_BR_NF_CALL_ARPTABLES,
505 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
507 # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), # already dealt with, in a separate loop
508 'bridge-igmp-version': Link
.IFLA_BR_MCAST_IGMP_VERSION
,
509 'bridge-mcstats': Link
.IFLA_BR_MCAST_STATS_ENABLED
,
510 'bridge-mld-version': Link
.IFLA_BR_MCAST_MLD_VERSION
512 # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
513 # they are supported. It is done this way because this dictionary is used
514 # in a loop, but these attributes require additional work. Thus they are
515 # excluded from this loop without overhead.
517 _ifla_br_attributes_translate_user_config_to_netlink_map
= dict(
519 # Link.IFLA_BR_UNSPEC,
520 (Link
.IFLA_BR_FORWARD_DELAY
, lambda x
: int(x
) * 100),
521 (Link
.IFLA_BR_HELLO_TIME
, lambda x
: int(x
) * 100),
522 (Link
.IFLA_BR_MAX_AGE
, lambda x
: int(x
) * 100),
523 (Link
.IFLA_BR_AGEING_TIME
, lambda x
: int(x
) * 100),
524 # Link.IFLA_BR_STP_STATE, # STP is treated outside the loop
525 (Link
.IFLA_BR_PRIORITY
, int),
526 (Link
.IFLA_BR_VLAN_FILTERING
, utils
.get_boolean_from_string
),
527 (Link
.IFLA_BR_VLAN_PROTOCOL
, str.upper
),
528 # Link.IFLA_BR_GROUP_FWD_MASK,
529 # Link.IFLA_BR_ROOT_ID,
530 # Link.IFLA_BR_BRIDGE_ID,
531 # Link.IFLA_BR_ROOT_PORT,
532 # Link.IFLA_BR_ROOT_PATH_COST,
533 # Link.IFLA_BR_TOPOLOGY_CHANGE,
534 # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
535 # Link.IFLA_BR_HELLO_TIMER,
536 # Link.IFLA_BR_TCN_TIMER,
537 # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
538 # Link.IFLA_BR_GC_TIMER,
539 # Link.IFLA_BR_GROUP_ADDR,
540 # Link.IFLA_BR_FDB_FLUSH,
541 (Link
.IFLA_BR_MCAST_ROUTER
, utils
.get_int_from_boolean_and_string
),
542 (Link
.IFLA_BR_MCAST_SNOOPING
, utils
.get_boolean_from_string
),
543 (Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
, utils
.get_boolean_from_string
),
544 (Link
.IFLA_BR_MCAST_QUERIER
, utils
.get_boolean_from_string
),
545 (Link
.IFLA_BR_MCAST_HASH_ELASTICITY
, int),
546 (Link
.IFLA_BR_MCAST_HASH_MAX
, int),
547 (Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
, int),
548 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
, int),
549 (Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
, lambda x
: int(x
) * 100),
550 (Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
, lambda x
: int(x
) * 100),
551 (Link
.IFLA_BR_MCAST_QUERIER_INTVL
, lambda x
: int(x
) * 100),
552 (Link
.IFLA_BR_MCAST_QUERY_INTVL
, lambda x
: int(x
) * 100),
553 (Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
, lambda x
: int(x
) * 100),
554 (Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
, lambda x
: int(x
) * 100),
555 # Link.IFLA_BR_NF_CALL_IPTABLES,
556 # Link.IFLA_BR_NF_CALL_IP6TABLES,
557 # Link.IFLA_BR_NF_CALL_ARPTABLES,
558 # Link.IFLA_BR_VLAN_DEFAULT_PVID,
560 (Link
.IFLA_BR_VLAN_STATS_ENABLED
, utils
.get_boolean_from_string
),
561 (Link
.IFLA_BR_MCAST_IGMP_VERSION
, int),
562 (Link
.IFLA_BR_MCAST_STATS_ENABLED
, utils
.get_boolean_from_string
),
563 (Link
.IFLA_BR_MCAST_MLD_VERSION
, int)
567 _ifla_brport_attributes_map
= {
568 # Link.IFLA_BRPORT_UNSPEC,
569 # Link.IFLA_BRPORT_STATE,
570 'bridge-portprios': Link
.IFLA_BRPORT_PRIORITY
,
571 'bridge-pathcosts': Link
.IFLA_BRPORT_COST
,
572 # Link.IFLA_BRPORT_MODE,
573 # Link.IFLA_BRPORT_GUARD,
574 # Link.IFLA_BRPORT_PROTECT,
575 'bridge-portmcfl': Link
.IFLA_BRPORT_FAST_LEAVE
,
576 'bridge-learning': Link
.IFLA_BRPORT_LEARNING
,
577 'bridge-unicast-flood': Link
.IFLA_BRPORT_UNICAST_FLOOD
,
578 # Link.IFLA_BRPORT_PROXYARP,
579 # Link.IFLA_BRPORT_LEARNING_SYNC,
580 # Link.IFLA_BRPORT_PROXYARP_WIFI,
581 # Link.IFLA_BRPORT_ROOT_ID,
582 # Link.IFLA_BRPORT_BRIDGE_ID,
583 # Link.IFLA_BRPORT_DESIGNATED_PORT,
584 # Link.IFLA_BRPORT_DESIGNATED_COST,
585 # Link.IFLA_BRPORT_ID,
586 # Link.IFLA_BRPORT_NO,
587 # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
588 # Link.IFLA_BRPORT_CONFIG_PENDING,
589 # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
590 # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
591 # Link.IFLA_BRPORT_HOLD_TIMER,
592 # Link.IFLA_BRPORT_FLUSH,
593 'bridge-portmcrouter': Link
.IFLA_BRPORT_MULTICAST_ROUTER
,
594 # Link.IFLA_BRPORT_PAD,
595 'bridge-multicast-flood': Link
.IFLA_BRPORT_MCAST_FLOOD
,
596 # Link.IFLA_BRPORT_MCAST_TO_UCAST,
597 # Link.IFLA_BRPORT_VLAN_TUNNEL,
598 'bridge-broadcast-flood': Link
.IFLA_BRPORT_BCAST_FLOOD
,
599 'bridge-l2protocol-tunnel': Link
.IFLA_BRPORT_GROUP_FWD_MASK
,
600 # Link.IFLA_BRPORT_PEER_LINK,
601 # Link.IFLA_BRPORT_DUAL_LINK,
602 'bridge-arp-nd-suppress': Link
.IFLA_BRPORT_NEIGH_SUPPRESS
,
605 _ifla_brport_multicast_router_dict_to_int
= {
616 _ifla_brport_multicast_router_dict_int_to_str
= {
622 # callable to translate <interface-yes-no-0-1-list> to netlink value
623 _ifla_brport_attributes_translate_user_config_to_netlink_map
= dict(
625 (Link
.IFLA_BRPORT_PRIORITY
, int),
626 (Link
.IFLA_BRPORT_COST
, int),
627 (Link
.IFLA_BRPORT_MULTICAST_ROUTER
, lambda x
: bridge
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(x
, 0)),
628 (Link
.IFLA_BRPORT_FAST_LEAVE
, utils
.get_boolean_from_string
),
629 (Link
.IFLA_BRPORT_LEARNING
, utils
.get_boolean_from_string
),
630 (Link
.IFLA_BRPORT_UNICAST_FLOOD
, utils
.get_boolean_from_string
),
631 (Link
.IFLA_BRPORT_MCAST_FLOOD
, utils
.get_boolean_from_string
),
632 (Link
.IFLA_BRPORT_BCAST_FLOOD
, utils
.get_boolean_from_string
),
633 (Link
.IFLA_BRPORT_GROUP_FWD_MASK
, lambda x
: x
),
634 (Link
.IFLA_BRPORT_NEIGH_SUPPRESS
, utils
.get_boolean_from_string
)
638 def __init__(self
, *args
, **kargs
):
639 Bridge
.__init
__(self
)
640 moduleBase
.__init
__(self
, *args
, **kargs
)
641 self
.name
= self
.__class
__.__name
__
642 self
._resv
_vlan
_range
= self
._get
_reserved
_vlan
_range
()
643 self
.logger
.debug('%s: using reserved vlan range %s' % (self
.__class
__.__name
__, str(self
._resv
_vlan
_range
)))
645 self
.default_stp_on
= utils
.get_boolean_from_string(
646 policymanager
.policymanager_api
.get_attr_default(
647 module_name
=self
.__class
__.__name
__,
652 self
.default_vlan_stats
= policymanager
.policymanager_api
.get_attr_default(
653 module_name
=self
.__class
__.__name
__,
654 attr
='bridge-vlan-stats'
657 self
.warn_on_untagged_bridge_absence
= utils
.get_boolean_from_string(
658 policymanager
.policymanager_api
.get_module_globals(
659 module_name
=self
.__class
__.__name
__,
660 attr
='warn_on_untagged_bridge_absence'
663 self
.logger
.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
664 % self
.warn_on_untagged_bridge_absence
)
666 self
._vxlan
_bridge
_default
_igmp
_snooping
= policymanager
.policymanager_api
.get_module_globals(
667 self
.__class
__.__name
__,
668 'vxlan_bridge_default_igmp_snooping'
670 self
.logger
.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
671 % self
._vxlan
_bridge
_default
_igmp
_snooping
)
673 self
.arp_nd_suppress_only_on_vxlan
= utils
.get_boolean_from_string(
674 policymanager
.policymanager_api
.get_module_globals(
675 module_name
=self
.__class
__.__name
__,
676 attr
='allow_arp_nd_suppress_only_on_vxlan'
679 self
.logger
.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self
.arp_nd_suppress_only_on_vxlan
)
681 self
.bridge_always_up_dummy_brport
= policymanager
.policymanager_api
.get_module_globals(
682 module_name
=self
.__class
__.__name
__,
683 attr
='bridge_always_up_dummy_brport'
685 self
.logger
.debug('bridge: init: bridge_always_up_dummy_brport=%s' % self
.bridge_always_up_dummy_brport
)
688 self
.bridge_allow_multiple_vlans
= utils
.get_boolean_from_string(
689 self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
692 # Cumulus Linux specific variable. Failure probably means that
693 # ifupdown2 is running a a different system.
694 self
.bridge_allow_multiple_vlans
= True
695 self
.logger
.debug('bridge: init: multiple vlans allowed %s' % self
.bridge_allow_multiple_vlans
)
697 self
.bridge_mac_iface_list
= policymanager
.policymanager_api
.get_module_globals(self
.__class
__.__name
__, 'bridge_mac_iface') or []
698 # each bridge should have it's own tuple (ifname, mac)
699 self
.bridge_mac_iface
= {}
701 self
.bridge_set_static_mac_from_port
= utils
.get_boolean_from_string(
702 policymanager
.policymanager_api
.get_module_globals(
703 self
.__class
__.__name
__, 'bridge_set_static_mac_from_port'
707 self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
= utils
.get_boolean_from_string(
708 policymanager
.policymanager_api
.get_module_globals(
709 module_name
=self
.__class
__.__name
__,
710 attr
="vxlan_bridge_igmp_snooping_enable_port_mcrouter"
715 self
.allow_vlan_sub_interface_in_vlan_aware_bridge
= utils
.get_boolean_from_string(
716 policymanager
.policymanager_api
.get_module_globals(
717 module_name
=self
.__class
__.__name
__,
718 attr
="allow-vlan-sub-interface-in-vlan-aware-bridge"
723 self
.bridge_vxlan_arp_nd_suppress
= utils
.get_boolean_from_string(
724 policymanager
.policymanager_api
.get_module_globals(
725 module_name
=self
.__class
__.__name
__,
726 attr
="bridge-vxlan-arp-nd-suppress"
730 self
.bridge_vxlan_arp_nd_suppress_int
= int(self
.bridge_vxlan_arp_nd_suppress
)
732 self
.l2protocol_tunnel_callback
= {
733 'all': self
._l2protocol
_tunnel
_set
_all
,
734 'stp': self
._l2protocol
_tunnel
_set
_stp
,
735 'cdp': self
._l2protocol
_tunnel
_set
_cdp
,
736 'pvst': self
._l2protocol
_tunnel
_set
_pvst
,
737 'lldp': self
._l2protocol
_tunnel
_set
_lldp
,
738 'lacp': self
._l2protocol
_tunnel
_set
_lacp
741 self
.query_check_l2protocol_tunnel_callback
= {
742 'all': self
._query
_check
_l2protocol
_tunnel
_all
,
743 'stp': self
._query
_check
_l2protocol
_tunnel
_stp
,
744 'cdp': self
._query
_check
_l2protocol
_tunnel
_cdp
,
745 'pvst': self
._query
_check
_l2protocol
_tunnel
_pvst
,
746 'lldp': self
._query
_check
_l2protocol
_tunnel
_lldp
,
747 'lacp': self
._query
_check
_l2protocol
_tunnel
_lacp
750 self
._bridge
_attribute
_query
_check
_handler
= {
751 "bridge-maxwait": (self
._query
_check
_br
_attr
_wait
, None),
752 "bridge-waitport": (self
._query
_check
_br
_attr
_wait
, None),
754 "bridge-stp": (self
._query
_check
_br
_attr
_stp
, Link
.IFLA_BR_STP_STATE
),
756 "bridge-mcstats": (self
._query
_check
_br
_attr
_boolean
_on
_off
, Link
.IFLA_BR_MCAST_STATS_ENABLED
),
757 "bridge-vlan-stats": (self
._query
_check
_br
_attr
_boolean
_on
_off
, Link
.IFLA_BR_VLAN_STATS_ENABLED
),
759 "bridge-vlan-aware": (self
._query
_check
_br
_attr
_boolean
, Link
.IFLA_BR_VLAN_FILTERING
),
760 "bridge-mcqifaddr": (self
._query
_check
_br
_attr
_boolean
, Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
),
761 "bridge-mcsnoop": (self
._query
_check
_br
_attr
_boolean
, Link
.IFLA_BR_MCAST_SNOOPING
),
762 "bridge-mcquerier": (self
._query
_check
_br
_attr
_boolean
, Link
.IFLA_BR_MCAST_QUERIER
),
763 "bridge-mcrouter": (self
._query
_check
_br
_attr
_boolean
, Link
.IFLA_BR_MCAST_ROUTER
),
765 "bridge-vlan-protocol": (self
._query
_check
_br
_attr
_string
, Link
.IFLA_BR_VLAN_PROTOCOL
),
767 "bridge-mcsqc": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
),
768 "bridge-mclmc": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
),
769 "bridge-hashmax": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_HASH_MAX
),
770 "bridge-hashel": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_HASH_ELASTICITY
),
771 "bridge-bridgeprio": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_PRIORITY
),
772 "bridge-igmp-version": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_IGMP_VERSION
),
773 "bridge-mld-version": (self
._query
_check
_br
_attr
_int
, Link
.IFLA_BR_MCAST_MLD_VERSION
),
775 "bridge-maxage": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MAX_AGE
),
776 "bridge-fd": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_FORWARD_DELAY
),
777 "bridge-hello": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_HELLO_TIME
),
778 "bridge-ageing": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_AGEING_TIME
),
779 "bridge-mcmi": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
),
780 "bridge-mcsqi": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
),
781 "bridge-mclmi": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
),
782 "bridge-mcqri": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
),
783 "bridge-mcqpi": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_QUERIER_INTVL
),
784 "bridge-mcqi": (self
._query
_check
_br
_attr
_int
_divided
100, Link
.IFLA_BR_MCAST_QUERY_INTVL
),
787 self
._brport
_attribute
_query
_check
_handler
= {
788 "bridge-pathcosts": self
._query
_check
_brport
_attr
_int
,
789 "bridge-portprios": self
._query
_check
_brport
_attr
_int
,
790 "bridge-portmcfl": self
._query
_check
_brport
_attr
_boolean
_yes
_no
,
791 "bridge-learning": self
._query
_check
_brport
_attr
_boolean
_on
_off
,
792 "bridge-arp-nd-suppress": self
._query
_check
_brport
_attr
_boolean
_on
_off
,
793 "bridge-unicast-flood": self
._query
_check
_brport
_attr
_boolean
_on
_off
,
794 "bridge-multicast-flood": self
._query
_check
_brport
_attr
_boolean
_on
_off
,
795 "bridge-broadcast-flood": self
._query
_check
_brport
_attr
_boolean
_on
_off
,
796 "bridge-portmcrouter": self
._query
_check
_brport
_attr
_portmcrouter
,
799 self
.bridge_vxlan_port_learning
= utils
.get_boolean_from_string(
800 policymanager
.policymanager_api
.get_module_globals(
801 self
.__class
__.__name
__,
802 "bridge_vxlan_port_learning"
807 # To avoid disabling ipv6 on SVD we need to keep track of them
808 self
.svd_list
= set()
810 # user defined limit of VNI per vlan on the same bridge
812 self
.bridge_vni_per_svi
= {}
814 self
.bridge_vni_per_svi_limit
= int(policymanager
.policymanager_api
.get_module_globals(
815 module_name
=self
.__class
__.__name
__,
816 attr
="bridge_vni_per_svi_limit"
819 self
.bridge_vni_per_svi_limit
= -1
822 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
823 if not ifla_brport_group_maskhi
:
824 ifla_brport_group_maskhi
= 0x1
826 ifla_brport_group_maskhi |
= 0x1
827 return ifla_brport_group_mask
, ifla_brport_group_maskhi
830 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
831 if not ifla_brport_group_maskhi
:
832 ifla_brport_group_maskhi
= 0x2
834 ifla_brport_group_maskhi |
= 0x2
835 return ifla_brport_group_mask
, ifla_brport_group_maskhi
838 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
839 if not ifla_brport_group_mask
:
840 ifla_brport_group_mask
= 0x1
842 ifla_brport_group_mask |
= 0x1
843 return ifla_brport_group_mask
, ifla_brport_group_maskhi
846 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
847 if not ifla_brport_group_mask
:
848 ifla_brport_group_mask
= 0x4
850 ifla_brport_group_mask |
= 0x4
851 return ifla_brport_group_mask
, ifla_brport_group_maskhi
854 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
855 if not ifla_brport_group_mask
:
856 ifla_brport_group_mask
= 0x4000
858 ifla_brport_group_mask |
= 0x4000
859 return ifla_brport_group_mask
, ifla_brport_group_maskhi
862 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
863 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
864 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
867 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
868 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x1
871 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
872 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x2
875 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
876 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x1
879 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
880 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4000
883 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
884 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4
887 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
888 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
890 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
891 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
892 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
893 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
895 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
896 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
897 c3
= self
.syntax_check_learning_l2_vni_evpn(ifaceobj
)
898 c4
= self
.syntax_check_bridge_arp_vni_vlan(ifaceobj
, ifaceobj_getfunc
)
899 c5
= self
.syntax_check_bridge_vni_svi_limit(ifaceobj
, ifaceobj_getfunc
)
900 return retval
and c1
and c3
and c4
and c5
#and c2
902 def syntax_check_bridge_vni_svi_limit(self
, ifaceobj
, ifaceobj_getfunc
):
903 if self
.bridge_vni_per_svi_limit
> 0 and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
904 vni_name
= ifaceobj
.name
905 bridge_name
= self
.__get
_vxlan
_bridge
_name
(ifaceobj
, ifaceobj_getfunc
)
910 svi
= ifaceobj
.get_attr_value_first("bridge-access")
915 vni_per_svi
= self
.bridge_vni_per_svi
.get(bridge_name
, {}).get(svi
)
919 "%s: misconfiguration detected: maximum vni allowed per bridge (%s) svi (%s) is limited to %s (policy: 'bridge_vni_per_svi_limit')" %
923 self
.bridge_vni_per_svi_limit
)
930 if not bridge_name
in self
.bridge_vni_per_svi
:
931 self
.bridge_vni_per_svi
[bridge_name
] = {
935 elif not svi
in self
.bridge_vni_per_svi
[bridge_name
]:
936 self
.bridge_vni_per_svi
[bridge_name
][svi
] = vni_name
944 def __get_vxlan_bridge_name(self
, ifaceobj
, ifaceobj_getfunc
):
946 for intf
in ifaceobj
.upperifaces
:
947 for obj
in ifaceobj_getfunc(intf
):
948 if obj
.link_kind
& ifaceLinkKind
.BRIDGE
:
954 def syntax_check_bridge_arp_vni_vlan(self
, ifaceobj
, ifaceobj_getfunc
):
956 Detect and warn when arp suppression is enabled and there is no vlan configured
959 :param ifaceobj_getfunc:
962 if ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN \
963 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT \
964 and utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-arp-nd-suppress")) \
965 and not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
967 bridge_access
= ifaceobj
.get_attr_value_first("bridge-access")
969 if not bridge_access
:
972 for obj
in ifaceobj_getfunc(ifaceobj
.upperifaces
[0]) or []:
973 for upper_ifname
in obj
.upperifaces
or []:
974 for upper_obj
in ifaceobj_getfunc(upper_ifname
) or []:
975 if upper_obj
.link_kind
& ifaceLinkKind
.VLAN
:
976 if str(self
._get
_vlan
_id
(upper_obj
)) == bridge_access
:
980 "%s: ARP suppression configured on %s and associated vlan %s not configured. "
981 "This may result in unexpected behavior"
982 % (ifaceobj
.name
, ifaceobj
.name
, bridge_access
)
988 def syntax_check_learning_l2_vni_evpn(self
, ifaceobj
):
990 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
991 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-learning")) and \
992 (not ifaceobj
.get_attr_value_first("vxlan-remoteip") and not ifaceobj
.get_attr_value_first("vxlan-remoteip-map")):
994 "%s: possible mis-configuration detected: l2-vni configured with bridge-learning ON "
995 "while EVPN is also configured - these two parameters conflict with each other."
1001 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
1003 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
1005 for brport_name
in ifaceobj
.lowerifaces
:
1006 for obj
in ifaceobj_getfunc(brport_name
) or []:
1007 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
1008 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
1009 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
1010 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
1011 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
1012 % (ifaceobj
.name
, brport_name
))
1015 vlan_id
= sub_intf_vlan_id
1018 def check_bridge_port_vid_attrs(self
, ifaceobj
):
1019 if (ifaceobj
.get_attr_value('bridge-access') and
1020 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
1021 ifaceobj
.get_attr_value('bridge-pvid'))):
1022 self
.logger
.warning('%s: bridge-access given, bridge-vids and bridge-pvid '
1023 'will be ignored' % ifaceobj
.name
)
1027 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
1028 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1029 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1033 for port_name
in ports
:
1034 port_obj_l
= ifaceobj_getfunc(port_name
)
1035 if not self
.allow_vlan_sub_interface_in_vlan_aware_bridge
:
1036 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
1037 self
.logger
.error('%s: %s: vlan sub-interface is not '
1038 'supported in a vlan-aware bridge'
1039 % (ifaceobj
.name
, port_name
))
1042 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
1043 self
.arp_nd_suppress_only_on_vxlan
and
1044 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
1045 self
.log_error('\'bridge-arp-nd-suppress\' is not '
1046 'supported on a non-vxlan port %s'
1047 %port_obj_l
[0].name
)
1052 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
1053 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
1054 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
1055 'device (%s) is part of vlan aware bridge (%s)'
1056 % (ifaceobj
.name
, bridgename
), ifaceobj
)
1060 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
1061 if not ifaceobj_getfunc
:
1063 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
1064 if ifaceobj
.get_attr_value('bridge-access'):
1066 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
1067 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
1068 if not ifaceobj_upper_list
:
1070 ifaceobj_upper
= ifaceobj_upper_list
[0]
1071 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
1072 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1073 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1074 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1077 or not utils
.compare_ids(bridge_vids
,
1080 if not self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
, ifaceobj_upper
.name
):
1085 def _is_bridge(ifaceobj
):
1086 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
1087 ifaceobj
.get_attr_value_first('bridge-ports') or
1088 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
1090 def check_valid_bridge(self
, ifaceobj
, ifname
):
1091 if self
.cache
.link_exists(ifname
) and not self
.cache
.link_is_bridge(ifname
):
1092 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
1096 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None, old_ifaceobjs
=False):
1098 if not old_ifaceobjs
and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
or ifaceobj
.get_attr_value_first("bridge-vlan-vni-map")):
1099 self
.svd_list
.add(ifaceobj
.name
)
1101 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
1103 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
1104 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
1105 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
1106 # for special vlan aware bridges, we need to add another bit
1107 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
1108 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
1109 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
1111 if not old_ifaceobjs
:
1112 # store the name of all bridge vlan aware in a global list
1113 self
.bridge_vlan_aware_list
.add(ifaceobj
.name
)
1115 ifaceobj
.role |
= ifaceRole
.MASTER
1116 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
1118 return self
.parse_port_list(ifaceobj
.name
,
1119 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
1122 def get_dependent_ifacenames_running(self
, ifaceobj
):
1123 if not self
.cache
.bridge_exists(ifaceobj
.name
):
1125 return self
.cache
.get_slaves(ifaceobj
.name
)
1127 def _get_bridge_port_list(self
, ifaceobj
):
1129 # port list is also available in the previously
1130 # parsed dependent list. Use that if available, instead
1131 # of parsing port expr again
1132 port_list
= ifaceobj
.lowerifaces
1135 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
1137 return self
.parse_port_list(ifaceobj
.name
, ports
)
1141 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
1142 # When enslaving bridge-ports we need to return the exact user
1143 # configured bridge ports list (bridge will inherit the mac of the
1145 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
1146 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
1148 def _get_bridge_port_condone_regex(self
, ifaceobj
, get_string
= False):
1149 bridge_port_condone_regex
= ifaceobj
.get_attr_value_first('bridge-ports-condone-regex')
1150 # If bridge-ports-ignore-regex is configured, do NOT use the parse_port_list()
1151 # function to gather a list of ports matching the regex here and now but set
1152 # up a compiled regex to be used in a match later. This way we try to avoid
1153 # a race condition where an (possibly VM) interface is created after this
1154 # function has been called but before the bridgeports are validated.
1155 if bridge_port_condone_regex
:
1157 return bridge_port_condone_regex
1158 return re
.compile (r
"%s" % bridge_port_condone_regex
)
1161 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
1162 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
1163 if not waitport_value
: return
1165 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
1166 if not waitportvals
: return
1168 waitporttime
= int(waitportvals
[0])
1170 self
.log_warn('%s: invalid waitport value \'%s\''
1171 %(ifaceobj
.name
, waitportvals
[0]))
1173 if waitporttime
<= 0: return
1175 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
1177 except IndexError as e
:
1178 # ignore error and use all bridge ports
1179 waitportlist
= portlist
1181 if not waitportlist
: return
1182 self
.logger
.info('%s: waiting for ports %s to exist ...'
1183 %(ifaceobj
.name
, str(waitportlist
)))
1184 starttime
= time
.time()
1185 while ((time
.time() - starttime
) < waitporttime
):
1186 if all([False for p
in waitportlist
1187 if not self
.cache
.link_exists(p
)]):
1190 except Exception as e
:
1191 self
.log_warn('%s: unable to process waitport: %s'
1192 %(ifaceobj
.name
, str(e
)))
1194 def _enable_disable_ipv6(self
, port
, enable
='1'):
1196 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
1197 except Exception as e
:
1198 self
.logger
.info(str(e
))
1200 def handle_ipv6(self
, ports
, state
):
1202 self
._enable
_disable
_ipv
6(p
, state
)
1204 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
1205 """ pretty print bridge port add errors.
1206 since the commands are batched and the kernel only returns error
1207 codes, this function tries to interpret some error codes
1208 and prints clearer errors """
1210 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
1211 # Cumulus Linux specific error checks
1213 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
1215 for bport
in bridgeports
:
1216 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
1218 if currvlanid
!= vlanid
:
1219 self
.log_error('%s: ' %bridgeifaceobj
.name
+
1220 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
1224 except Exception as e
:
1225 errstr
+= '\n%s' % str(e
)
1226 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
1228 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
1229 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1230 bridgeportscondoneregex
= self
._get
_bridge
_port
_condone
_regex
(ifaceobj
)
1231 runningbridgeports
= []
1233 # bridge-always-up #####################################################
1234 bridge_always_up
= ifaceobj
.get_attr_value_first("bridge-always-up")
1237 if utils
.get_boolean_from_string(bridge_always_up
):
1238 # the dummy port will be added to the bridgeports list so the
1239 # following code don't de-enslave the dummy device.
1240 dummy_brport
= self
.bridge_always_up(ifaceobj
.name
, bridgeports
)
1242 ########################################################################
1244 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
1245 # Delete active ports not in the new port list
1246 if not ifupdownflags
.flags
.PERFMODE
:
1247 runningbridgeports
= self
.cache
.get_slaves(ifaceobj
.name
)
1248 if runningbridgeports
:
1249 for bport
in runningbridgeports
:
1250 if not bridgeports
or bport
not in bridgeports
:
1251 if bridgeportscondoneregex
and bridgeportscondoneregex
.match(bport
):
1252 self
.logger
.info("%s: port %s will stay enslaved as it matches with bridge-ports-condone-regex" % (ifaceobj
.name
, bport
))
1254 self
.netlink
.link_set_nomaster(bport
)
1255 # set admin DOWN on all removed ports
1256 # that don't have config outside bridge
1257 if not ifaceobj_getfunc(bport
):
1258 self
.netlink
.link_down(bport
)
1259 # enable ipv6 for ports that were removed
1260 self
.handle_ipv6([bport
], '0')
1262 runningbridgeports
= []
1266 newbridgeports
= set(bridgeports
).difference(set(runningbridgeports
))
1267 newly_enslaved_ports
= []
1269 newbridgeports_ordered
= []
1270 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
1271 if br_port
in newbridgeports
:
1272 newbridgeports_ordered
.append(br_port
)
1275 # add the dummy port to the list of interface to enslave
1276 # link_set_master should make sure that the device is not
1278 newbridgeports_ordered
.append(dummy_brport
)
1280 self
.iproute2
.batch_start()
1282 for bridgeport
in newbridgeports_ordered
:
1284 if (not ifupdownflags
.flags
.DRYRUN
and
1285 not self
.cache
.link_exists(bridgeport
)):
1286 self
.log_error('%s: bridge port %s does not exist'
1287 %(ifaceobj
.name
, bridgeport
), ifaceobj
, raise_error
=False)
1290 hwaddress
= self
.cache
.get_link_address(bridgeport
)
1291 if not ifupdownflags
.flags
.DRYRUN
and not self
._valid
_ethaddr
(hwaddress
):
1292 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
1293 bridgeport
) + 'invalid ether addr %s'
1296 self
.iproute2
.link_set_master(bridgeport
, ifaceobj
.name
)
1297 newly_enslaved_ports
.append(bridgeport
)
1299 # dont disable ipv6 for SVD
1300 if bridgeport
not in self
.svd_list
:
1301 self
.handle_ipv6([bridgeport
], '1')
1303 self
.iproute2
.addr_flush(bridgeport
)
1304 except Exception as e
:
1305 self
.logger
.error(str(e
))
1308 self
.iproute2
.batch_commit()
1309 self
.cache
.force_add_slave_list(ifaceobj
.name
, newly_enslaved_ports
)
1312 self
.log_error('bridge configuration failed (missing ports)')
1315 # to avoid any side effect we remove the dummy brport from the
1316 # list of supposedly newly configured ports.
1317 newly_enslaved_ports
.remove(dummy_brport
)
1321 return newly_enslaved_ports
1323 def get_dummy_brport_name_for_bridge(self
, bridge_name
):
1325 dummy brport will have user provided name if it's defined in 'bridge_always_up_dummy_brport' policy
1326 Otherwise dummy brport will have pre-formated name: brport-if$BRIDGE_IFINDEX
1327 That way we can avoid collision with existing interfaces
1329 if self
.bridge_always_up_dummy_brport
:
1330 return self
.bridge_always_up_dummy_brport
1331 # this can raise: NetlinkCacheIfnameNotFoundError
1332 return "brport-if%d" % self
.cache
.get_ifindex(bridge_name
)
1334 def bridge_always_up(self
, bridge_name
, newbridgeports_ordered
):
1335 dummy_brport
= self
.get_dummy_brport_name_for_bridge(bridge_name
)
1337 if not self
.cache
.link_exists(dummy_brport
):
1338 self
.logger
.info("%s: bridge-always-up yes: enslaving dummy port: %s" % (bridge_name
, dummy_brport
))
1339 self
.netlink
.link_add(ifname
=dummy_brport
, kind
="dummy")
1340 self
.netlink
.link_up_force(dummy_brport
)
1342 newbridgeports_ordered
.append(dummy_brport
)
1345 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1346 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1347 if not maxwait
: return
1349 maxwait
= int(maxwait
)
1351 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1354 if not maxwait
: return
1355 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1358 starttime
= time
.time()
1359 while ((time
.time() - starttime
) < maxwait
):
1360 if all([False for p
in portlist
1361 if self
.read_file_oneline(
1362 '/sys/class/net/%s/brif/%s/state'
1363 %(ifaceobj
.name
, p
)) != '3']):
1366 except Exception as e
:
1367 self
.log_warn('%s: unable to process maxwait: %s'
1368 %(ifaceobj
.name
, str(e
)))
1370 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1372 # Sets old style igmp querier
1374 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1376 running_mcqv4src
= {}
1377 if not ifupdownflags
.flags
.PERFMODE
:
1378 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobj
.name
)
1380 srclist
= attrval
.split()
1385 k_to_del
= set(list(running_mcqv4src
.keys())).difference(list(mcqs
.keys()))
1387 self
.iproute2
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1388 for v
in list(mcqs
.keys()):
1389 self
.iproute2
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1390 elif not ifupdownflags
.flags
.PERFMODE
:
1391 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobj
.name
)
1392 if running_mcqv4src
:
1393 for v
in list(running_mcqv4src
.keys()):
1394 self
.iproute2
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1396 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1398 # Supports old style vlan vid info format
1401 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1402 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1403 if not bridge_port_pvids
and not bridge_port_vids
:
1406 # Handle bridge vlan attrs
1408 if bridge_port_pvids
:
1409 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1411 self
.log_warn('%s: could not parse \'%s %s\''
1412 %(ifaceobj
.name
, 'bridge-port-pvids',
1417 (port
, pvid
) = p
.split('=')
1419 running_pvid
= self
.cache
.get_pvid(port
)
1421 if running_pvid
== pvid
:
1424 self
.iproute2
.bridge_vlan_del_pvid(port
, running_pvid
)
1425 self
.iproute2
.bridge_vlan_add_pvid(port
, pvid
)
1426 except Exception as e
:
1427 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1428 %(ifaceobj
.name
, p
, str(e
)))
1431 if bridge_port_vids
:
1432 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1434 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1435 'bridge-port-vids', bridge_port_vids
))
1439 (port
, val
) = p
.split('=')
1440 vids
= val
.split(',')
1441 vids_int
= utils
.ranges_to_ints(vids
)
1442 _
, running_vids
= self
.cache
.get_pvid_and_vids(port
)
1444 (vids_to_del
, vids_to_add
) = \
1445 utils
.diff_ids(vids_int
, running_vids
)
1447 self
.iproute2
.bridge_vlan_del_vid_list(port
,
1448 utils
.compress_into_ranges(vids_to_del
))
1450 self
.iproute2
.bridge_vlan_add_vid_list(port
,
1451 utils
.compress_into_ranges(vids_to_add
))
1453 self
.iproute2
.bridge_vlan_add_vid_list(port
, vids_int
)
1454 except Exception as e
:
1455 self
.log_warn('%s: failed to set vid `%s` (%s)'
1456 %(ifaceobj
.name
, p
, str(e
)))
1458 def _is_running_stp_state_on(self
, bridgename
):
1459 """ Returns True if running stp state is on, else False """
1461 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1463 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1464 return running_stp_state
and running_stp_state
!= '0'
1468 def _is_config_stp_state_on(self
, ifaceobj
):
1469 """ Returns true if user specified stp state is on, else False """
1471 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1473 return self
.default_stp_on
1474 return utils
.get_boolean_from_string(stp_attr
)
1476 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1477 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1482 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1483 if self
._vxlan
_bridge
_default
_igmp
_snooping
is not None:
1484 return self
._vxlan
_bridge
_default
_igmp
_snooping
1486 return self
.get_attr_default_value("bridge-mcsnoop")
1488 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1497 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1499 if not callable(translate_func
):
1503 user_config
= policymanager
.policymanager_api
.get_iface_default(
1504 module_name
=self
.__class
__.__name
__,
1509 if not link_just_created
and cached_value
is None:
1510 # the link already exists but we don't have any value
1511 # cached for this attr, it probably means that the
1512 # capability is not available on this system (i.e old kernel)
1513 self
.logger
.debug("%s: ignoring %s %s: capability probably not supported on this system"
1514 % (ifname
, attr_name
, user_config
))
1517 if not user_config
and not link_just_created
and cached_value
is not None:
1518 # there is no user configuration for this attribute
1519 # if the bridge existed before we need to check if
1520 # this attribute needs to be reset to default value
1521 default_value
= self
.get_attr_default_value(attr_name
)
1524 # the attribute has a default value, we need to convert it to
1525 # netlink format to compare it with the cache value
1526 default_value_nl
= translate_func(default_value
) # default_value.lower()
1528 if default_value_nl
!= cached_value
:
1529 # the running value difers from the default value
1530 # but the user didn't specify any config
1531 # resetting attribute to default
1532 ifla_info_data
[nl_attr
] = default_value_nl
1533 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1535 user_config_nl
= translate_func(user_config
) # user_config.lower()
1537 if user_config_nl
!= cached_value
:
1538 ifla_info_data
[nl_attr
] = user_config_nl
1540 if cached_value
is not None:
1541 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1543 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1544 except Exception as e
:
1545 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1547 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1548 ifla_info_data
= dict()
1549 ifname
= ifaceobj
.name
1551 self
.logger
.info('%s: applying bridge settings' % ifname
)
1553 cached_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
1556 # we compare the user value (or policy value) with the current running state
1557 # we need to divide the cached value by 100 to ignore small difference.
1558 # i.e. our default value is 31 but the kernel default seems to be 3125
1559 cached_ifla_info_data
[Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
] //= 100
1560 cached_ifla_info_data
[Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
] *= 100
1564 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
.items():
1565 self
.fill_ifla_info_data_with_ifla_br_attribute(
1566 ifla_info_data
=ifla_info_data
,
1567 link_just_created
=link_just_created
,
1570 attr_name
=attr_name
,
1571 user_config
=ifaceobj
.get_attr_value_first(attr_name
),
1572 cached_value
=cached_ifla_info_data
.get(nl_attr
)
1575 # special cases ########################################################
1578 # if mstpctl-treeprio is configured on the bridge
1579 # do not reset the bridge-bridgeprio to the default value
1580 # NOTE: this is the case for every bridge/mstpctl attribute pairs.
1581 # TODO: more code should be added to handle this in the future.
1582 mstpctl_treeprio
= ifaceobj
.get_attr_value_first("mstpctl-treeprio")
1583 bridge_bridgeprio
= ifaceobj
.get_attr_value_first("bridge-bridgeprio")
1585 if mstpctl_treeprio
:
1586 self
.logger
.info("%s: mstpctl-treeprio attribute is set - ignorning bridge-bridgeprio" % ifname
)
1588 self
.fill_ifla_info_data_with_ifla_br_attribute(
1589 ifla_info_data
=ifla_info_data
,
1590 link_just_created
=link_just_created
,
1592 nl_attr
=Link
.IFLA_BR_PRIORITY
,
1593 attr_name
='bridge-bridgeprio',
1594 user_config
=bridge_bridgeprio
,
1595 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_PRIORITY
)
1599 self
.fill_ifla_info_data_with_ifla_br_attribute(
1600 ifla_info_data
=ifla_info_data
,
1601 link_just_created
=link_just_created
,
1603 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1604 attr_name
='bridge-mcsnoop',
1605 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
),
1606 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_MCAST_SNOOPING
)
1611 if bridge_vlan_aware
:
1612 self
.fill_ifla_info_data_with_ifla_br_attribute(
1613 ifla_info_data
=ifla_info_data
,
1614 link_just_created
=link_just_created
,
1616 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1617 attr_name
='bridge-vlan-stats',
1618 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
,
1619 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_VLAN_STATS_ENABLED
)
1623 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1624 if not self
._is
_running
_stp
_state
_on
(ifname
):
1625 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1626 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1627 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1628 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1629 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1631 # If stp not specified and running stp state on, set it to off
1632 if self
._is
_running
_stp
_state
_on
(ifname
):
1633 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1634 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1635 except Exception as e
:
1636 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1639 self
.netlink
.link_set_bridge_info_data(ifname
, ifla_info_data
)
1641 def _check_vids(self
, ifaceobj
, vids
):
1646 va
, vb
= v
.split('-')
1647 va
, vb
= int(va
), int(vb
)
1648 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1651 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1652 except exceptions
.ReservedVlanException
as e
:
1655 self
.logger
.warning('%s: unable to parse vid \'%s\''
1656 %(ifaceobj
.name
, v
))
1659 def _get_running_vids_n_pvid_str(self
, ifacename
):
1660 pvid
, vids
= self
.cache
.get_pvid_and_vids(ifacename
)
1663 ret_vids
= utils
.compress_into_ranges(vids
)
1668 ret_pvid
= '%s' %pvid
1671 return (ret_vids
, ret_pvid
)
1673 def config_check_bridge_vni_svi_limit(self
, vxlan_brport_obj
, ifaceobj_getfunc
, pvid
):
1675 Multiple VXLANs can't be added to the same VLAN
1677 ifname
= vxlan_brport_obj
.name
1679 for intf
in vxlan_brport_obj
.upperifaces
:
1680 # find the bridge object to access the brport list
1682 for obj
in ifaceobj_getfunc(intf
):
1683 if obj
.link_kind
& ifaceLinkKind
.BRIDGE
:
1685 for brport_name
in self
._get
_bridge
_port
_list
(obj
):
1686 # loop through the brports
1688 if ifname
== brport_name
:
1689 # ignore current brport
1692 for brport_obj
in ifaceobj_getfunc(brport_name
):
1693 # loop through brport ifaceobjs and check for vxlan bridge-access value
1695 if not brport_obj
.link_kind
& ifaceLinkKind
.VXLAN
:
1698 access
= brport_obj
.get_attr_value_first("bridge-access")
1701 "%s: misconfiguration detected: vlan \"%s\" added to two or more VXLANS (%s, %s)" % (
1709 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, ifaceobj_getfunc
, vids
, pvid
,
1711 """ This method is a combination of methods _apply_bridge_vids and
1712 _apply_bridge_port_pvids above. A combined function is
1713 found necessary to do the deletes first and the adds later
1714 because kernel does honor vid info flags during deletes.
1717 if not isbridge
and (bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
and not bportifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
1718 self
.config_check_bridge_vni_svi_limit(bportifaceobj
, ifaceobj_getfunc
, pvid
)
1720 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1721 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1722 bportifaceobj
.upperifaces
[0])
1725 vids_int
= utils
.ranges_to_ints(vids
)
1727 pvid_int
= int(pvid
) if pvid
else 0
1729 self
.logger
.warning('%s: unable to parse pvid \'%s\''
1730 %(bportifaceobj
.name
, pvid
))
1735 vids_to_add
= vids_int
1737 pvid_to_add
= pvid_int
1740 if not self
._check
_vids
(bportifaceobj
, vids
):
1743 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(bportifaceobj
.name
)
1745 if not running_vids
and not running_pvid
:
1746 # There cannot be a no running pvid.
1747 # It might just not be in our cache:
1748 # this can happen if at the time we were
1749 # creating the bridge vlan cache, the port
1750 # was not part of the bridge. And we need
1751 # to make sure both vids and pvid is not in
1752 # the cache, to declare that our cache may
1758 (vids_to_del
, vids_to_add
) = \
1759 utils
.diff_ids(vids_to_add
, running_vids
)
1762 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1763 pvid_to_del
= running_pvid
1765 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1766 (pvid_to_del
not in vids_to_add
)):
1767 # kernel deletes dont take into account
1768 # bridge vid flags and its possible that
1769 # the pvid deletes we do end up deleting
1770 # the vids. Be proactive and add the pvid
1771 # to the vid add list if it is in the vids
1772 # and not already part of vids_to_add.
1773 # This helps with a small corner case:
1777 # - new change is going to move the state to
1780 vids_to_add
.add(pvid_to_del
)
1781 except exceptions
.ReservedVlanException
as e
:
1783 except Exception as e
:
1784 self
.log_error('%s: failed to process vids/pvids'
1785 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1786 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1787 bportifaceobj
, raise_error
=False)
1790 if pvid_to_add
in vids_to_del
:
1791 vids_to_del
.remove(pvid_to_add
)
1793 vids_to_del
= sorted(list(self
.remove_bridge_vlans_mapped_to_vnis_from_vids_list(None, bportifaceobj
, vids_to_del
)))
1795 self
.iproute2
.batch_start()
1796 self
.iproute2
.bridge_vlan_del_vid_list_self(bportifaceobj
.name
,
1797 utils
.compress_into_ranges(
1798 vids_to_del
), isbridge
)
1799 self
.iproute2
.batch_commit()
1800 except Exception as e
:
1801 self
.log_warn('%s: failed to del vid `%s` (%s)'
1802 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1806 self
.iproute2
.bridge_vlan_del_pvid(bportifaceobj
.name
,
1808 except Exception as e
:
1809 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1810 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1815 self
.iproute2
.batch_start()
1816 self
.iproute2
.bridge_vlan_add_vid_list_self(
1818 utils
.compress_into_ranges(sorted(list(vids_to_add
))),
1821 self
.iproute2
.batch_commit()
1822 except Exception as e
:
1823 self
.log_error('%s: failed to set vid `%s` (%s)'
1824 %(bportifaceobj
.name
, str(vids_to_add
),
1825 str(e
)), bportifaceobj
, raise_error
=False)
1828 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1829 self
.iproute2
.bridge_vlan_add_pvid(bportifaceobj
.name
,
1831 except Exception as e
:
1832 self
.log_error('%s: failed to set pvid `%s` (%s)'
1833 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1836 def get_bridge_vlans_mapped_to_vnis_as_integer_list(self
, ifaceobj
):
1838 Get all vlans that the user wants to configured in vlan-vni maps
1843 for vlans_vnis_map
in ifaceobj
.get_attr_value("bridge-vlan-vni-map"):
1844 for vlans_vni_map
in vlans_vnis_map
.split():
1845 vids
.extend(utils
.ranges_to_ints([vlans_vni_map
.split("=")[0]]))
1848 except Exception as e
:
1849 self
.logger
.debug("get_bridge_vlans_mapped_to_vnis_as_integer_list: %s" % str(e
))
1852 def remove_bridge_vlans_mapped_to_vnis_from_vids_list(self
, bridge_ifaceobj
, vxlan_ifaceobj
, vids_list
):
1854 For single vxlan we need to remove the vlans mapped to vnis
1855 from the vids list otherwise they will get removed from the brport
1857 if not (vxlan_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
1860 user_config_vids
= []
1863 for vid
in self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(bridge_ifaceobj
):
1864 user_config_vids
.append(vid
)
1867 for vid
in self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(vxlan_ifaceobj
):
1868 user_config_vids
.append(vid
)
1870 for vlan
in user_config_vids
:
1872 vids_list
.remove(vlan
)
1878 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
, ifaceobj_getfunc
,
1885 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1887 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1889 allow_untagged
= 'yes'
1890 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1892 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1894 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1896 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1898 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1900 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1905 vids_final
= bridge_vids
1907 if allow_untagged
== 'yes':
1909 pvid_final
= pvids
[0]
1911 pvid_final
= bridge_pvid
1917 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, ifaceobj_getfunc
, vids_final
,
1920 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1923 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1924 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1925 # Old style bridge port vid info
1926 # skip new style setting on ports
1928 self
.logger
.info('%s: applying bridge configuration '
1929 %ifaceobj
.name
+ 'specific to ports')
1931 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1933 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1937 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1939 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1943 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1944 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1945 port_processed_override
= True
1947 port_processed_override
= False
1949 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1951 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1953 self
.iproute2
.batch_start()
1954 for bport
in bridgeports
:
1955 # on link_set_master we need to wait until we cache the correct
1956 # notification and register the brport as slave
1957 if not self
.cache
.bridge_port_exists(ifaceobj
.name
, bport
):
1958 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1959 ' for port %s (missing port)' %bport
)
1961 self
.logger
.info('%s: processing bridge config for port %s'
1962 %(ifaceobj
.name
, bport
))
1963 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1964 if not bportifaceobjlist
:
1966 for bportifaceobj
in bportifaceobjlist
:
1967 # Dont process bridge port if it already has been processed
1968 # and there is no override on port_processed
1969 if (not port_processed_override
and
1970 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1971 bridgeFlags
.PORT_PROCESSED
)):
1974 # Add attributes specific to the vlan aware bridge
1975 if bridge_vlan_aware
:
1976 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1977 bportifaceobj
, ifaceobj_getfunc
, bridge_vids
, bridge_pvid
)
1978 elif self
.warn_on_untagged_bridge_absence
:
1979 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1980 except exceptions
.ReservedVlanException
as e
:
1982 except Exception as e
:
1984 self
.logger
.warning('%s: %s' %(ifaceobj
.name
, str(e
)))
1986 self
.iproute2
.batch_commit()
1988 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1990 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1991 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1992 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1993 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1994 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1995 self
.logger
.warning('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1996 self
.warn_on_untagged_bridge_absence
= False
1998 def bridge_port_get_bridge_name(self
, ifaceobj
):
1999 bridgename
= self
.cache
.get_bridge_name_from_port(ifaceobj
.name
)
2001 # bridge port is not enslaved to a bridge we need to find
2002 # the bridge in it's upper ifaces then enslave it
2003 for u
in ifaceobj
.upperifaces
:
2004 if self
.cache
.link_is_bridge(u
):
2007 # return should_enslave port, bridgename
2008 return False, bridgename
2010 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
2011 if should_enslave_port
:
2012 self
.netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
2014 if ifaceobj
.name
not in self
.svd_list
:
2015 self
.handle_ipv6([ifaceobj
.name
], '1')
2017 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
2018 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
2020 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, ifaceobj_getfunc
, bridge_vids
, bridge_pvid
)
2021 except Exception as e
:
2022 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2025 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
2026 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
2029 # bridge doesn't exist
2032 # check for bridge-learning on l2 vni in evpn setup
2033 self
.syntax_check_learning_l2_vni_evpn(ifaceobj
)
2035 # detect and warn when arp suppression is enabled and there is no vlan configured
2036 self
.syntax_check_bridge_arp_vni_vlan(ifaceobj
, ifaceobj_getfunc
)
2038 vlan_aware_bridge
= self
.cache
.bridge_is_vlan_aware(bridge_name
)
2039 if vlan_aware_bridge
:
2040 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
2043 should_enslave_port
)
2045 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
2047 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
2048 ifaceobj
=bridge_ifaceobj
,
2049 ifaceobj_getfunc
=ifaceobj_getfunc
,
2050 bridge_vlan_aware
=vlan_aware_bridge
)
2052 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
2054 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_just_created
):
2055 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
2056 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
2058 if not link_just_created
and not self
.cache
.bridge_is_vlan_aware(ifaceobj
.name
):
2059 # if bridge-vlan-aware was added on a existing old-bridge, we need to reprocess all ports
2060 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
2065 def parse_interface_list_value(user_config
):
2067 for entry
in user_config
.split():
2068 ifname
, value
= entry
.split('=')
2069 config
[ifname
] = value
2072 def sync_bridge_learning_to_vxlan_brport(self
, bridge_name
, brport_ifaceobj
, brport_name
, brport_ifla_info_slave_data
, user_config_brport_learning_nl
, cached_brport_learning
):
2074 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
2076 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
2078 Checks are not performed in this function and must be verified
2079 before. This is done this way to avoid calling this method on
2080 non vlan & bridge port interfaces thus wasting a bit less time
2085 if user_config_brport_learning_nl
is None:
2086 user_config_brport_learning_nl
= self
.bridge_vxlan_port_learning
2087 # bridge-learning is not configured by the user or by a policy
2088 # use "bridge-vxlan-port-learning" policy to set bridge-learning (default on)
2090 if user_config_brport_learning_nl
!= cached_brport_learning
:
2091 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] \
2092 = cached_brport_learning \
2093 = user_config_brport_learning_nl
2096 "%s: %s: set bridge-learning %s"
2097 % (bridge_name
, brport_name
, "on" if user_config_brport_learning_nl
else "off")
2100 # in this case, the current bridge-learning value is properly configured and
2101 # doesn't need to be reset. We need to make sure that BRPORT_LEARNING is not
2102 # part of ifla_info_slave_data.
2104 del brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
]
2109 # vxlan-learning sync:
2111 user_brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first("vxlan-learning")
2113 if not user_brport_vxlan_learning_config
:
2114 # if vxlan-learning is not defined on the brport
2116 if user_config_brport_learning_nl
is not None:
2117 # if bridge-learning is defined on the brport use it's value to sync vxlan-learning
2118 user_brport_vxlan_learning_config_nl
= user_config_brport_learning_nl
2121 # if bridge-learning is not defined, we check for policy and convert it into netlink format
2122 brport_vxlan_learning_config
= policymanager
.policymanager_api
.get_attr_default("vxlan", "vxlan-learning")
2124 if brport_vxlan_learning_config
is not None:
2125 user_brport_vxlan_learning_config_nl
= utils
.get_boolean_from_string(brport_vxlan_learning_config
)
2128 # None = no policy set, default to the current brport learning
2129 user_brport_vxlan_learning_config_nl
= cached_brport_learning
2132 # if vxlan-learning is set we need to honor the user config
2133 user_brport_vxlan_learning_config_nl
= utils
.get_boolean_from_string(user_brport_vxlan_learning_config
)
2135 if user_brport_vxlan_learning_config_nl
!= self
.cache
.get_link_info_data_attribute(
2137 Link
.IFLA_VXLAN_LEARNING
2140 "%s: %s: vxlan learning and bridge learning out of sync: set vxlan-learning %s"
2141 % (bridge_name
, brport_name
, "on" if user_brport_vxlan_learning_config_nl
else "off")
2143 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: user_brport_vxlan_learning_config_nl
}
2145 # if kind and ifla_info_data are set they will be added to the
2146 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
2147 return kind
, ifla_info_data
2149 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
2150 ifname
= ifaceobj
.name
2151 single_vxlan_device_ifaceobj
= None
2154 brports_ifla_info_slave_data
= dict()
2155 brport_ifaceobj_dict
= dict()
2156 brport_name_list
= []
2158 cache_brports_ifla_info_slave_data
= {}
2160 port_processed_override
= ifaceobj
.module_flags
.get(self
.name
, 0x0) & bridgeFlags
.PORT_PROCESSED_OVERRIDE
2162 running_brports
= self
.cache
.get_slaves(ifname
)
2164 # If target_ports is specified we want to configure only this
2165 # sub-list of port, we need to check if these ports are already
2166 # enslaved, if not they will be ignored.
2167 # If target_ports is not populated we will apply the brport
2168 # attributes on all running brport.
2171 for brport_name
in target_ports
:
2172 if brport_name
not in running_brports
:
2173 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
2175 new_targets
.append(brport_name
)
2176 running_brports
= new_targets
2178 for port
in running_brports
:
2179 brport_list
= ifaceobj_getfunc(port
)
2181 port_already_processed
= False
2183 # ports just added to the bridge have to be processed
2184 if port
not in newly_enslaved_ports
:
2185 # check if brport was already processed
2186 for brportifaceobj
in brport_list
:
2187 if not port_processed_override
and brportifaceobj
.module_flags
.get(self
.name
, 0x0) & bridgeFlags
.PORT_PROCESSED
:
2188 # skip port if already processed (probably by `up_bridge_port`)
2189 port_already_processed
= True
2190 self
.logger
.info("%s: port %s: already processed" % (ifname
, port
))
2193 if not port_already_processed
:
2194 brport_name_list
.append(port
)
2195 brport_ifaceobj_dict
[port
] = brport_list
[0]
2196 brports_ifla_info_slave_data
[port
] = dict()
2198 if not ifupdownflags
.flags
.PERFMODE
and port
not in newly_enslaved_ports
:
2199 # if the port has just been enslaved, info_slave_data is not cached yet
2200 cache_brports_ifla_info_slave_data
[port
] = self
.cache
.get_link_info_slave_data(port
)
2202 cache_brports_ifla_info_slave_data
[port
] = {}
2204 if not brport_name_list
:
2205 self
.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj
)
2208 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, brport_name_list
))
2210 cached_bridge_mcsnoop
= self
.cache
.get_bridge_multicast_snooping(ifname
)
2212 bridge_ports_learning
= {}
2213 bridge_ports_vxlan_arp_suppress
= {}
2214 cached_bridge_ports_learning
= {}
2216 # we iterate through all IFLA_BRPORT supported attributes
2217 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
.items():
2218 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
2219 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
2221 if not translate_func
:
2222 # if no translation function is found,
2223 # we ignore this attribute and continue
2227 # user didn't specify any value for this attribute
2228 # looking at policy overrides
2229 br_config
= policymanager
.policymanager_api
.get_iface_default(
2230 module_name
=self
.__class
__.__name
__,
2236 #if bridge_vlan_aware:
2237 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
2238 # 'should be configured under the ports'
2239 # % (ifname, attr_name, br_config))
2241 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
2242 # brport_name: { attr: value }
2244 # bridge-portprios swp1=5 swp2=32
2245 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
2246 if '=' in br_config
:
2248 br_config
= self
.parse_interface_list_value(br_config
)
2250 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
2253 for brport_ifaceobj
in list(brport_ifaceobj_dict
.values()):
2254 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
2255 brport_name
= brport_ifaceobj
.name
2257 if not ifupdownflags
.flags
.PERFMODE
:
2258 cached_value
= cache_brports_ifla_info_slave_data
.get(brport_name
, {}).get(nl_attr
, None)
2262 if not brport_config
:
2263 # if a brport attribute was specified under the bridge and not under the port
2264 # we assign the bridge value to the port. If an attribute is both defined under
2265 # the bridge and the brport we keep the value of the port and ignore the br val.
2266 if type(br_config
) == dict:
2267 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
2268 # br_config is a dictionary, example:
2269 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
2270 brport_config
= br_config
.get(brport_name
)
2272 brport_config
= br_config
2274 if not brport_config
:
2275 brport_config
= policymanager
.policymanager_api
.get_iface_default(
2276 module_name
=self
.__class
__.__name
__,
2281 user_config
= brport_config
2283 # attribute specific work
2284 # This shouldn't be here but we don't really have a choice otherwise this
2285 # will require too much code duplication and will make the code very complex
2286 if nl_attr
== Link
.IFLA_BRPORT_NEIGH_SUPPRESS
:
2287 bridge_ports_vxlan_arp_suppress
[brport_name
] = user_config
2290 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2291 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
2292 'is not supported on a non-vxlan port'
2293 % (ifaceobj
.name
, brport_name
))
2295 elif bridge_vlan_aware
:
2296 if not self
.arp_nd_suppress_only_on_vxlan
:
2297 user_config
= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
2298 elif self
.arp_nd_suppress_only_on_vxlan
and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2299 # ignore the case of VXLAN brport - handled later in the code
2303 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
2304 # special handking for group_fwd_mask because Cisco proprietary
2305 # protocol needs to be set via a private netlink attribute
2306 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
2307 brports_ifla_info_slave_data
,
2308 user_config
, cached_value
)
2312 # if not bridge_vlan_aware:
2313 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
2314 # 'should be configured under the bridge'
2315 # % (ifname, brport_name,
2316 # attr_name, brport_config))
2319 user_config_nl
= translate_func(user_config
)
2320 # check config value against running value
2321 if user_config_nl
!= cached_value
:
2322 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
2323 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
2324 self
.logger
.debug('(cache %s)' % cached_value
)
2326 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
2327 # for vxlan-learning sync purposes we need to save the user config for each brports.
2328 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
2329 # IFLA_BRPORT_LEARNING if the user value is already configured and running
2330 # nevertheless we still need to check if the vxlan-learning is rightly synced with
2331 # the brport since it might go out of sync for X and Y reasons.
2332 # we also store the cached value to avoid an extra cache lookup.
2333 bridge_ports_learning
[brport_name
] = user_config_nl
2334 cached_bridge_ports_learning
[brport_name
] = cached_value
2336 elif cached_value
is not None:
2337 # no config found, do we need to reset to default?
2338 default
= self
.get_attr_default_value(attr_name
)
2340 default_netlink
= translate_func(default
)
2342 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
2343 # for vxlan-learning sync purposes we need to save the user config for each brports.
2344 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
2345 # IFLA_BRPORT_LEARNING if the user value is already configured and running
2346 # nevertheless we still need to check if the vxlan-learning is rightly synced with
2347 # the brport since it might go out of sync for X and Y reasons.
2348 # we also store the cached value to avoid an extra cache lookup.
2349 cached_bridge_ports_learning
[brport_name
] = cached_value
2350 bridge_ports_learning
[brport_name
] = self
.bridge_vxlan_port_learning
2352 if brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2353 # bridge-learning for vxlan device is handled separatly in sync_bridge_learning_to_vxlan_brport
2356 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
2357 # We don't query new slaves and not during boot
2359 if self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_PEER_LINK
):
2360 if default_netlink
!= cached_value
:
2361 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
2362 % (ifname
, brport_name
))
2364 except Exception as e
:
2365 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
2367 if nl_attr
== Link
.IFLA_BRPORT_MULTICAST_ROUTER
:
2369 if (brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
2370 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
) \
2373 self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
2374 self
.get_bridge_mcsnoop_value(ifaceobj
))
2375 ) or cached_bridge_mcsnoop
2377 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter" is on and mcsnoop is
2378 # on (or mcsnoop is already enabled on the bridge, keep 'bridge-portmcrouter 2'
2379 # on vxlan ports (if not set by the user)
2380 if cached_value
== 2:
2383 if default_netlink
!= cached_value
:
2384 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
2385 % (ifname
, brport_name
, attr_name
, default
))
2386 self
.logger
.debug('(cache %s)' % cached_value
)
2387 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
2389 # is the current bridge (ifaceobj) a QinQ bridge?
2390 # This variable is initialized to None and will be
2391 # change to True/False, so that the check is only
2395 # applying bridge port configuration via netlink
2396 for brport_name
, brport_ifla_info_slave_data
in list(brports_ifla_info_slave_data
.items()):
2398 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
2400 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
2401 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
2402 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
2403 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
2404 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
2407 brport_ifla_info_slave_data
,
2408 bridge_ports_learning
.get(brport_name
),
2409 cached_bridge_ports_learning
.get(brport_name
))
2411 if (self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
2412 self
.get_bridge_mcsnoop_value(ifaceobj
)
2413 )) or cached_bridge_mcsnoop
:
2414 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
2415 # is on and mcsnoop is on (or mcsnoop is already enabled on the
2416 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
2417 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
) \
2418 and self
.cache
.get_bridge_port_multicast_router(brport_name
) != 2:
2419 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
2420 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
2423 # handling attribute: bridge-arp-nd-suppress
2424 # defaults to bridge-vxlan-arp-nd-suppress policy (default False)
2426 user_config_neigh_suppress
= bridge_ports_vxlan_arp_suppress
.get(brport_name
)
2428 if user_config_neigh_suppress
is None:
2430 if qinq_bridge
is None:
2431 # QinQ bridge hasn't been checked yet
2432 qinq_bridge
= self
.is_qinq_bridge(
2436 brport_ifaceobj_dict
,
2441 # exclude QinQ bridge from arp-nd-suppress default policy on
2442 config_neigh_suppress
= 0
2443 self
.logger
.info("%s: QinQ bridge detected: %s: set bridge-arp-nd-suppress off" % (ifname
, brport_name
))
2445 config_neigh_suppress
= self
.bridge_vxlan_arp_nd_suppress_int
2447 config_neigh_suppress
= int(utils
.get_boolean_from_string(user_config_neigh_suppress
))
2449 brport_neigh_suppress_cached_value
= self
.cache
.get_link_info_slave_data_attribute(
2451 Link
.IFLA_BRPORT_NEIGH_SUPPRESS
2454 if config_neigh_suppress
!= brport_neigh_suppress_cached_value
:
2455 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_NEIGH_SUPPRESS
] = config_neigh_suppress
2457 if not user_config_neigh_suppress
:
2458 # if the configuration is not explicitely defined by the user
2459 # we need report that the default behavior is enabled by policy
2461 "%s: set bridge-arp-nd-suppress %s by default on vxlan port (%s)"
2462 % (ifname
, "on" if self
.bridge_vxlan_arp_nd_suppress
else "off", brport_name
)
2465 # the user configuration (or policy) is already configured and running
2466 # we need to remove this attribute from the request dictionary
2468 del brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_NEIGH_SUPPRESS
]
2473 # SINGLE VXLAN - enable IFLA_BRPORT_VLAN_TUNNEL
2476 if brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
2477 single_vxlan_device_ifaceobj
= brport_ifaceobj
2478 brport_vlan_tunnel_cached_value
= self
.cache
.get_link_info_slave_data_attribute(
2480 Link
.IFLA_BRPORT_VLAN_TUNNEL
2483 if not brport_vlan_tunnel_cached_value
:
2484 self
.logger
.info("%s: %s: enabling vlan_tunnel on single vxlan device" % (ifname
, brport_name
))
2485 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_VLAN_TUNNEL
] = 1
2491 if brport_ifla_info_slave_data
or ifla_info_data
:
2493 self
.netlink
.link_set_brport_with_info_slave_data(
2496 ifla_info_data
=ifla_info_data
,
2497 ifla_info_slave_data
=brport_ifla_info_slave_data
2499 except Exception as e
:
2500 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
2502 self
.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj
)
2504 except Exception as e
:
2505 self
.log_error(str(e
), ifaceobj
)
2507 if single_vxlan_device_ifaceobj
:
2508 self
.apply_bridge_port_vlan_vni_map(single_vxlan_device_ifaceobj
)
2511 def range_to_string(range_start
, range_end
):
2512 return "%s" % range_start
if range_start
== range_end
else "%s-%s" % (range_start
, range_end
)
2514 def range_list_to_string(self
, ifname
, vni_list
):
2515 range_list
= [v
for v
in utils
.ints_to_ranges(vni_list
)]
2517 if len(range_list
) != 1 and len(range_list
[0]) > 0:
2518 self
.logger
.debug("%s: vlan-vni-map has duplicated ranges: %s" % (ifname
, json
.dumps(range_list
, indent
=4)))
2519 self
.log_error("misconfiguration detected - see debug output for details")
2521 return self
.range_to_string(range_list
[0][0], range_list
[0][1])
2523 def check_duplicate_vnis(self
, ifaceobj
, vlan_vni_dict
):
2526 for key
, value
in vlan_vni_dict
.items():
2527 rev
.setdefault(value
, set()).add(key
)
2529 duplicates
= [(key
, values
) for key
, values
in rev
.items() if len(values
) > 1]
2532 err_msg
= ["duplicate vnis detected - see details below"]
2534 for vni
, vlans
in duplicates
:
2535 err_msg
.append("\tvni %s assigned to vlans: %s" % (vni
, ", ".join(map(str, vlans
))))
2537 self
.log_error("\n".join(err_msg
), ifaceobj
)
2542 def get_vlan_vni_ranges_from_dict(self
, ifname
, vlan_vni_dict
):
2544 Since bridge-vlan-vni-map is a multiline attribute, we expend all the ranges
2545 and have all the vlan-vni mapping in vlan_vni_dict. We need to reconstruct the
2546 ranges to execute iproute2 commands.
2548 i.e. for a multiline vlan-vni configuration:
2549 bridge-vlan-vni-map 1=1
2550 bridge-vlan-vni-map 2=2
2551 bridge-vlan-vni-map 3=3
2552 bridge-vlan-vni-map 4=4
2554 we will only execute a single ranged-command: vlan add dev vxlan48 vid 1-4 tunnel_info id 1-4
2556 If we find duplicated vlan/vnis in ranges we raise an exception
2558 vlan_vni_ranges
= {}
2560 def list_to_range(vlan_list
, vni_list
, range_dict
):
2561 if not vlan_list
and not vni_list
:
2563 vlans
= self
.range_list_to_string(ifname
, vlan_list
)
2564 vnis
= self
.range_list_to_string(ifname
, vni_list
)
2565 range_dict
[vlans
] = vnis
2567 current_vlan_range
= []
2568 current_vni_range
= []
2570 for vlan
in sorted(vlan_vni_dict
.keys()):
2571 vni
= vlan_vni_dict
[vlan
]
2573 if not current_vlan_range
:
2574 current_vlan_range
.append(vlan
)
2575 current_vni_range
.append(vni
)
2578 if vlan
- 1 == current_vlan_range
[-1] and vni
- 1 == current_vni_range
[-1]:
2579 current_vlan_range
.append(vlan
)
2580 current_vni_range
.append(vni
)
2582 list_to_range(current_vlan_range
, current_vni_range
, vlan_vni_ranges
)
2583 current_vlan_range
= [vlan
]
2584 current_vni_range
= [vni
]
2586 list_to_range(current_vlan_range
, current_vni_range
, vlan_vni_ranges
)
2587 return vlan_vni_ranges
2589 def check_bridge_vlan_vni_map_reserved(self
, ifaceobj
, vlan_to_add
):
2590 for vlan
in sorted(vlan_to_add
):
2591 self
._handle
_reserved
_vlan
(vlan
, ifaceobj
.name
)
2593 def apply_bridge_port_vlan_vni_map(self
, ifaceobj
):
2595 bridge vlan add vid <vlan-id> dev vxlan0
2596 bridge vlan add dev vxlan0 vid <vlan-id> tunnel_info id <vni>
2598 vxlan_name
= ifaceobj
.name
2600 self
.iproute2
.batch_start()
2602 bridge_vlan_tunnel_info_running_config
= self
.iproute2
.bridge_vlan_tunnel_show(vxlan_name
)
2603 all_user_config
= {}
2605 for bridge_vlan_vni_map_entry
in ifaceobj
.get_attr_value("bridge-vlan-vni-map"):
2606 if not bridge_vlan_vni_map_entry
:
2609 for vlan_vni_map_entry
in bridge_vlan_vni_map_entry
.split():
2611 vlans_str
, vni_str
= utils
.get_vlan_vni_in_map_entry(vlan_vni_map_entry
)
2613 return self
.__warn
_bridge
_vlan
_vni
_map
_syntax
_error
(vxlan_name
, vlan_vni_map_entry
)
2615 # we need to convert vlan_str and vni_str back to a map {vlan: vni}
2616 for vlan
, vni
in zip(utils
.ranges_to_ints([vlans_str
]), utils
.ranges_to_ints([vni_str
])):
2618 if vlan
in all_user_config
:
2619 self
.log_error("duplicate vlan found: %s" % vlan
, ifaceobj
)
2621 all_user_config
[vlan
] = vni
2623 vlan_vni_to_remove
= {}
2624 for k
, v
in set(bridge_vlan_tunnel_info_running_config
.items()) - set(all_user_config
.items()):
2625 vlan_vni_to_remove
[k
] = v
2627 vlan_vni_to_add
= {}
2628 for k
, v
in set(all_user_config
.items()) - set(bridge_vlan_tunnel_info_running_config
.items()):
2629 vlan_vni_to_add
[k
] = v
2631 vlan_vni_ranges_to_remove
= self
.get_vlan_vni_ranges_from_dict(ifaceobj
.name
, vlan_vni_to_remove
)
2633 # check if we have duplicated vnis in the user configuration
2634 self
.check_duplicate_vnis(ifaceobj
, vlan_vni_to_add
)
2636 # check reserved vlans
2637 self
.check_bridge_vlan_vni_map_reserved(ifaceobj
, vlan_vni_to_add
.keys())
2639 vlan_vni_ranges_to_add
= self
.get_vlan_vni_ranges_from_dict(ifaceobj
.name
, vlan_vni_to_add
)
2641 for vlan_range
, vni_range
in vlan_vni_ranges_to_remove
.items():
2642 self
.iproute2
.bridge_vlan_del_vid_list_self(vxlan_name
, [vlan_range
], False)
2643 self
.iproute2
.bridge_vlan_del_vlan_tunnel_info(vxlan_name
, vlan_range
, vni_range
)
2645 for vlan_range
, vni_range
in vlan_vni_ranges_to_add
.items():
2646 self
.iproute2
.bridge_vlan_add_vid_list_self(vxlan_name
, [vlan_range
], False)
2647 self
.iproute2
.bridge_vlan_add_vlan_tunnel_info(vxlan_name
, vlan_range
, vni_range
)
2649 self
.iproute2
.batch_commit()
2650 except Exception as e
:
2651 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2652 raise BridgeVlanVniMapError("%s: error while processing bridge-vlan-vni-map: %s" % (vxlan_name
, str(e
)))
2654 def __warn_bridge_vlan_vni_map_syntax_error(self
, ifname
, user_config_vlan_vni_map
):
2655 self
.logger
.warning("%s: syntax error: bridge-vlan-vni-map %s" % (ifname
, user_config_vlan_vni_map
))
2657 def is_qinq_bridge(self
, ifaceobj
, brport_name
, running_brports
, brport_ifaceobj_dict
, ifaceobj_getfunc
):
2658 """ Detect QinQ bridge
2659 Potential improvement: We could add a ifaceobj.link_privflags called
2660 BRIDGE_QINQ but for now it is not necessary.
2663 # bridge-vlan-aware case
2664 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
2665 return (ifaceobj
.get_attr_value_first("bridge-vlan-protocol") or "").lower() == "802.1ad"
2669 for qinq_running_brport
in running_brports
:
2670 if qinq_running_brport
== brport_name
:
2673 qinq_running_brport_ifaceobj
= brport_ifaceobj_dict
.get(qinq_running_brport
)
2675 if not qinq_running_brport_ifaceobj
:
2678 if qinq_running_brport_ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
2679 for lower_iface
in qinq_running_brport_ifaceobj
.lowerifaces
or []:
2680 for lower_ifaceobj
in ifaceobj_getfunc(lower_iface
) or []:
2681 if (lower_ifaceobj
.get_attr_value_first("vlan-protocol") or "").lower() == "802.1ad":
2685 def bridge_process_vidinfo_mcqv4src_maxwait(self
, ifaceobj
):
2686 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
2687 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
2688 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
2690 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
2692 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
2693 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
2694 field we need to have special handling for that.
2696 ifla_brport_group_fwd_mask
= 0
2697 ifla_brport_group_fwd_maskhi
= 0
2700 for group
in user_config
.replace(",", " ").split():
2704 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2706 if not callable(callback
):
2707 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2709 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2711 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2712 cached_ifla_brport_group_fwd_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
2714 log_mask_change
= True
2715 # if user specify bridge-l2protocol-tunnel stp cdp
2716 # we need to set both MASK and MASKHI but we only want to log once
2718 if cached_ifla_brport_group_fwd_mask
is None:
2719 cached_ifla_brport_group_fwd_mask
= 0
2720 if cached_ifla_brport_group_fwd_maskhi
is None:
2721 cached_ifla_brport_group_fwd_maskhi
= 0
2723 # if the cache value is None it means that the kernel doesn't support this attribute
2724 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2726 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2728 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2729 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2730 log_mask_change
= False
2731 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2733 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2735 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2736 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2737 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2739 def get_bridge_mtu(self
, ifaceobj
):
2740 user_config_mtu
= ifaceobj
.get_attr_value_first("mtu")
2742 if not user_config_mtu
:
2743 user_config_mtu
= policymanager
.policymanager_api
.get_attr_default(
2744 module_name
="address",
2750 int(user_config_mtu
)
2751 self
.logger
.info("%s: set bridge mtu %s" % (ifaceobj
.name
, user_config_mtu
))
2752 return str(user_config_mtu
)
2753 except Exception as e
:
2754 self
.logger
.warning("%s: invalid bridge mtu %s: %s" % (ifaceobj
.name
, user_config_mtu
, str(e
)))
2757 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2758 ifname
= ifaceobj
.name
2760 if ifupdownflags
.flags
.PERFMODE
:
2763 link_exists
= self
.cache
.link_exists(ifaceobj
.name
)
2766 self
.netlink
.link_add_bridge(ifname
)
2767 link_just_created
= True
2769 bridge_mtu
= self
.get_bridge_mtu(ifaceobj
)
2771 self
.sysfs
.link_set_mtu(ifname
, bridge_mtu
, int(bridge_mtu
))
2773 link_just_created
= False
2774 self
.logger
.info('%s: bridge already exists' % ifname
)
2776 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, link_just_created
)
2778 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2781 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2782 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2783 newly_enslaved_ports
=newly_enslaved_ports
)
2784 except BridgeVlanVniMapError
:
2786 except Exception as e
:
2787 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2791 running_ports
= self
.cache
.get_slaves(ifaceobj
.name
)
2792 if not running_ports
:
2794 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2795 ifaceobj_getfunc
=ifaceobj_getfunc
,
2796 bridge_vlan_aware
=bridge_vlan_aware
)
2797 except exceptions
.ReservedVlanException
as e
:
2799 except Exception as e
:
2800 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2802 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2803 self
.iproute2
.batch_start()
2804 for p
in running_ports
:
2805 ifaceobj_list
= ifaceobj_getfunc(p
)
2806 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2807 self
.iproute2
.link_down(p
)
2809 self
.iproute2
.link_up(p
)
2811 self
.iproute2
.batch_commit()
2812 except Exception as e
:
2813 # link set up on bridge ports failed - ignore and log debug
2814 self
.logger
.debug("%s: %s" % (ifname
, str(e
)))
2817 self
._up
_bridge
_mac
(ifaceobj
, link_just_created
, ifaceobj_getfunc
)
2818 except Exception as e
:
2819 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2821 def _get_bridge_mac(self
, ifaceobj
, ifname
, link_just_created
, ifaceobj_getfunc
):
2822 bridge_mac_iface
= self
.bridge_mac_iface
.get(ifname
)
2824 if bridge_mac_iface
and bridge_mac_iface
[0] and bridge_mac_iface
[1]:
2825 return bridge_mac_iface
2827 if self
.bridge_mac_iface_list
:
2828 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2830 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2831 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2835 for obj
in ifaceobj_list
:
2836 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2837 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2838 if iface_user_configured_hwaddress
:
2839 iface_mac
= iface_user_configured_hwaddress
2841 if not iface_mac
and not self
.cache
.link_exists(bridge_mac_intf
):
2845 iface_mac
= self
.cache
.get_link_address(bridge_mac_intf
)
2846 # if hwaddress attribute is not configured we use the running mac addr
2848 self
.bridge_mac_iface
[ifname
] = (bridge_mac_intf
, iface_mac
)
2849 return self
.bridge_mac_iface
[ifname
]
2850 elif self
.bridge_set_static_mac_from_port
:
2851 # no policy was provided, we need to get the first physdev or bond ports
2852 # and use its hwaddress to set the bridge mac
2854 # first we need to make sure that the bridge mac is not already inherited from one of it's port
2855 bridge_ports
= self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
)
2857 # if the bridge was just created we need to set it's mac address to the first port and not look at the
2858 # current bridge mac (the bridge driver probably chose the lowest mac of it's port)
2859 if not link_just_created
:
2860 current_mac
= self
.cache
.get_link_address(ifname
)
2862 for port
in bridge_ports
or []:
2863 if not self
.is_vxlan(ifaceobj_getfunc(port
)):
2864 port_mac
= self
.cache
.get_link_address(port
)
2866 if current_mac
== port_mac
:
2867 self
.logger
.info("bridge mac is already inherited from %s" % port
)
2868 self
.bridge_mac_iface
[ifname
] = (port
, port_mac
)
2869 return self
.bridge_mac_iface
[ifname
]
2871 for port
in bridge_ports
or []:
2872 # iterate through the bridge-port list
2873 for port_obj
in ifaceobj_getfunc(port
) or []:
2874 # check if the port is a physdev (link_kind is null) or a bon
2875 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2876 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2877 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2878 if iface_user_configured_hwaddress
:
2879 iface_mac
= iface_user_configured_hwaddress
.lower()
2880 # we need to "normalize" the user provided MAC so it can match with
2881 # what we have in the cache (data retrieved via a netlink dump by
2882 # nlmanager). nlmanager return all macs in lower-case
2884 iface_mac
= self
.cache
.get_link_address(port
)
2887 self
.bridge_mac_iface
[ifname
] = (port
, iface_mac
)
2888 return self
.bridge_mac_iface
[ifname
]
2893 def is_vxlan(port_obj_list
):
2894 # checking if the port is a vxlan by checking the ifaceobjs
2895 # instead of checking to cache (saving on locking time)
2896 for _port_obj
in port_obj_list
or []:
2897 if _port_obj
.link_kind
== ifaceLinkKind
.VXLAN
:
2901 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2902 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2903 self
.iproute2
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2905 def _up_bridge_mac(self
, ifaceobj
, link_just_created
, ifaceobj_getfunc
):
2907 We have a day one bridge mac changing problem with changing ports
2908 (basically bridge mac changes when the port it inherited the mac from
2911 We have discussed this problem many times before and tabled it.
2912 The issue has aggravated with vxlan bridge ports having auto-generated
2913 random macs...which change on every reboot.
2915 ifupdown2 extract from policy files an iface to select a mac from and
2916 configure it automatically.
2918 if ifaceobj
.get_attr_value('hwaddress'):
2919 # if the user configured a static hwaddress
2920 # there is no need to assign one
2923 ifname
= ifaceobj
.name
2924 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, link_just_created
, ifaceobj_getfunc
)
2925 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2926 %(ifname
, mac_intf
, bridge_mac
))
2929 # if an interface is configured with the following attribute:
2930 # hwaddress 08:00:27:42:42:4
2931 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2932 # from the kernel. The only way to counter that is to convert all mac to int
2933 # and compare the ints, it will increase perfs and be safer.
2934 cached_value
= self
.cache
.get_link_address(ifname
)
2935 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2936 bridge_mac_int
= utils
.mac_str_to_int(bridge_mac
)
2938 # if the bridge was just created (link_just_created) we should force-set the mac address
2939 if not link_just_created
and cached_value
and utils
.mac_str_to_int(cached_value
) == bridge_mac_int
:
2940 # the bridge mac is already set to the bridge_mac_intf's mac
2943 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2945 self
.netlink
.link_set_address(ifname
, bridge_mac
, bridge_mac_int
) # force=True
2946 except Exception as e
:
2947 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2948 # log info this error because the user didn't explicitly configured this
2950 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.cache
.get_link_address(ifname
))
2952 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2953 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2954 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2956 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2957 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2960 bridge_attributes
= list(self
._modinfo
.get('attrs', {}).keys())
2962 for ifaceobj_config_attr
in list(ifaceobj
.config
.keys()):
2963 if ifaceobj_config_attr
in bridge_attributes
:
2964 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2965 % (ifaceobj
.name
, ifaceobj_config_attr
))
2967 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2968 if not self
._is
_bridge
(ifaceobj
):
2970 ifname
= ifaceobj
.name
2971 if not self
.cache
.link_exists(ifname
):
2975 self
.netlink
.link_del(self
.get_dummy_brport_name_for_bridge(ifname
))
2980 running_ports
= self
.cache
.get_slaves(ifname
)
2982 self
.handle_ipv6(running_ports
, '0')
2983 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2984 for p
in running_ports
:
2985 self
.netlink
.link_down(p
)
2986 except Exception as e
:
2987 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2989 self
.netlink
.link_del(ifname
)
2990 except Exception as e
:
2991 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2992 self
.logger
.error(str(e
))
2993 # netlink exception already contains the ifname
2995 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2998 running_bridge_port_vids
= ''
3001 _
, running_vids
= self
.cache
.get_pvid_and_vids(p
)
3003 running_bridge_port_vids
+= ' %s=%s' %(p
,
3004 ','.join(running_vids
))
3007 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
3009 running_bridge_port_pvid
= ''
3012 running_pvid
= self
.cache
.get_pvid(p
)
3014 running_bridge_port_pvid
+= ' %s=%s' %(p
,
3018 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
3020 _
, running_bridge_vids
= self
.cache
.get_pvid_and_vids(ifaceobjrunning
.name
)
3021 if running_bridge_vids
:
3022 running_attrs
['bridge-vids'] = ','.join(utils
.compress_into_ranges(running_bridge_vids
))
3023 return running_attrs
3025 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
3029 # 'bridge-vids' under the bridge is all about 'vids' on the port.
3030 # so query the ports
3031 running_bridgeport_vids
= []
3032 running_bridgeport_pvids
= []
3033 for bport
in bridgeports
:
3034 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
3036 running_bridgeport_vids
.append(' '.join(vids
))
3038 running_bridgeport_pvids
.append(pvid
)
3041 if running_bridgeport_vids
:
3042 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
3043 if freq
== len(bridgeports
):
3044 running_attrs
['bridge-vids'] = vidval
3045 bridge_vids
= vidval
.split()
3048 if running_bridgeport_pvids
:
3049 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
3050 if freq
== len(bridgeports
) and vidval
!= '1':
3051 running_attrs
['bridge-pvid'] = vidval
3052 bridge_pvid
= vidval
.split()[0]
3054 # Go through all bridge ports and find their vids
3055 for bport
in bridgeports
:
3056 bportifaceobj
= ifaceobj_getfunc(bport
)
3057 if not bportifaceobj
:
3061 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
3062 if vids
and vids
!= bridge_vids
:
3064 if pvid
and pvid
!= bridge_pvid
:
3066 if bport_vids
and bport_pvid
in bport_vids
:
3067 bport_vids
.remove(bport_pvid
)
3068 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
3069 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
3070 bportifaceobj
[0].delete_config('bridge-pvid')
3071 bportifaceobj
[0].delete_config('bridge-vids')
3073 if bport_pvid
and bport_pvid
!= '1':
3074 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
3076 # delete any stale bridge-vids under ports
3077 bportifaceobj
[0].delete_config('bridge-pvid')
3079 bportifaceobj
[0].replace_config('bridge-vids',
3080 ' '.join(bport_vids
))
3082 # delete any stale bridge-vids under ports
3083 bportifaceobj
[0].delete_config('bridge-vids')
3084 return running_attrs
3086 def _query_running_mcqv4src(self
, ifaceobjrunning
):
3087 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobjrunning
.name
)
3088 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in list(running_mcqv4src
.items())]
3090 mcq
= ' '.join(mcqs
)
3093 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
3094 bridge_vlan_aware
=False):
3096 ifname
= ifaceobjrunning
.name
3101 if self
.systcl_get_net_bridge_stp_user_space() == '1':
3103 except Exception as e
:
3104 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
3106 bridge_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
3109 # Fill bridge_ports and bridge stp attributes first
3113 bridgeattrdict
["bridge-ports"] = [" ".join(self
.cache
.get_slaves(ifname
))]
3118 cached_stp
= bool(bridge_ifla_info_data
.get(Link
.IFLA_BR_STP_STATE
))
3120 if cached_stp
!= utils
.get_boolean_from_string(
3121 self
.get_mod_subattr("bridge-stp", "default")
3123 bridgeattrdict
['bridge-stp'] = ["yes" if cached_stp
else "no"]
3125 skip_kernel_stp_attrs
= cached_stp
and userspace_stp
3127 if skip_kernel_stp_attrs
:
3128 bridge_attributes_map
= {
3129 "bridge-mcqifaddr": Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
,
3130 "bridge-mcquerier": Link
.IFLA_BR_MCAST_QUERIER
,
3131 "bridge-mcrouter": Link
.IFLA_BR_MCAST_ROUTER
,
3132 "bridge-mcstats": Link
.IFLA_BR_MCAST_STATS_ENABLED
,
3133 "bridge-mcsnoop": Link
.IFLA_BR_MCAST_SNOOPING
,
3134 "bridge-mclmc": Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
,
3135 "bridge-mclmi": Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
,
3136 "bridge-mcqri": Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
,
3137 "bridge-mcqpi": Link
.IFLA_BR_MCAST_QUERIER_INTVL
,
3138 "bridge-mcsqc": Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
,
3139 "bridge-mcsqi": Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
,
3140 "bridge-mcmi": Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
,
3141 "bridge-mcqi": Link
.IFLA_BR_MCAST_QUERY_INTVL
,
3144 bridge_attributes_map
= dict(self
._ifla
_br
_attributes
_map
)
3146 del bridge_attributes_map
[Link
.IFLA_BR_STP_STATE
]
3153 cached_vlan_stats
= bridge_ifla_info_data
.get(Link
.IFLA_BR_VLAN_STATS_ENABLED
)
3155 if cached_vlan_stats
!= utils
.get_boolean_from_string(
3156 self
.get_mod_subattr("bridge-vlan-stats", "default")
3158 bridgeattrdict
['bridge-vlan-stats'] = ["on" if cached_vlan_stats
else "off"]
3161 del bridge_attributes_map
[Link
.IFLA_BR_VLAN_STATS_ENABLED
]
3165 lambda_nl_value_int_divide100
= lambda x
: str(x
// 100)
3166 lambda_nl_value_to_yes_no_boolean
= lambda x
: "yes" if x
else "no"
3168 bridge_attr_value_netlink_to_string_dict
= {
3169 Link
.IFLA_BR_VLAN_PROTOCOL
: lambda x
: x
.lower(), # return lower case vlan protocol
3170 Link
.IFLA_BR_AGEING_TIME
: lambda_nl_value_int_divide100
,
3171 Link
.IFLA_BR_MAX_AGE
: lambda_nl_value_int_divide100
,
3172 Link
.IFLA_BR_FORWARD_DELAY
: lambda_nl_value_int_divide100
,
3173 Link
.IFLA_BR_HELLO_TIME
: lambda_nl_value_int_divide100
,
3174 Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
: lambda_nl_value_int_divide100
,
3175 Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
: lambda_nl_value_int_divide100
,
3176 Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
: lambda_nl_value_int_divide100
,
3177 Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
: lambda_nl_value_int_divide100
,
3178 Link
.IFLA_BR_MCAST_QUERIER_INTVL
: lambda_nl_value_int_divide100
,
3179 Link
.IFLA_BR_MCAST_QUERY_INTVL
: lambda_nl_value_int_divide100
,
3180 Link
.IFLA_BR_VLAN_FILTERING
: lambda_nl_value_to_yes_no_boolean
,
3181 Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
: lambda_nl_value_to_yes_no_boolean
,
3182 Link
.IFLA_BR_MCAST_SNOOPING
: lambda_nl_value_to_yes_no_boolean
,
3183 Link
.IFLA_BR_MCAST_QUERIER
: lambda_nl_value_to_yes_no_boolean
,
3184 Link
.IFLA_BR_MCAST_ROUTER
: lambda_nl_value_to_yes_no_boolean
,
3187 for attr_name
, attr_nl
in bridge_attributes_map
.items():
3188 default_value
= self
.get_mod_subattr(attr_name
, "default")
3189 cached_value
= bridge_ifla_info_data
.get(attr_nl
)
3191 if cached_value
is None:
3194 cached_value_string
= bridge_attr_value_netlink_to_string_dict
.get(attr_nl
, str)(cached_value
)
3196 if default_value
!= cached_value_string
:
3197 bridgeattrdict
[attr_name
] = [cached_value_string
]
3199 if bridge_vlan_aware
:
3202 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
3206 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
3209 bridgeattrdict
.update({k
: [v
] for k
, v
in list(bridgevidinfo
.items())
3212 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
3214 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
3216 if skip_kernel_stp_attrs
:
3217 return bridgeattrdict
3219 # Do this only for vlan-UNAWARE-bridge
3220 if ports
and not bridge_vlan_aware
:
3221 portconfig
= {'bridge-pathcosts' : '',
3222 'bridge-portprios' : '',
3223 'bridge-learning' : '',
3224 'bridge-unicast-flood' : '',
3225 'bridge-multicast-flood' : '',
3226 'bridge-broadcast-flood' : '',
3227 'bridge-arp-nd-suppress' : '',
3229 for p
, v
in list(ports
.items()):
3230 v
= str(self
.cache
.get_brport_cost(p
))
3231 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
3233 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
3235 v
= str(self
.cache
.get_brport_priority(p
))
3236 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
3238 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
3240 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_learning(p
))
3242 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
3243 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
3245 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_unicast_flood(p
))
3247 v
!= self
.get_mod_subattr('bridge-unicast-flood',
3249 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
3251 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_multicast_flood(p
))
3253 v
!= self
.get_mod_subattr('bridge-multicast-flood',
3255 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
3257 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_broadcast_flood(p
))
3259 v
!= self
.get_mod_subattr('bridge-broadcast-flood',
3261 portconfig
['bridge-broadcast-flood'] += ' %s=%s' %(p
, v
)
3263 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_neigh_suppress(p
))
3265 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
3267 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
3269 bridgeattrdict
.update({k
: [v
] for k
, v
in list(portconfig
.items())
3272 return bridgeattrdict
3274 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
3275 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
3276 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
3278 mcqs
= attrval
.split()
3280 mcqsout
= ' '.join(mcqs
)
3281 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
3282 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
3284 def _query_check_bridge_vidinfo(self
, ifname
, ifaceobj
, ifaceobjcurr
):
3288 bridge_port_vids_user_config
= ifaceobj
.get_attr_value_first("bridge-port-vids")
3289 if bridge_port_vids_user_config
:
3291 port_list
= self
.parse_port_list(ifname
, bridge_port_vids_user_config
)
3294 self
.log_warn("%s: could not parse 'bridge-port-vids %s'"
3295 % (ifname
, bridge_port_vids_user_config
))
3296 ifaceobjcurr
.update_config_with_status("bridge-port-vids", "ERROR", 1)
3300 for port_config
in port_list
:
3302 port
, vids_raw
= port_config
.split("=")
3303 packed_vids
= vids_raw
.split(",")
3305 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(port
)
3307 if not utils
.compare_ids(packed_vids
, running_vids
, pvid
=running_pvid
, expand_range
=False):
3310 except Exception as e
:
3311 self
.log_warn("%s: failure checking vid %s (%s)" % (ifname
, port_config
, str(e
)))
3313 ifaceobjcurr
.update_config_with_status("bridge-port-vids", bridge_port_vids_user_config
, error
)
3318 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
3320 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3322 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
3323 % (ifname
, attrval
))
3327 running_pvid_config
= []
3329 (port
, pvid
) = p
.split('=')
3330 running_pvid
, _
= self
.cache
.get_pvid_and_vids(port
)
3332 running_pvid_config
.append("%s=%s" % (port
, running_pvid
))
3334 if running_pvid
!= int(pvid
):
3337 ifaceobjcurr
.update_config_with_status(
3338 "bridge-port-pvids",
3339 " ".join(running_pvid_config
),
3343 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
3345 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
3347 def _query_check_snooping_wdefault(self
, ifaceobj
):
3348 if (ifupdownflags
.flags
.WITHDEFAULTS
3349 and not self
._vxlan
_bridge
_default
_igmp
_snooping
3350 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
3351 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
3353 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
3354 if not self
._is
_bridge
(ifaceobj
):
3357 ifname
= ifaceobj
.name
3359 if not self
.cache
.bridge_exists(ifname
):
3360 self
.logger
.info("%s: bridge: does not exist" % (ifname
))
3363 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
3365 user_config_attributes
= self
.dict_key_subset(ifaceobj
.config
, self
.get_mod_attrs())
3367 # add default attributes if --with-defaults is set
3368 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in user_config_attributes
:
3369 user_config_attributes
.append('bridge-stp')
3371 if not user_config_attributes
:
3374 if "bridge-ports" in user_config_attributes
:
3375 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, self
.cache
.get_slaves(ifname
), ifaceobj_getfunc
)
3377 if "bridge-ports-condone-regex" in user_config_attributes
:
3378 ifaceobjcurr
.update_config_with_status(
3379 "bridge-ports-condone-regex",
3380 self
._get
_bridge
_port
_condone
_regex
(ifaceobj
, True),
3384 # Those attributes require separate handling
3385 filter_attributes
= [
3392 "bridge-port-pvids",
3393 "bridge-l2protocol-tunnel",
3394 "bridge-ports-condone-regex"
3397 ignore_attributes
= (
3398 # bridge-pvid and bridge-vids on a bridge does not correspond
3399 # directly to a running config on the bridge. They correspond to
3400 # default values for the bridge ports. And they are already checked
3401 # against running config of the bridge port and reported against a
3402 # bridge port. So, ignore these attributes under the bridge. Use '2'
3403 # for ignore today. XXX: '2' will be mapped to a defined value in
3404 # subsequent patches.
3406 "bridge-allow-untagged",
3408 for attr
in ignore_attributes
:
3409 if attr
in user_config_attributes
:
3410 ifaceobjcurr
.update_config_with_status(attr
, ifaceobj
.get_attr_value_first(attr
), 2)
3411 filter_attributes
.append(attr
)
3413 bridge_config
= set(user_config_attributes
).difference(filter_attributes
)
3414 cached_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
3416 self
._query
_check
_bridge
_attributes
(ifaceobj
, ifaceobjcurr
, bridge_config
, cached_ifla_info_data
)
3417 self
._query
_check
_brport
_attributes
_on
_bridge
(ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
)
3418 self
._query
_check
_bridge
_vidinfo
(ifname
, ifaceobj
, ifaceobjcurr
)
3419 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
3420 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifname
, ifaceobj
, ifaceobjcurr
)
3422 def _query_check_bridge_always_up(self
, ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
):
3423 bridge_always_up
= ifaceobj
.get_attr_value_first("bridge-always-up")
3425 if bridge_always_up
:
3426 bridge_config
.remove("bridge-always-up")
3428 if utils
.get_boolean_from_string(bridge_always_up
):
3430 link_exists
= self
.cache
.link_exists(self
.get_dummy_brport_name_for_bridge(ifname
))
3434 ifaceobjcurr
.update_config_with_status(
3436 "yes" if link_exists
else "no",
3440 def _query_check_bridge_attributes(self
, ifaceobj
, ifaceobjcurr
, bridge_config
, cached_ifla_info_data
):
3441 for attr
in list(bridge_config
):
3442 query_check_handler
, netlink_attr
= self
._bridge
_attribute
_query
_check
_handler
.get(attr
, (None, None))
3444 if callable(query_check_handler
):
3445 query_check_handler(attr
, ifaceobj
.get_attr_value_first(attr
), ifaceobjcurr
, cached_ifla_info_data
.get(netlink_attr
))
3446 bridge_config
.remove(attr
)
3448 self
._query
_check
_bridge
_always
_up
(ifaceobj
.name
, ifaceobj
, ifaceobjcurr
, bridge_config
)
3450 def _query_check_brport_attributes_on_bridge(self
, ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
):
3451 brports_info_slave_data
= {}
3452 # bridge_config should only have bridge-port-list attributes
3453 for attr
in bridge_config
:
3454 attr_nl
= self
._ifla
_brport
_attributes
_map
.get(attr
)
3455 brport_query_check_handler
= self
._brport
_attribute
_query
_check
_handler
.get(attr
)
3457 if not attr_nl
or not brport_query_check_handler
:
3458 self
.logger
.warning("%s: query-check: missing handler for attribute: %s (%s)" % (ifname
, attr
, attr_nl
))
3464 for port_config
in self
.parse_port_list(ifname
, ifaceobj
.get_attr_value_first(attr
)) or []:
3465 port
, config
= port_config
.split("=")
3467 if not port
in brports_info_slave_data
:
3468 info_slave_data
= brports_info_slave_data
[port
] = self
.cache
.get_link_info_slave_data(port
)
3470 info_slave_data
= brports_info_slave_data
[port
]
3472 port_config
, port_status
= brport_query_check_handler(port
, config
, info_slave_data
.get(attr_nl
))
3474 running_config
.append(port_config
)
3479 ifaceobjcurr
.update_config_with_status(
3481 " ".join(running_config
),
3486 def _query_check_br_attr_wait(attr
, wait_value
, ifaceobjcurr
, __
):
3487 ifaceobjcurr
.update_config_with_status(attr
, wait_value
, 0)
3489 def _query_check_br_attr_stp(self
, attr
, stp_value
, ifaceobjcurr
, cached_value
):
3491 if ifupdownflags
.flags
.WITHDEFAULTS
:
3492 stp_value
= "on" if self
.default_stp_on
else "off"
3496 user_config_to_nl
= utils
.get_boolean_from_string(stp_value
)
3498 ifaceobjcurr
.update_config_with_status(
3500 "yes" if cached_value
else "no",
3501 user_config_to_nl
!= bool(cached_value
)
3505 def _query_check_br_attr_int(attr
, user_config
, ifaceobjcurr
, cached_value
):
3506 ifaceobjcurr
.update_config_with_status(
3509 int(user_config
) != cached_value
3513 def _query_check_br_attr_int_divided100(attr
, user_config
, ifaceobjcurr
, cached_value
):
3514 value
= cached_value
// 100
3515 ifaceobjcurr
.update_config_with_status(
3518 int(user_config
) != value
3522 def _query_check_br_attr_boolean(attr
, user_config
, ifaceobjcurr
, cached_value
):
3523 ifaceobjcurr
.update_config_with_status(
3525 "yes" if cached_value
else "no",
3526 utils
.get_boolean_from_string(user_config
) != cached_value
3530 def _query_check_br_attr_boolean_on_off(attr
, user_config
, ifaceobjcurr
, cached_value
):
3531 ifaceobjcurr
.update_config_with_status(
3533 "on" if cached_value
else "off",
3534 utils
.get_boolean_from_string(user_config
) != cached_value
3538 def _query_check_br_attr_string(attr
, user_config
, ifaceobjcurr
, cached_value
):
3539 ifaceobjcurr
.update_config_with_status(
3542 user_config
.lower() != cached_value
3546 def _query_check_brport_attr_boolean_on_off(port
, user_config
, cached_value
):
3547 return "%s=%s" % (port
, "on" if cached_value
else "off"), utils
.get_boolean_from_string(user_config
) != cached_value
3550 def _query_check_brport_attr_boolean_yes_no(port
, user_config
, cached_value
):
3551 return "%s=%s" % (port
, "yes" if cached_value
else "no"), utils
.get_boolean_from_string(user_config
) != cached_value
3554 def _query_check_brport_attr_int(port
, user_config
, cached_value
):
3555 return "%s=%s" % (port
, cached_value
), int(user_config
) != cached_value
3558 def _query_check_brport_attr_portmcrouter(cls
, port
, user_config
, cached_value
):
3560 "%s=%s" % (port
, cls
._ifla
_brport
_multicast
_router
_dict
_int
_to
_str
.get(cached_value
)),
3561 cls
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(user_config
) != cached_value
3564 ####################################################################################################################
3566 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
3568 # if bridge-always-up is set we need to remove the dummy brport from the running_port_list
3569 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-always-up")):
3571 running_port_list
.remove(self
.get_dummy_brport_name_for_bridge(ifaceobj
.name
))
3575 bridge_all_ports
= []
3576 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
3577 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
3579 if not running_port_list
and not bridge_all_ports
:
3583 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
3584 # we want to display the same bridge-ports list as provided
3585 # in the interfaces file but if this list contains regexes or
3586 # globs, for now, we won't try to change it.
3587 if 'regex' in port_list
or 'glob' in port_list
:
3588 port_list
= running_port_list
3591 for i
in range(0, len(port_list
)):
3592 if port_list
[i
] in running_port_list
:
3593 ordered
.append(port_list
[i
])
3596 port_list
= running_port_list
3598 difference
= set(running_port_list
).symmetric_difference(bridge_all_ports
)
3599 bridge_port_condone_regex
= self
._get
_bridge
_port
_condone
_regex
(ifaceobj
)
3601 if bridge_port_condone_regex
:
3602 # Drop any condoned port from the difference set
3603 condone_ports
= [port
for port
in difference
if bridge_port_condone_regex
.match(port
)]
3605 for port
in condone_ports
:
3607 difference
.remove(port
)
3611 # Tag all condoned ports in brackets in output
3612 if port
not in bridge_all_ports
:
3613 port_list
.append("(%s)" % port
)
3615 ifaceobjcurr
.update_config_with_status(
3617 " ".join(port_list
) if port_list
else "",
3618 0 if not difference
else 1
3621 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
3622 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
3624 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
3627 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
3628 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
3630 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
3631 ifaceobjs
= ifaceobj_getfunc(bridgename
)
3632 for ifaceobj
in ifaceobjs
:
3633 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
3634 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
3637 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
3638 ifaceobjs
= ifaceobj_getfunc(bridgename
)
3640 for ifaceobj
in ifaceobjs
:
3641 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
3646 def _query_check_bridge_port_vidinfo(self
, ifname
, bridge_name
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
):
3647 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(ifname
)
3649 if (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
3655 brport_vid_access_user_config
= ifaceobj
.get_attr_value_first("bridge-access")
3657 if brport_vid_access_user_config
:
3659 vid_int
= int(brport_vid_access_user_config
)
3660 except ValueError as e
:
3661 ifaceobjcurr
.update_config_with_status("bridge-access", brport_vid_access_user_config
, 1)
3662 raise Exception("%s: bridge-access invalid value: %s" % (ifname
, str(e
)))
3664 ifaceobjcurr
.update_config_with_status(
3667 running_pvid
!= vid_int
or running_vids
[0] != vid_int
3674 brport_pvid_user_config
= ifaceobj
.get_attr_value_first("bridge-pvid")
3676 if brport_pvid_user_config
:
3678 pvid
= int(brport_pvid_user_config
)
3679 except ValueError as e
:
3680 ifaceobjcurr
.update_config_with_status("bridge-pvid", brport_pvid_user_config
, 1)
3681 raise Exception("%s: bridge-pvid invalid value: %s" % (ifname
, str(e
)))
3683 ifaceobjcurr
.update_config_with_status(
3686 running_pvid
!= pvid
3688 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
3689 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
3690 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
3691 # if the interface has multiple iface sections,
3692 # we check the below only for the oldest sibling
3693 # or the last iface section
3695 pvid
= int(self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
))
3696 except (TypeError, ValueError):
3699 if not running_pvid
or running_pvid
!= pvid
:
3700 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3701 ifaceobjcurr
.status_str
= 'bridge pvid error'
3702 elif not running_pvid
or running_pvid
!= 1:
3703 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3704 ifaceobjcurr
.status_str
= 'bridge pvid error'
3706 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
3708 vids
= re
.split(r
'[\s\t]\s*', vids
)
3710 # Special treatment to make sure that the vlans mapped with vnis
3711 # (in single-vxlan context) are not mistaken for regular vlans.
3712 # We need to proactively remove them from the "running_vids"
3713 vlans_mapped_with_vnis
= self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(ifaceobj
)
3714 new_running_vids
= []
3715 user_config_vids
= utils
.ranges_to_ints(vids
)
3716 for v
in running_vids
:
3717 if v
in user_config_vids
:
3718 new_running_vids
.append(v
)
3719 elif v
not in vlans_mapped_with_vnis
:
3720 new_running_vids
.append(v
)
3721 running_vids
= new_running_vids
3722 #####################################################################
3724 if not running_vids
or not utils
.compare_ids(vids
, running_vids
, running_pvid
, expand_range
=False):
3725 running_vids
= [str(o
) for o
in running_vids
]
3726 ifaceobjcurr
.update_config_with_status(attr_name
,
3727 ' '.join(running_vids
), 1)
3729 ifaceobjcurr
.update_config_with_status(attr_name
,
3731 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
3732 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
3733 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
3734 # if the interface has multiple iface sections,
3735 # we check the below only for the oldest sibling
3736 # or the last iface section
3738 # check if it matches the bridge vids
3739 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
3740 if (bridge_vids
and (not running_vids
or
3741 not utils
.compare_ids(bridge_vids
, running_vids
, running_pvid
, expand_range
=False))):
3742 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3743 ifaceobjcurr
.status_str
= 'bridge vid error'
3745 _query_check_brport_attributes
= (
3752 "bridge-portmcrouter",
3755 "bridge-unicast-flood",
3756 "bridge-multicast-flood",
3757 "bridge-broadcast-flood",
3758 "bridge-arp-nd-suppress",
3759 "bridge-l2protocol-tunnel"
3762 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
3765 ifname
= ifaceobj
.name
3767 if not self
.cache
.link_is_bridge_port(ifname
):
3768 # Mark all bridge brport attributes as failed
3769 ifaceobjcurr
.check_n_update_config_with_status_many(
3770 ifaceobj
, self
._query
_check
_brport
_attributes
, 1
3774 bridge_name
= self
.cache
.get_bridge_name_from_port(ifname
)
3776 self
.logger
.warning("%s: unable to determine bridge name" % ifname
)
3779 if self
.cache
.bridge_is_vlan_aware(bridge_name
):
3780 self
._query
_check
_bridge
_port
_vidinfo
(ifname
, bridge_name
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
3782 brport_info_slave_data
= self
.cache
.get_link_info_slave_data(ifname
)
3787 portmcfl
= ifaceobj
.get_attr_value_first("bridge-portmcfl")
3790 cached_value
= brport_info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
)
3792 ifaceobjcurr
.update_config_with_status(
3794 "yes" if cached_value
else "no",
3795 utils
.get_boolean_from_string(portmcfl
) != cached_value
3799 # bridge-portmcrouter
3801 portmcrouter
= ifaceobj
.get_attr_value_first("bridge-portmcrouter")
3804 cached_value
= brport_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
)
3806 ifaceobjcurr
.update_config_with_status(
3807 "bridge-portmcrouter",
3808 self
._ifla
_brport
_multicast
_router
_dict
_int
_to
_str
.get(cached_value
),
3809 self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(portmcrouter
) != cached_value
3814 # bridge-unicast-flood
3815 # bridge-multicast-flood
3816 # bridge-broadcast-flood
3817 # bridge-arp-nd-suppress
3819 for attr_name
, attr_nl
in (
3820 ("bridge-learning", Link
.IFLA_BRPORT_LEARNING
),
3821 ("bridge-unicast-flood", Link
.IFLA_BRPORT_UNICAST_FLOOD
),
3822 ("bridge-multicast-flood", Link
.IFLA_BRPORT_MCAST_FLOOD
),
3823 ("bridge-broadcast-flood", Link
.IFLA_BRPORT_BCAST_FLOOD
),
3824 ("bridge-arp-nd-suppress", Link
.IFLA_BRPORT_NEIGH_SUPPRESS
),
3826 attribute_value
= ifaceobj
.get_attr_value_first(attr_name
)
3828 if not attribute_value
:
3831 cached_value
= brport_info_slave_data
.get(attr_nl
)
3833 ifaceobjcurr
.update_config_with_status(
3835 "on" if cached_value
else "off",
3836 utils
.get_boolean_from_string(attribute_value
) != cached_value
3843 for attr_name
, attr_nl
in (
3844 ("bridge-pathcosts", Link
.IFLA_BRPORT_COST
),
3845 ("bridge-portprios", Link
.IFLA_BRPORT_PRIORITY
),
3847 attribute_value
= ifaceobj
.get_attr_value_first(attr_name
)
3849 if not attribute_value
:
3852 cached_value
= brport_info_slave_data
.get(attr_nl
)
3855 ifaceobjcurr
.update_config_with_status(
3858 int(attribute_value
) != cached_value
3860 except ValueError as e
:
3861 ifaceobjcurr
.update_config_with_status(attr_name
, str(cached_value
), 1)
3862 raise Exception("%s: %s invalid value: %s" % (ifname
, attr_name
, str(e
)))
3864 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
3867 # bridge-vlan-vni-map
3869 cached_vlans
, cached_vnis
= self
.get_vlan_vni_ranges(self
.cache
.get_vlan_vni(ifaceobj
.name
))
3871 for bridge_vlan_vni_map_entry
in ifaceobj
.get_attr_value("bridge-vlan-vni-map") or []:
3874 for vlan_vni
in bridge_vlan_vni_map_entry
.split():
3876 vlans_str
, vni_str
= utils
.get_vlan_vni_in_map_entry(vlan_vni
)
3879 self
.__warn
_bridge
_vlan
_vni
_map
_syntax
_error
(ifname
, vlan_vni
)
3883 # if we already have detected an error on this entry there's
3884 # no point doing anything else than syntax check on the rest
3887 vlans_list
= utils
.ranges_to_ints([vlans_str
])
3888 vnis_list
= utils
.ranges_to_ints([vni_str
])
3891 for i
, vlan
in enumerate(vlans_list
):
3892 index
= cached_vnis
.index(vlan
)
3894 if vlan
!= cached_vnis
[index
] or vnis_list
[i
] != cached_vlans
[index
]:
3899 ifaceobjcurr
.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map_entry
, fail
)
3902 def get_vlan_vni_ranges(bridge_vlan_tunnel
, compress
=False):
3906 if not bridge_vlan_tunnel
:
3909 tunnel_vlan_range
= None
3910 tunnel_vni_range
= None
3912 for tunnel_vlan
, tunnel_vni
, tunnel_flags
in bridge_vlan_tunnel
:
3914 if tunnel_flags
& Link
.BRIDGE_VLAN_INFO_RANGE_BEGIN
:
3915 tunnel_vlan_range
= tunnel_vlan
3916 tunnel_vni_range
= tunnel_vni
3918 elif tunnel_flags
& Link
.BRIDGE_VLAN_INFO_RANGE_END
:
3921 vlans
.append("%s-%s" % (tunnel_vlan_range
, tunnel_vlan
))
3922 vnis
.append("%s-%s" % (tunnel_vni_range
, tunnel_vni
))
3924 vlans
.extend(range(tunnel_vlan_range
, tunnel_vlan
+ 1))
3925 vnis
.extend(range(tunnel_vni_range
, tunnel_vni
+ 1))
3928 vlans
.append(tunnel_vlan
)
3929 vnis
.append(tunnel_vni
)
3933 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
3934 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
3936 if user_config_l2protocol_tunnel
:
3939 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
3940 except Exception as e
:
3941 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
3943 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
3945 def _query_check_l2protocol_tunnel_on_bridge(self
, ifname
, ifaceobj
, ifaceobjcurr
):
3947 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
3948 We need to make sure that all ports comply with the mask given under the bridge
3950 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
3952 if user_config_l2protocol_tunnel
:
3953 if '=' in user_config_l2protocol_tunnel
:
3955 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
3956 brport_list
= list(config_per_port_dict
.keys())
3958 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
3961 config_per_port_dict
= {}
3962 brport_list
= self
.cache
.get_slaves(ifname
)
3965 for brport_name
in brport_list
:
3966 self
._query
_check
_l2protocol
_tunnel
(
3968 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
3971 except Exception as e
:
3972 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
3974 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
3976 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
3977 cached_ifla_brport_group_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
3978 cached_ifla_brport_group_mask
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASK
)
3980 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
3981 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
3983 if callable(callback
):
3984 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3985 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
3986 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
3988 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
3989 cached_ifla_brport_group_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
3990 cached_ifla_brport_group_mask
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASK
)
3991 running_protocols
= []
3992 for protocol_name
, callback
in list(self
.query_check_l2protocol_tunnel_callback
.items()):
3993 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3994 running_protocols
= list(self
.query_check_l2protocol_tunnel_callback
.keys())
3995 running_protocols
.remove('all')
3997 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3998 running_protocols
.append(protocol_name
)
3999 if running_protocols
:
4001 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
4002 elif bridge_ifaceobj
:
4003 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
4006 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
4008 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
4010 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
4011 if self
._is
_bridge
(ifaceobj
):
4012 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
4014 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
4017 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
4018 if self
.cache
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
4019 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
4020 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
4023 bridge_vlan_aware
=True))
4025 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
4026 ifaceobjrunning
, None))
4028 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
4029 if self
.systcl_get_net_bridge_stp_user_space() == '1':
4032 v
= str(self
.cache
.get_brport_cost(ifaceobjrunning
.name
))
4033 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
4034 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
4036 v
= str(self
.cache
.get_brport_priority(ifaceobjrunning
.name
))
4037 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
4038 ifaceobjrunning
.update_config('bridge-portprios', v
)
4040 def _query_running_bridge_port(self
, ifaceobjrunning
,
4041 ifaceobj_getfunc
=None):
4043 bridgename
= self
.cache
.get_bridge_name_from_port(
4044 ifaceobjrunning
.name
)
4048 self
.logger
.warning('%s: unable to find bridgename'
4049 %ifaceobjrunning
.name
)
4052 if not self
.cache
.bridge_is_vlan_aware(bridgename
):
4054 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
4055 except Exception as e
:
4056 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
4059 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
4061 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
4062 ifaceobjrunning
.name
)
4063 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
4064 bridge_port_vids
.remove(bridge_port_pvid
)
4066 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
4067 if bridgeifaceobjlist
:
4068 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
4069 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
4071 if not bridge_port_vids
and bridge_port_pvid
:
4072 # must be an access port
4073 if bridge_port_pvid
!= '1':
4074 ifaceobjrunning
.update_config('bridge-access',
4077 if bridge_port_vids
:
4078 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
4079 ifaceobjrunning
.update_config('bridge-vids',
4080 ' '.join(bridge_port_vids
))
4081 if bridge_port_pvid
and bridge_port_pvid
!= '1':
4082 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
4083 ifaceobjrunning
.update_config('bridge-pvid',
4086 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_learning(ifaceobjrunning
.name
))
4087 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
4088 ifaceobjrunning
.update_config('bridge-learning', v
)
4090 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_unicast_flood(ifaceobjrunning
.name
))
4091 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
4092 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
4094 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_multicast_flood(ifaceobjrunning
.name
))
4095 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
4096 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
4098 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_broadcast_flood(ifaceobjrunning
.name
))
4099 if v
and v
!= self
.get_mod_subattr('bridge-broadcast-flood', 'default'):
4100 ifaceobjrunning
.update_config('bridge-broadcast-flood', v
)
4102 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_neigh_suppress(ifaceobjrunning
.name
))
4103 # Display running 'arp-nd-suppress' only on vxlan ports
4104 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
4105 # otherwise, display on all bridge-ports
4107 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
4109 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
4110 (not self
.arp_nd_suppress_only_on_vxlan
or
4111 (self
.arp_nd_suppress_only_on_vxlan
and
4112 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
4113 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
4115 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
4118 # bridge-vlan-vni-map
4121 # there's a mix-up vlan_vni should return vlans/vnis and not vnis/vlans
4122 # ifquery-check is also using this function and has already code to work
4123 # around the issue, so to fix our ordering problem we will simply and
4124 # temporarily, swap the two return values
4125 cached_vnis
, cached_vlans
= self
.get_vlan_vni_ranges(
4126 self
.cache
.get_vlan_vni(ifaceobjrunning
.name
), compress
=True
4129 if cached_vlans
and cached_vnis
:
4130 ifaceobjrunning
.update_config(
4131 "bridge-vlan-vni-map",
4132 " ".join(["%s=%s" % (vlan
, vni
) for vlan
, vni
in zip(cached_vlans
, cached_vnis
)])
4134 except Exception as e
:
4135 self
.logger
.debug("bridge-vlan-vni-map: exception: %s" % str(e
))
4137 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
4139 if self
.cache
.bridge_exists(ifaceobjrunning
.name
):
4140 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
4141 elif self
.cache
.link_is_bridge_port(ifaceobjrunning
.name
):
4142 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
4143 except Exception as e
:
4144 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
4146 def _query(self
, ifaceobj
, **kwargs
):
4147 """ add default policy attributes supported by the module """
4149 if self
.bridge_vxlan_arp_nd_suppress \
4150 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT \
4151 and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
4152 ifaceobj
.update_config("bridge-arp-nd-suppress", "on")
4154 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
4155 ifaceobj
.get_attr_value_first('bridge-stp')):
4157 if self
.default_stp_on
:
4158 ifaceobj
.update_config('bridge-stp', 'yes')
4164 'query-checkcurr': _query_check
,
4165 'query-running': _query_running
,
4170 """ returns list of ops supported by this module """
4171 return list(self
._run
_ops
.keys())
4173 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
4174 """ run bridge configuration on the interface object passed as
4175 argument. Can create bridge interfaces if they dont exist already
4178 **ifaceobj** (object): iface object
4180 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
4184 **query_ifaceobj** (object): query check ifaceobject. This is only
4185 valid when op is 'query-checkcurr'. It is an object same as
4186 ifaceobj, but contains running attribute values and its config
4187 status. The modules can use it to return queried running state
4188 of interfaces. status is success if the running state is same
4189 as user required state in ifaceobj. error otherwise.
4191 op_handler
= self
._run
_ops
.get(operation
)
4195 if (not self
.requirements
.bridge_utils_is_installed
4196 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
4197 and self
.bridge_utils_missing_warning
):
4198 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
4199 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
4200 self
.bridge_utils_missing_warning
= False
4202 # make sure BRIDGE_VXLAN is set if we have a vxlan port
4203 self
._re
_evaluate
_bridge
_vxlan
(ifaceobj
, ifaceobj_getfunc
)
4205 if operation
== 'query-checkcurr':
4206 op_handler(self
, ifaceobj
, query_ifaceobj
,
4207 ifaceobj_getfunc
=ifaceobj_getfunc
)
4209 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)