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()
811 def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
812 if not ifla_brport_group_maskhi
:
813 ifla_brport_group_maskhi
= 0x1
815 ifla_brport_group_maskhi |
= 0x1
816 return ifla_brport_group_mask
, ifla_brport_group_maskhi
819 def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
820 if not ifla_brport_group_maskhi
:
821 ifla_brport_group_maskhi
= 0x2
823 ifla_brport_group_maskhi |
= 0x2
824 return ifla_brport_group_mask
, ifla_brport_group_maskhi
827 def _l2protocol_tunnel_set_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
828 if not ifla_brport_group_mask
:
829 ifla_brport_group_mask
= 0x1
831 ifla_brport_group_mask |
= 0x1
832 return ifla_brport_group_mask
, ifla_brport_group_maskhi
835 def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
836 if not ifla_brport_group_mask
:
837 ifla_brport_group_mask
= 0x4
839 ifla_brport_group_mask |
= 0x4
840 return ifla_brport_group_mask
, ifla_brport_group_maskhi
843 def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
844 if not ifla_brport_group_mask
:
845 ifla_brport_group_mask
= 0x4000
847 ifla_brport_group_mask |
= 0x4000
848 return ifla_brport_group_mask
, ifla_brport_group_maskhi
851 def _l2protocol_tunnel_set_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
852 # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
853 return 0x1 |
0x4 |
0x4000, 0x1 |
0x2
856 def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
857 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x1
860 def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
861 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x2
864 def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
865 return ifla_brport_group_maskhi
and ifla_brport_group_maskhi
& 0x1
868 def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
869 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4000
872 def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
873 return ifla_brport_group_mask
and ifla_brport_group_mask
& 0x4
876 def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask
, ifla_brport_group_maskhi
):
877 return ifla_brport_group_mask
== (0x1 |
0x4 |
0x4000) and ifla_brport_group_maskhi
== (0x1 |
0x2)
879 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
880 retval
= self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
)
881 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
882 if not self
.check_bridge_port_vid_attrs(ifaceobj
):
884 c1
= self
.syntax_check_vxlan_in_vlan_aware_br(ifaceobj
, ifaceobj_getfunc
)
885 c2
= self
.syntax_check_bridge_allow_multiple_vlans(ifaceobj
, ifaceobj_getfunc
)
886 c3
= self
.syntax_check_learning_l2_vni_evpn(ifaceobj
)
887 c4
= self
.syntax_check_bridge_arp_vni_vlan(ifaceobj
, ifaceobj_getfunc
)
888 return retval
and c1
and c3
and c4
#and c2
890 def syntax_check_bridge_arp_vni_vlan(self
, ifaceobj
, ifaceobj_getfunc
):
892 Detect and warn when arp suppression is enabled and there is no vlan configured
895 :param ifaceobj_getfunc:
898 if ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN \
899 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT \
900 and utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-arp-nd-suppress")) \
901 and not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
903 bridge_access
= ifaceobj
.get_attr_value_first("bridge-access")
905 if not bridge_access
:
908 for obj
in ifaceobj_getfunc(ifaceobj
.upperifaces
[0]) or []:
909 for upper_ifname
in obj
.upperifaces
or []:
910 for upper_obj
in ifaceobj_getfunc(upper_ifname
) or []:
911 if upper_obj
.link_kind
& ifaceLinkKind
.VLAN
:
912 if str(self
._get
_vlan
_id
(upper_obj
)) == bridge_access
:
916 "%s: ARP suppression configured on %s and associated vlan %s not configured. "
917 "This may result in unexpected behavior"
918 % (ifaceobj
.name
, ifaceobj
.name
, bridge_access
)
924 def syntax_check_learning_l2_vni_evpn(self
, ifaceobj
):
926 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
927 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-learning")):
929 "%s: possible mis-configuration detected: l2-vni configured with bridge-learning ON "
930 "while EVPN is also configured - these two parameters conflict with each other."
936 def syntax_check_bridge_allow_multiple_vlans(self
, ifaceobj
, ifaceobj_getfunc
):
938 if not self
.bridge_allow_multiple_vlans
and ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
and ifaceobj
.lowerifaces
:
940 for brport_name
in ifaceobj
.lowerifaces
:
941 for obj
in ifaceobj_getfunc(brport_name
) or []:
942 if obj
.link_kind
& ifaceLinkKind
.VLAN
:
943 sub_intf_vlan_id
= self
._get
_vlan
_id
(obj
)
944 if vlan_id
and vlan_id
!= sub_intf_vlan_id
:
945 self
.logger
.error('%s: ignore %s: multiple vlans not allowed under bridge '
946 '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
947 % (ifaceobj
.name
, brport_name
))
950 vlan_id
= sub_intf_vlan_id
953 def check_bridge_port_vid_attrs(self
, ifaceobj
):
954 if (ifaceobj
.get_attr_value('bridge-access') and
955 (self
.get_ifaceobj_bridge_vids_value(ifaceobj
) or
956 ifaceobj
.get_attr_value('bridge-pvid'))):
957 self
.logger
.warning('%s: bridge-access given, bridge-vids and bridge-pvid '
958 'will be ignored' % ifaceobj
.name
)
962 def check_bridge_vlan_aware_port(self
, ifaceobj
, ifaceobj_getfunc
):
963 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
964 ports
= self
._get
_bridge
_port
_list
(ifaceobj
)
968 for port_name
in ports
:
969 port_obj_l
= ifaceobj_getfunc(port_name
)
970 if not self
.allow_vlan_sub_interface_in_vlan_aware_bridge
:
971 if port_obj_l
and port_obj_l
[0].link_kind
& ifaceLinkKind
.VLAN
:
972 self
.logger
.error('%s: %s: vlan sub-interface is not '
973 'supported in a vlan-aware bridge'
974 % (ifaceobj
.name
, port_name
))
977 port_obj_l
[0].get_attr_value('bridge-arp-nd-suppress') and
978 self
.arp_nd_suppress_only_on_vxlan
and
979 not port_obj_l
[0].link_kind
& ifaceLinkKind
.VXLAN
):
980 self
.log_error('\'bridge-arp-nd-suppress\' is not '
981 'supported on a non-vxlan port %s'
987 def _error_vxlan_in_vlan_aware_br(self
, ifaceobj
, bridgename
):
988 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
989 self
.log_error('`bridge-access` attribute is mandatory when vxlan '
990 'device (%s) is part of vlan aware bridge (%s)'
991 % (ifaceobj
.name
, bridgename
), ifaceobj
)
995 def syntax_check_vxlan_in_vlan_aware_br(self
, ifaceobj
, ifaceobj_getfunc
):
996 if not ifaceobj_getfunc
:
998 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
999 if ifaceobj
.get_attr_value('bridge-access'):
1001 for iface
in ifaceobj
.upperifaces
if ifaceobj
.upperifaces
else []:
1002 ifaceobj_upper_list
= ifaceobj_getfunc(iface
)
1003 if not ifaceobj_upper_list
:
1005 ifaceobj_upper
= ifaceobj_upper_list
[0]
1006 bridge_vids
= self
._get
_bridge
_vids
(iface
, ifaceobj_getfunc
)
1007 if ifaceobj_upper
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1008 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1009 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1012 or not utils
.compare_ids(bridge_vids
,
1015 if not self
._error
_vxlan
_in
_vlan
_aware
_br
(ifaceobj
, ifaceobj_upper
.name
):
1020 def _is_bridge(ifaceobj
):
1021 return (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
or
1022 ifaceobj
.get_attr_value_first('bridge-ports') or
1023 ifaceobj
.get_attr_value_first('bridge-vlan-aware'))
1025 def check_valid_bridge(self
, ifaceobj
, ifname
):
1026 if self
.cache
.link_exists(ifname
) and not self
.cache
.link_is_bridge(ifname
):
1027 self
.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname
, ifaceobj
=ifaceobj
)
1031 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None, old_ifaceobjs
=False):
1033 if not old_ifaceobjs
and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
or ifaceobj
.get_attr_value_first("bridge-vlan-vni-map")):
1034 self
.svd_list
.add(ifaceobj
.name
)
1036 if not self
._is
_bridge
(ifaceobj
) or not self
.check_valid_bridge(ifaceobj
, ifaceobj
.name
):
1038 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
1039 ifaceobj
.link_type
= ifaceLinkType
.LINK_MASTER
1040 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
1041 # for special vlan aware bridges, we need to add another bit
1042 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first('bridge-vlan-aware')):
1043 ifaceobj
.link_kind |
= ifaceLinkKind
.BRIDGE
1044 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
1046 if not old_ifaceobjs
:
1047 # store the name of all bridge vlan aware in a global list
1048 self
.bridge_vlan_aware_list
.add(ifaceobj
.name
)
1050 ifaceobj
.role |
= ifaceRole
.MASTER
1051 ifaceobj
.dependency_type
= ifaceDependencyType
.MASTER_SLAVE
1053 return self
.parse_port_list(ifaceobj
.name
,
1054 self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
),
1057 def get_dependent_ifacenames_running(self
, ifaceobj
):
1058 if not self
.cache
.bridge_exists(ifaceobj
.name
):
1060 return self
.cache
.get_slaves(ifaceobj
.name
)
1062 def _get_bridge_port_list(self
, ifaceobj
):
1064 # port list is also available in the previously
1065 # parsed dependent list. Use that if available, instead
1066 # of parsing port expr again
1067 port_list
= ifaceobj
.lowerifaces
1070 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
1072 return self
.parse_port_list(ifaceobj
.name
, ports
)
1076 def _get_bridge_port_list_user_ordered(self
, ifaceobj
):
1077 # When enslaving bridge-ports we need to return the exact user
1078 # configured bridge ports list (bridge will inherit the mac of the
1080 ports
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
)
1081 return self
.parse_port_list(ifaceobj
.name
, ports
) if ports
else None
1083 def _get_bridge_port_condone_regex(self
, ifaceobj
, get_string
= False):
1084 bridge_port_condone_regex
= ifaceobj
.get_attr_value_first('bridge-ports-condone-regex')
1085 # If bridge-ports-ignore-regex is configured, do NOT use the parse_port_list()
1086 # function to gather a list of ports matching the regex here and now but set
1087 # up a compiled regex to be used in a match later. This way we try to avoid
1088 # a race condition where an (possibly VM) interface is created after this
1089 # function has been called but before the bridgeports are validated.
1090 if bridge_port_condone_regex
:
1092 return bridge_port_condone_regex
1093 return re
.compile (r
"%s" % bridge_port_condone_regex
)
1096 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
1097 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
1098 if not waitport_value
: return
1100 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
1101 if not waitportvals
: return
1103 waitporttime
= int(waitportvals
[0])
1105 self
.log_warn('%s: invalid waitport value \'%s\''
1106 %(ifaceobj
.name
, waitportvals
[0]))
1108 if waitporttime
<= 0: return
1110 waitportlist
= self
.parse_port_list(ifaceobj
.name
,
1112 except IndexError as e
:
1113 # ignore error and use all bridge ports
1114 waitportlist
= portlist
1116 if not waitportlist
: return
1117 self
.logger
.info('%s: waiting for ports %s to exist ...'
1118 %(ifaceobj
.name
, str(waitportlist
)))
1119 starttime
= time
.time()
1120 while ((time
.time() - starttime
) < waitporttime
):
1121 if all([False for p
in waitportlist
1122 if not self
.cache
.link_exists(p
)]):
1125 except Exception as e
:
1126 self
.log_warn('%s: unable to process waitport: %s'
1127 %(ifaceobj
.name
, str(e
)))
1129 def _enable_disable_ipv6(self
, port
, enable
='1'):
1131 self
.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port
, enable
)
1132 except Exception as e
:
1133 self
.logger
.info(str(e
))
1135 def handle_ipv6(self
, ports
, state
):
1137 self
._enable
_disable
_ipv
6(p
, state
)
1139 def _pretty_print_add_ports_error(self
, errstr
, bridgeifaceobj
, bridgeports
):
1140 """ pretty print bridge port add errors.
1141 since the commands are batched and the kernel only returns error
1142 codes, this function tries to interpret some error codes
1143 and prints clearer errors """
1145 if re
.search('RTNETLINK answers: Invalid argument', errstr
):
1146 # Cumulus Linux specific error checks
1148 if self
.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
1150 for bport
in bridgeports
:
1151 currvlanid
= self
._get
_vlan
_id
_from
_ifacename
(bport
)
1153 if currvlanid
!= vlanid
:
1154 self
.log_error('%s: ' %bridgeifaceobj
.name
+
1155 'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj
)
1159 except Exception as e
:
1160 errstr
+= '\n%s' % str(e
)
1161 self
.log_error(bridgeifaceobj
.name
+ ': ' + errstr
, bridgeifaceobj
)
1163 def _add_ports(self
, ifaceobj
, ifaceobj_getfunc
):
1164 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1165 bridgeportscondoneregex
= self
._get
_bridge
_port
_condone
_regex
(ifaceobj
)
1166 runningbridgeports
= []
1168 # bridge-always-up #####################################################
1169 bridge_always_up
= ifaceobj
.get_attr_value_first("bridge-always-up")
1172 if utils
.get_boolean_from_string(bridge_always_up
):
1173 # the dummy port will be added to the bridgeports list so the
1174 # following code don't de-enslave the dummy device.
1175 dummy_brport
= self
.bridge_always_up(ifaceobj
.name
, bridgeports
)
1177 ########################################################################
1179 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
1180 # Delete active ports not in the new port list
1181 if not ifupdownflags
.flags
.PERFMODE
:
1182 runningbridgeports
= self
.cache
.get_slaves(ifaceobj
.name
)
1183 if runningbridgeports
:
1184 for bport
in runningbridgeports
:
1185 if not bridgeports
or bport
not in bridgeports
:
1186 if bridgeportscondoneregex
and bridgeportscondoneregex
.match(bport
):
1187 self
.logger
.info("%s: port %s will stay enslaved as it matches with bridge-ports-condone-regex" % (ifaceobj
.name
, bport
))
1189 self
.netlink
.link_set_nomaster(bport
)
1190 # set admin DOWN on all removed ports
1191 # that don't have config outside bridge
1192 if not ifaceobj_getfunc(bport
):
1193 self
.netlink
.link_down(bport
)
1194 # enable ipv6 for ports that were removed
1195 self
.handle_ipv6([bport
], '0')
1197 runningbridgeports
= []
1201 newbridgeports
= set(bridgeports
).difference(set(runningbridgeports
))
1202 newly_enslaved_ports
= []
1204 newbridgeports_ordered
= []
1205 for br_port
in self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
):
1206 if br_port
in newbridgeports
:
1207 newbridgeports_ordered
.append(br_port
)
1210 # add the dummy port to the list of interface to enslave
1211 # link_set_master should make sure that the device is not
1213 newbridgeports_ordered
.append(dummy_brport
)
1215 self
.iproute2
.batch_start()
1217 for bridgeport
in newbridgeports_ordered
:
1219 if (not ifupdownflags
.flags
.DRYRUN
and
1220 not self
.cache
.link_exists(bridgeport
)):
1221 self
.log_error('%s: bridge port %s does not exist'
1222 %(ifaceobj
.name
, bridgeport
), ifaceobj
)
1225 hwaddress
= self
.cache
.get_link_address(bridgeport
)
1226 if not ifupdownflags
.flags
.DRYRUN
and not self
._valid
_ethaddr
(hwaddress
):
1227 self
.log_warn('%s: skipping port %s, ' %(ifaceobj
.name
,
1228 bridgeport
) + 'invalid ether addr %s'
1231 self
.iproute2
.link_set_master(bridgeport
, ifaceobj
.name
)
1232 newly_enslaved_ports
.append(bridgeport
)
1234 # dont disable ipv6 for SVD
1235 if bridgeport
not in self
.svd_list
:
1236 self
.handle_ipv6([bridgeport
], '1')
1238 self
.iproute2
.addr_flush(bridgeport
)
1239 except Exception as e
:
1240 self
.logger
.error(str(e
))
1243 self
.iproute2
.batch_commit()
1244 self
.cache
.force_add_slave_list(ifaceobj
.name
, newly_enslaved_ports
)
1247 self
.log_error('bridge configuration failed (missing ports)')
1250 # to avoid any side effect we remove the dummy brport from the
1251 # list of supposedly newly configured ports.
1252 newly_enslaved_ports
.remove(dummy_brport
)
1256 return newly_enslaved_ports
1258 def get_dummy_brport_name_for_bridge(self
, bridge_name
):
1260 dummy brport will have user provided name if it's defined in 'bridge_always_up_dummy_brport' policy
1261 Otherwise dummy brport will have pre-formated name: brport-if$BRIDGE_IFINDEX
1262 That way we can avoid collision with existing interfaces
1264 if self
.bridge_always_up_dummy_brport
:
1265 return self
.bridge_always_up_dummy_brport
1266 # this can raise: NetlinkCacheIfnameNotFoundError
1267 return "brport-if%d" % self
.cache
.get_ifindex(bridge_name
)
1269 def bridge_always_up(self
, bridge_name
, newbridgeports_ordered
):
1270 dummy_brport
= self
.get_dummy_brport_name_for_bridge(bridge_name
)
1272 if not self
.cache
.link_exists(dummy_brport
):
1273 self
.logger
.info("%s: bridge-always-up yes: enslaving dummy port: %s" % (bridge_name
, dummy_brport
))
1274 self
.netlink
.link_add(ifname
=dummy_brport
, kind
="dummy")
1275 self
.netlink
.link_up_force(dummy_brport
)
1277 newbridgeports_ordered
.append(dummy_brport
)
1280 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
1281 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
1282 if not maxwait
: return
1284 maxwait
= int(maxwait
)
1286 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
1289 if not maxwait
: return
1290 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
1293 starttime
= time
.time()
1294 while ((time
.time() - starttime
) < maxwait
):
1295 if all([False for p
in portlist
1296 if self
.read_file_oneline(
1297 '/sys/class/net/%s/brif/%s/state'
1298 %(ifaceobj
.name
, p
)) != '3']):
1301 except Exception as e
:
1302 self
.log_warn('%s: unable to process maxwait: %s'
1303 %(ifaceobj
.name
, str(e
)))
1305 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
1307 # Sets old style igmp querier
1309 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
1311 running_mcqv4src
= {}
1312 if not ifupdownflags
.flags
.PERFMODE
:
1313 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobj
.name
)
1315 srclist
= attrval
.split()
1320 k_to_del
= set(list(running_mcqv4src
.keys())).difference(list(mcqs
.keys()))
1322 self
.iproute2
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1323 for v
in list(mcqs
.keys()):
1324 self
.iproute2
.bridge_set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
1325 elif not ifupdownflags
.flags
.PERFMODE
:
1326 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobj
.name
)
1327 if running_mcqv4src
:
1328 for v
in list(running_mcqv4src
.keys()):
1329 self
.iproute2
.bridge_del_mcqv4src(ifaceobj
.name
, v
)
1331 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
1333 # Supports old style vlan vid info format
1336 bridge_port_pvids
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
1337 bridge_port_vids
= ifaceobj
.get_attr_value_first('bridge-port-vids')
1338 if not bridge_port_pvids
and not bridge_port_vids
:
1341 # Handle bridge vlan attrs
1343 if bridge_port_pvids
:
1344 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_pvids
)
1346 self
.log_warn('%s: could not parse \'%s %s\''
1347 %(ifaceobj
.name
, 'bridge-port-pvids',
1352 (port
, pvid
) = p
.split('=')
1354 running_pvid
= self
.cache
.get_pvid(port
)
1356 if running_pvid
== pvid
:
1359 self
.iproute2
.bridge_vlan_del_pvid(port
, running_pvid
)
1360 self
.iproute2
.bridge_vlan_add_pvid(port
, pvid
)
1361 except Exception as e
:
1362 self
.log_warn('%s: failed to set pvid `%s` (%s)'
1363 %(ifaceobj
.name
, p
, str(e
)))
1366 if bridge_port_vids
:
1367 portlist
= self
.parse_port_list(ifaceobj
.name
, bridge_port_vids
)
1369 self
.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj
.name
,
1370 'bridge-port-vids', bridge_port_vids
))
1374 (port
, val
) = p
.split('=')
1375 vids
= val
.split(',')
1376 vids_int
= utils
.ranges_to_ints(vids
)
1377 _
, running_vids
= self
.cache
.get_pvid_and_vids(port
)
1379 (vids_to_del
, vids_to_add
) = \
1380 utils
.diff_ids(vids_int
, running_vids
)
1382 self
.iproute2
.bridge_vlan_del_vid_list(port
,
1383 utils
.compress_into_ranges(vids_to_del
))
1385 self
.iproute2
.bridge_vlan_add_vid_list(port
,
1386 utils
.compress_into_ranges(vids_to_add
))
1388 self
.iproute2
.bridge_vlan_add_vid_list(port
, vids_int
)
1389 except Exception as e
:
1390 self
.log_warn('%s: failed to set vid `%s` (%s)'
1391 %(ifaceobj
.name
, p
, str(e
)))
1393 def _is_running_stp_state_on(self
, bridgename
):
1394 """ Returns True if running stp state is on, else False """
1396 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
1398 running_stp_state
= self
.read_file_oneline(stp_state_file
)
1399 return running_stp_state
and running_stp_state
!= '0'
1403 def _is_config_stp_state_on(self
, ifaceobj
):
1404 """ Returns true if user specified stp state is on, else False """
1406 stp_attr
= ifaceobj
.get_attr_value_first('bridge-stp')
1408 return self
.default_stp_on
1409 return utils
.get_boolean_from_string(stp_attr
)
1411 def get_bridge_mcsnoop_value(self
, ifaceobj
):
1412 mcsnoop
= ifaceobj
.get_attr_value_first('bridge-mcsnoop')
1417 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
:
1418 if self
._vxlan
_bridge
_default
_igmp
_snooping
is not None:
1419 return self
._vxlan
_bridge
_default
_igmp
_snooping
1421 return self
.get_attr_default_value("bridge-mcsnoop")
1423 def fill_ifla_info_data_with_ifla_br_attribute(self
,
1432 translate_func
= self
._ifla
_br
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
1434 if not callable(translate_func
):
1438 user_config
= policymanager
.policymanager_api
.get_iface_default(
1439 module_name
=self
.__class
__.__name
__,
1444 if not link_just_created
and cached_value
is None:
1445 # the link already exists but we don't have any value
1446 # cached for this attr, it probably means that the
1447 # capability is not available on this system (i.e old kernel)
1448 self
.logger
.debug("%s: ignoring %s %s: capability probably not supported on this system"
1449 % (ifname
, attr_name
, user_config
))
1452 if not user_config
and not link_just_created
and cached_value
is not None:
1453 # there is no user configuration for this attribute
1454 # if the bridge existed before we need to check if
1455 # this attribute needs to be reset to default value
1456 default_value
= self
.get_attr_default_value(attr_name
)
1459 # the attribute has a default value, we need to convert it to
1460 # netlink format to compare it with the cache value
1461 default_value_nl
= translate_func(default_value
) # default_value.lower()
1463 if default_value_nl
!= cached_value
:
1464 # the running value difers from the default value
1465 # but the user didn't specify any config
1466 # resetting attribute to default
1467 ifla_info_data
[nl_attr
] = default_value_nl
1468 self
.logger
.info('%s: reset %s to default: %s' % (ifname
, attr_name
, default_value
))
1470 user_config_nl
= translate_func(user_config
) # user_config.lower()
1472 if user_config_nl
!= cached_value
:
1473 ifla_info_data
[nl_attr
] = user_config_nl
1475 if cached_value
is not None:
1476 self
.logger
.info('%s: set %s %s (cache %s)' % (ifname
, attr_name
, user_config
, cached_value
))
1478 self
.logger
.info('%s: set %s %s' % (ifname
, attr_name
, user_config
))
1479 except Exception as e
:
1480 self
.logger
.warning('%s: %s: %s' % (ifname
, attr_name
, str(e
)))
1482 def up_apply_bridge_settings(self
, ifaceobj
, link_just_created
, bridge_vlan_aware
):
1483 ifla_info_data
= dict()
1484 ifname
= ifaceobj
.name
1486 self
.logger
.info('%s: applying bridge settings' % ifname
)
1488 cached_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
1491 # we compare the user value (or policy value) with the current running state
1492 # we need to divide the cached value by 100 to ignore small difference.
1493 # i.e. our default value is 31 but the kernel default seems to be 3125
1494 cached_ifla_info_data
[Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
] //= 100
1495 cached_ifla_info_data
[Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
] *= 100
1499 for attr_name
, nl_attr
in self
._ifla
_br
_attributes
_map
.items():
1500 self
.fill_ifla_info_data_with_ifla_br_attribute(
1501 ifla_info_data
=ifla_info_data
,
1502 link_just_created
=link_just_created
,
1505 attr_name
=attr_name
,
1506 user_config
=ifaceobj
.get_attr_value_first(attr_name
),
1507 cached_value
=cached_ifla_info_data
.get(nl_attr
)
1510 # special cases ########################################################
1513 # if mstpctl-treeprio is configured on the bridge
1514 # do not reset the bridge-bridgeprio to the default value
1515 # NOTE: this is the case for every bridge/mstpctl attribute pairs.
1516 # TODO: more code should be added to handle this in the future.
1517 mstpctl_treeprio
= ifaceobj
.get_attr_value_first("mstpctl-treeprio")
1518 bridge_bridgeprio
= ifaceobj
.get_attr_value_first("bridge-bridgeprio")
1520 if mstpctl_treeprio
:
1521 self
.logger
.info("%s: mstpctl-treeprio attribute is set - ignorning bridge-bridgeprio" % ifname
)
1523 self
.fill_ifla_info_data_with_ifla_br_attribute(
1524 ifla_info_data
=ifla_info_data
,
1525 link_just_created
=link_just_created
,
1527 nl_attr
=Link
.IFLA_BR_PRIORITY
,
1528 attr_name
='bridge-bridgeprio',
1529 user_config
=bridge_bridgeprio
,
1530 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_PRIORITY
)
1534 self
.fill_ifla_info_data_with_ifla_br_attribute(
1535 ifla_info_data
=ifla_info_data
,
1536 link_just_created
=link_just_created
,
1538 nl_attr
=Link
.IFLA_BR_MCAST_SNOOPING
,
1539 attr_name
='bridge-mcsnoop',
1540 user_config
=self
.get_bridge_mcsnoop_value(ifaceobj
),
1541 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_MCAST_SNOOPING
)
1546 if bridge_vlan_aware
:
1547 self
.fill_ifla_info_data_with_ifla_br_attribute(
1548 ifla_info_data
=ifla_info_data
,
1549 link_just_created
=link_just_created
,
1551 nl_attr
=Link
.IFLA_BR_VLAN_STATS_ENABLED
,
1552 attr_name
='bridge-vlan-stats',
1553 user_config
=ifaceobj
.get_attr_value_first('bridge-vlan-stats') or self
.default_vlan_stats
,
1554 cached_value
=cached_ifla_info_data
.get(Link
.IFLA_BR_VLAN_STATS_ENABLED
)
1558 if self
._is
_config
_stp
_state
_on
(ifaceobj
):
1559 if not self
._is
_running
_stp
_state
_on
(ifname
):
1560 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 1
1561 self
.logger
.info('%s: stp state reset, reapplying port settings' % ifname
)
1562 ifaceobj
.module_flags
[ifaceobj
.name
] = \
1563 ifaceobj
.module_flags
.setdefault(self
.name
, 0) | \
1564 bridgeFlags
.PORT_PROCESSED_OVERRIDE
1566 # If stp not specified and running stp state on, set it to off
1567 if self
._is
_running
_stp
_state
_on
(ifname
):
1568 self
.logger
.info('%s: bridge-stp not specified but running: turning stp off')
1569 ifla_info_data
[Link
.IFLA_BR_STP_STATE
] = 0
1570 except Exception as e
:
1571 self
.logger
.warning('%s: bridge stp: %s' % (ifname
, str(e
)))
1574 self
.netlink
.link_set_bridge_info_data(ifname
, ifla_info_data
)
1576 def _check_vids(self
, ifaceobj
, vids
):
1581 va
, vb
= v
.split('-')
1582 va
, vb
= int(va
), int(vb
)
1583 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
, end
=vb
)
1586 self
._handle
_reserved
_vlan
(va
, ifaceobj
.name
)
1587 except exceptions
.ReservedVlanException
as e
:
1590 self
.logger
.warning('%s: unable to parse vid \'%s\''
1591 %(ifaceobj
.name
, v
))
1594 def _get_running_vids_n_pvid_str(self
, ifacename
):
1595 pvid
, vids
= self
.cache
.get_pvid_and_vids(ifacename
)
1598 ret_vids
= utils
.compress_into_ranges(vids
)
1603 ret_pvid
= '%s' %pvid
1606 return (ret_vids
, ret_pvid
)
1608 def _apply_bridge_vids_and_pvid(self
, bportifaceobj
, vids
, pvid
,
1610 """ This method is a combination of methods _apply_bridge_vids and
1611 _apply_bridge_port_pvids above. A combined function is
1612 found necessary to do the deletes first and the adds later
1613 because kernel does honor vid info flags during deletes.
1616 if not isbridge
and (bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
and not bportifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
1617 if not vids
or not pvid
or len(vids
) > 1 or vids
[0] != pvid
:
1618 self
._error
_vxlan
_in
_vlan
_aware
_br
(bportifaceobj
,
1619 bportifaceobj
.upperifaces
[0])
1622 vids_int
= utils
.ranges_to_ints(vids
)
1624 pvid_int
= int(pvid
) if pvid
else 0
1626 self
.logger
.warning('%s: unable to parse pvid \'%s\''
1627 %(bportifaceobj
.name
, pvid
))
1632 vids_to_add
= vids_int
1634 pvid_to_add
= pvid_int
1637 if not self
._check
_vids
(bportifaceobj
, vids
):
1640 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(bportifaceobj
.name
)
1642 if not running_vids
and not running_pvid
:
1643 # There cannot be a no running pvid.
1644 # It might just not be in our cache:
1645 # this can happen if at the time we were
1646 # creating the bridge vlan cache, the port
1647 # was not part of the bridge. And we need
1648 # to make sure both vids and pvid is not in
1649 # the cache, to declare that our cache may
1655 (vids_to_del
, vids_to_add
) = \
1656 utils
.diff_ids(vids_to_add
, running_vids
)
1659 if running_pvid
!= pvid_int
and running_pvid
!= 0:
1660 pvid_to_del
= running_pvid
1662 if (pvid_to_del
and (pvid_to_del
in vids_int
) and
1663 (pvid_to_del
not in vids_to_add
)):
1664 # kernel deletes dont take into account
1665 # bridge vid flags and its possible that
1666 # the pvid deletes we do end up deleting
1667 # the vids. Be proactive and add the pvid
1668 # to the vid add list if it is in the vids
1669 # and not already part of vids_to_add.
1670 # This helps with a small corner case:
1674 # - new change is going to move the state to
1677 vids_to_add
.add(pvid_to_del
)
1678 except exceptions
.ReservedVlanException
as e
:
1680 except Exception as e
:
1681 self
.log_error('%s: failed to process vids/pvids'
1682 %bportifaceobj
.name
+ ' vids = %s' %str
(vids
) +
1683 'pvid = %s ' %pvid
+ '(%s)' %str
(e
),
1684 bportifaceobj
, raise_error
=False)
1687 if pvid_to_add
in vids_to_del
:
1688 vids_to_del
.remove(pvid_to_add
)
1690 vids_to_del
= sorted(list(self
.remove_bridge_vlans_mapped_to_vnis_from_vids_list(None, bportifaceobj
, vids_to_del
)))
1692 self
.iproute2
.batch_start()
1693 self
.iproute2
.bridge_vlan_del_vid_list_self(bportifaceobj
.name
,
1694 utils
.compress_into_ranges(
1695 vids_to_del
), isbridge
)
1696 self
.iproute2
.batch_commit()
1697 except Exception as e
:
1698 self
.log_warn('%s: failed to del vid `%s` (%s)'
1699 %(bportifaceobj
.name
, str(vids_to_del
), str(e
)))
1703 self
.iproute2
.bridge_vlan_del_pvid(bportifaceobj
.name
,
1705 except Exception as e
:
1706 self
.log_warn('%s: failed to del pvid `%s` (%s)'
1707 %(bportifaceobj
.name
, pvid_to_del
, str(e
)))
1712 self
.iproute2
.batch_start()
1713 self
.iproute2
.bridge_vlan_add_vid_list_self(
1715 utils
.compress_into_ranges(sorted(list(vids_to_add
))),
1718 self
.iproute2
.batch_commit()
1719 except Exception as e
:
1720 self
.log_error('%s: failed to set vid `%s` (%s)'
1721 %(bportifaceobj
.name
, str(vids_to_add
),
1722 str(e
)), bportifaceobj
, raise_error
=False)
1725 if pvid_to_add
and pvid_to_add
!= running_pvid
:
1726 self
.iproute2
.bridge_vlan_add_pvid(bportifaceobj
.name
,
1728 except Exception as e
:
1729 self
.log_error('%s: failed to set pvid `%s` (%s)'
1730 %(bportifaceobj
.name
, pvid_to_add
, str(e
)),
1733 def get_bridge_vlans_mapped_to_vnis_as_integer_list(self
, ifaceobj
):
1735 Get all vlans that the user wants to configured in vlan-vni maps
1740 for vlans_vnis_map
in ifaceobj
.get_attr_value("bridge-vlan-vni-map"):
1741 for vlans_vni_map
in vlans_vnis_map
.split():
1742 vids
.extend(utils
.ranges_to_ints([vlans_vni_map
.split("=")[0]]))
1745 except Exception as e
:
1746 self
.logger
.debug("get_bridge_vlans_mapped_to_vnis_as_integer_list: %s" % str(e
))
1749 def remove_bridge_vlans_mapped_to_vnis_from_vids_list(self
, bridge_ifaceobj
, vxlan_ifaceobj
, vids_list
):
1751 For single vxlan we need to remove the vlans mapped to vnis
1752 from the vids list otherwise they will get removed from the brport
1754 if not (vxlan_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
1757 user_config_vids
= []
1760 for vid
in self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(bridge_ifaceobj
):
1761 user_config_vids
.append(vid
)
1764 for vid
in self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(vxlan_ifaceobj
):
1765 user_config_vids
.append(vid
)
1767 for vlan
in user_config_vids
:
1769 vids_list
.remove(vlan
)
1775 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
1782 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
1784 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
1786 allow_untagged
= 'yes'
1787 self
.check_bridge_port_vid_attrs(bportifaceobj
)
1789 allow_untagged
= bportifaceobj
.get_attr_value_first('bridge-allow-untagged') or 'yes'
1791 bport_vids
= self
.get_ifaceobj_bridge_vids_value(bportifaceobj
)
1793 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
1795 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
1797 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
1802 vids_final
= bridge_vids
1804 if allow_untagged
== 'yes':
1806 pvid_final
= pvids
[0]
1808 pvid_final
= bridge_pvid
1814 self
._apply
_bridge
_vids
_and
_pvid
(bportifaceobj
, vids_final
,
1817 def _apply_bridge_port_settings_all(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
):
1820 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
1821 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
1822 # Old style bridge port vid info
1823 # skip new style setting on ports
1825 self
.logger
.info('%s: applying bridge configuration '
1826 %ifaceobj
.name
+ 'specific to ports')
1828 bridge_vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
1830 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
1834 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1836 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)[0]
1840 if (ifaceobj
.module_flags
.get(self
.name
, 0x0) &
1841 bridgeFlags
.PORT_PROCESSED_OVERRIDE
):
1842 port_processed_override
= True
1844 port_processed_override
= False
1846 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
1848 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
1850 self
.iproute2
.batch_start()
1851 for bport
in bridgeports
:
1852 # on link_set_master we need to wait until we cache the correct
1853 # notification and register the brport as slave
1854 if not self
.cache
.bridge_port_exists(ifaceobj
.name
, bport
):
1855 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
1856 ' for port %s (missing port)' %bport
)
1858 self
.logger
.info('%s: processing bridge config for port %s'
1859 %(ifaceobj
.name
, bport
))
1860 bportifaceobjlist
= ifaceobj_getfunc(bport
)
1861 if not bportifaceobjlist
:
1863 for bportifaceobj
in bportifaceobjlist
:
1864 # Dont process bridge port if it already has been processed
1865 # and there is no override on port_processed
1866 if (not port_processed_override
and
1867 (bportifaceobj
.module_flags
.get(self
.name
,0x0) &
1868 bridgeFlags
.PORT_PROCESSED
)):
1871 # Add attributes specific to the vlan aware bridge
1872 if bridge_vlan_aware
:
1873 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
1874 bportifaceobj
, bridge_vids
, bridge_pvid
)
1875 elif self
.warn_on_untagged_bridge_absence
:
1876 self
._check
_untagged
_bridge
(ifaceobj
.name
, bportifaceobj
, ifaceobj_getfunc
)
1877 except exceptions
.ReservedVlanException
as e
:
1879 except Exception as e
:
1881 self
.logger
.warning('%s: %s' %(ifaceobj
.name
, str(e
)))
1883 self
.iproute2
.batch_commit()
1885 raise Exception('%s: errors applying port settings' %ifaceobj
.name
)
1887 def _check_untagged_bridge(self
, bridgename
, bridgeportifaceobj
, ifaceobj_getfunc
):
1888 if bridgeportifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
1889 lower_ifaceobj_list
= ifaceobj_getfunc(bridgeportifaceobj
.lowerifaces
[0])
1890 if lower_ifaceobj_list
and lower_ifaceobj_list
[0] and \
1891 not lower_ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
1892 self
.logger
.warning('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename
)
1893 self
.warn_on_untagged_bridge_absence
= False
1895 def bridge_port_get_bridge_name(self
, ifaceobj
):
1896 bridgename
= self
.cache
.get_bridge_name_from_port(ifaceobj
.name
)
1898 # bridge port is not enslaved to a bridge we need to find
1899 # the bridge in it's upper ifaces then enslave it
1900 for u
in ifaceobj
.upperifaces
:
1901 if self
.cache
.link_is_bridge(u
):
1904 # return should_enslave port, bridgename
1905 return False, bridgename
1907 def up_bridge_port_vlan_aware_bridge(self
, ifaceobj
, ifaceobj_getfunc
, bridge_name
, should_enslave_port
):
1908 if should_enslave_port
:
1909 self
.netlink
.link_set_master(ifaceobj
.name
, bridge_name
)
1911 if ifaceobj
.name
not in self
.svd_list
:
1912 self
.handle_ipv6([ifaceobj
.name
], '1')
1914 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
1915 bridge_pvid
= self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
)
1917 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
, bridge_vids
, bridge_pvid
)
1918 except Exception as e
:
1919 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
1922 def up_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
):
1923 should_enslave_port
, bridge_name
= self
.bridge_port_get_bridge_name(ifaceobj
)
1926 # bridge doesn't exist
1929 # check for bridge-learning on l2 vni in evpn setup
1930 self
.syntax_check_learning_l2_vni_evpn(ifaceobj
)
1932 # detect and warn when arp suppression is enabled and there is no vlan configured
1933 self
.syntax_check_bridge_arp_vni_vlan(ifaceobj
, ifaceobj_getfunc
)
1935 vlan_aware_bridge
= self
.cache
.bridge_is_vlan_aware(bridge_name
)
1936 if vlan_aware_bridge
:
1937 self
.up_bridge_port_vlan_aware_bridge(ifaceobj
,
1940 should_enslave_port
)
1942 bridge_ifaceobj
= ifaceobj_getfunc(bridge_name
)[0]
1944 self
.up_apply_brports_attributes(target_ports
=[ifaceobj
.name
],
1945 ifaceobj
=bridge_ifaceobj
,
1946 ifaceobj_getfunc
=ifaceobj_getfunc
,
1947 bridge_vlan_aware
=vlan_aware_bridge
)
1949 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED
1951 def up_check_bridge_vlan_aware(self
, ifaceobj
, ifaceobj_getfunc
, link_just_created
):
1952 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
1953 if not self
.check_bridge_vlan_aware_port(ifaceobj
, ifaceobj_getfunc
):
1955 if not link_just_created
and not self
.cache
.bridge_is_vlan_aware(ifaceobj
.name
):
1956 # if bridge-vlan-aware was added on a existing old-bridge, we need to reprocess all ports
1957 ifaceobj
.module_flags
[self
.name
] = ifaceobj
.module_flags
.setdefault(self
.name
, 0) | bridgeFlags
.PORT_PROCESSED_OVERRIDE
1962 def parse_interface_list_value(user_config
):
1964 for entry
in user_config
.split():
1965 ifname
, value
= entry
.split('=')
1966 config
[ifname
] = value
1969 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
):
1971 brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
1973 brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1975 Checks are not performed in this function and must be verified
1976 before. This is done this way to avoid calling this method on
1977 non vlan & bridge port interfaces thus wasting a bit less time
1983 if user_config_brport_learning_nl
is None:
1984 user_config_brport_learning_nl
= self
.bridge_vxlan_port_learning
1985 # bridge-learning is not configured by the user or by a policy
1986 # use "bridge-vxlan-port-learning" policy to set bridge-learning (default on)
1988 if user_config_brport_learning_nl
!= cached_brport_learning
:
1989 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
] \
1990 = cached_brport_learning \
1991 = user_config_brport_learning_nl
1994 "%s: %s: set bridge-learning %s"
1995 % (bridge_name
, brport_name
, "on" if user_config_brport_learning_nl
else "off")
1998 # in this case, the current bridge-learning value is properly configured and
1999 # doesn't need to be reset. We need to make sure that BRPORT_LEARNING is not
2000 # part of ifla_info_slave_data.
2002 del brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_LEARNING
]
2007 # vxlan-learning sync:
2010 brport_vxlan_learning_config
= brport_ifaceobj
.get_attr_value_first("vxlan-learning")
2011 # if vxlan-learning is defined by the user or via policy file we need
2012 # to honor his config and not sync vxlan-learning with bridge-learning
2014 if not brport_vxlan_learning_config
:
2016 brport_vxlan_learning_config
= policymanager
.policymanager_api
.get_attr_default("vxlan", "vxlan-learning")
2018 # convert vxlan-learning string to netlink value (if None use brport-learning value instead)
2019 brport_vxlan_learning_config_nl
= utils
.get_boolean_from_string(brport_vxlan_learning_config
) \
2020 if brport_vxlan_learning_config \
2021 else cached_brport_learning
2023 if brport_vxlan_learning_config_nl
!= self
.cache
.get_link_info_data_attribute(brport_name
, Link
.IFLA_VXLAN_LEARNING
):
2025 "%s: %s: vxlan learning and bridge learning out of sync: set vxlan-learning %s"
2026 % (bridge_name
, brport_name
, "on" if brport_vxlan_learning_config_nl
else "off")
2028 ifla_info_data
= {Link
.IFLA_VXLAN_LEARNING
: brport_vxlan_learning_config_nl
}
2031 # if kind and ifla_info_data are set they will be added to the
2032 # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
2033 return kind
, ifla_info_data
2035 def up_apply_brports_attributes(self
, ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
, target_ports
=[], newly_enslaved_ports
=[]):
2036 ifname
= ifaceobj
.name
2037 single_vxlan_device_ifaceobj
= None
2040 brports_ifla_info_slave_data
= dict()
2041 brport_ifaceobj_dict
= dict()
2042 brport_name_list
= []
2044 cache_brports_ifla_info_slave_data
= {}
2046 port_processed_override
= ifaceobj
.module_flags
.get(self
.name
, 0x0) & bridgeFlags
.PORT_PROCESSED_OVERRIDE
2048 running_brports
= self
.cache
.get_slaves(ifname
)
2050 # If target_ports is specified we want to configure only this
2051 # sub-list of port, we need to check if these ports are already
2052 # enslaved, if not they will be ignored.
2053 # If target_ports is not populated we will apply the brport
2054 # attributes on all running brport.
2057 for brport_name
in target_ports
:
2058 if brport_name
not in running_brports
:
2059 self
.logger
.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name
, ifname
))
2061 new_targets
.append(brport_name
)
2062 running_brports
= new_targets
2064 for port
in running_brports
:
2065 brport_list
= ifaceobj_getfunc(port
)
2067 port_already_processed
= False
2069 # ports just added to the bridge have to be processed
2070 if port
not in newly_enslaved_ports
:
2071 # check if brport was already processed
2072 for brportifaceobj
in brport_list
:
2073 if not port_processed_override
and brportifaceobj
.module_flags
.get(self
.name
, 0x0) & bridgeFlags
.PORT_PROCESSED
:
2074 # skip port if already processed (probably by `up_bridge_port`)
2075 port_already_processed
= True
2076 self
.logger
.info("%s: port %s: already processed" % (ifname
, port
))
2079 if not port_already_processed
:
2080 brport_name_list
.append(port
)
2081 brport_ifaceobj_dict
[port
] = brport_list
[0]
2082 brports_ifla_info_slave_data
[port
] = dict()
2084 if not ifupdownflags
.flags
.PERFMODE
and port
not in newly_enslaved_ports
:
2085 # if the port has just been enslaved, info_slave_data is not cached yet
2086 cache_brports_ifla_info_slave_data
[port
] = self
.cache
.get_link_info_slave_data(port
)
2088 cache_brports_ifla_info_slave_data
[port
] = {}
2090 if not brport_name_list
:
2091 self
.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj
)
2094 self
.logger
.info('%s: applying bridge port configuration: %s' % (ifname
, brport_name_list
))
2096 cached_bridge_mcsnoop
= self
.cache
.get_bridge_multicast_snooping(ifname
)
2098 bridge_ports_learning
= {}
2099 bridge_ports_vxlan_arp_suppress
= {}
2100 cached_bridge_ports_learning
= {}
2102 # we iterate through all IFLA_BRPORT supported attributes
2103 for attr_name
, nl_attr
in self
._ifla
_brport
_attributes
_map
.items():
2104 br_config
= ifaceobj
.get_attr_value_first(attr_name
)
2105 translate_func
= self
._ifla
_brport
_attributes
_translate
_user
_config
_to
_netlink
_map
.get(nl_attr
)
2107 if not translate_func
:
2108 # if no translation function is found,
2109 # we ignore this attribute and continue
2113 # user didn't specify any value for this attribute
2114 # looking at policy overrides
2115 br_config
= policymanager
.policymanager_api
.get_iface_default(
2116 module_name
=self
.__class
__.__name
__,
2122 #if bridge_vlan_aware:
2123 # self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
2124 # 'should be configured under the ports'
2125 # % (ifname, attr_name, br_config))
2127 # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
2128 # brport_name: { attr: value }
2130 # bridge-portprios swp1=5 swp2=32
2131 # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
2132 if '=' in br_config
:
2134 br_config
= self
.parse_interface_list_value(br_config
)
2136 self
.log_error('error while parsing \'%s %s\'' % (attr_name
, br_config
))
2139 for brport_ifaceobj
in list(brport_ifaceobj_dict
.values()):
2140 brport_config
= brport_ifaceobj
.get_attr_value_first(attr_name
)
2141 brport_name
= brport_ifaceobj
.name
2143 if not ifupdownflags
.flags
.PERFMODE
:
2144 cached_value
= cache_brports_ifla_info_slave_data
.get(brport_name
, {}).get(nl_attr
, None)
2148 if not brport_config
:
2149 # if a brport attribute was specified under the bridge and not under the port
2150 # we assign the bridge value to the port. If an attribute is both defined under
2151 # the bridge and the brport we keep the value of the port and ignore the br val.
2152 if type(br_config
) == dict:
2153 # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
2154 # br_config is a dictionary, example:
2155 # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
2156 brport_config
= br_config
.get(brport_name
)
2158 brport_config
= br_config
2160 if not brport_config
:
2161 brport_config
= policymanager
.policymanager_api
.get_iface_default(
2162 module_name
=self
.__class
__.__name
__,
2167 user_config
= brport_config
2169 # attribute specific work
2170 # This shouldn't be here but we don't really have a choice otherwise this
2171 # will require too much code duplication and will make the code very complex
2172 if nl_attr
== Link
.IFLA_BRPORT_NEIGH_SUPPRESS
:
2173 bridge_ports_vxlan_arp_suppress
[brport_name
] = user_config
2176 if self
.arp_nd_suppress_only_on_vxlan
and not brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2177 self
.logger
.warning('%s: %s: \'bridge-arp-nd-suppress\' '
2178 'is not supported on a non-vxlan port'
2179 % (ifaceobj
.name
, brport_name
))
2181 elif bridge_vlan_aware
:
2182 if not self
.arp_nd_suppress_only_on_vxlan
:
2183 user_config
= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default')
2184 elif self
.arp_nd_suppress_only_on_vxlan
and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2185 # ignore the case of VXLAN brport - handled later in the code
2189 elif nl_attr
== Link
.IFLA_BRPORT_GROUP_FWD_MASK
:
2190 # special handking for group_fwd_mask because Cisco proprietary
2191 # protocol needs to be set via a private netlink attribute
2192 self
.ifla_brport_group_fwd_mask(ifname
, brport_name
,
2193 brports_ifla_info_slave_data
,
2194 user_config
, cached_value
)
2198 # if not bridge_vlan_aware:
2199 # self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
2200 # 'should be configured under the bridge'
2201 # % (ifname, brport_name,
2202 # attr_name, brport_config))
2205 user_config_nl
= translate_func(user_config
)
2206 # check config value against running value
2207 if user_config_nl
!= cached_value
:
2208 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = user_config_nl
2209 self
.logger
.info('%s: %s: set %s %s' % (ifname
, brport_name
, attr_name
, user_config
))
2210 self
.logger
.debug('(cache %s)' % cached_value
)
2212 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
2213 # for vxlan-learning sync purposes we need to save the user config for each brports.
2214 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
2215 # IFLA_BRPORT_LEARNING if the user value is already configured and running
2216 # nevertheless we still need to check if the vxlan-learning is rightly synced with
2217 # the brport since it might go out of sync for X and Y reasons.
2218 # we also store the cached value to avoid an extra cache lookup.
2219 bridge_ports_learning
[brport_name
] = user_config_nl
2220 cached_bridge_ports_learning
[brport_name
] = cached_value
2222 elif cached_value
is not None:
2223 # no config found, do we need to reset to default?
2224 default
= self
.get_attr_default_value(attr_name
)
2226 default_netlink
= translate_func(default
)
2228 if nl_attr
== Link
.IFLA_BRPORT_LEARNING
:
2229 # for vxlan-learning sync purposes we need to save the user config for each brports.
2230 # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
2231 # IFLA_BRPORT_LEARNING if the user value is already configured and running
2232 # nevertheless we still need to check if the vxlan-learning is rightly synced with
2233 # the brport since it might go out of sync for X and Y reasons.
2234 # we also store the cached value to avoid an extra cache lookup.
2235 cached_bridge_ports_learning
[brport_name
] = cached_value
2236 bridge_ports_learning
[brport_name
] = self
.bridge_vxlan_port_learning
2238 if brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
2239 # bridge-learning for vxlan device is handled separatly in sync_bridge_learning_to_vxlan_brport
2242 if not ifupdownflags
.flags
.PERFMODE
and brport_name
not in newly_enslaved_ports
:
2243 # We don't query new slaves and not during boot
2245 if self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_PEER_LINK
):
2246 if default_netlink
!= cached_value
:
2247 self
.logger
.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
2248 % (ifname
, brport_name
))
2250 except Exception as e
:
2251 self
.logger
.debug('%s: %s: peerlink check: %s' % (ifname
, brport_name
, str(e
)))
2253 if default_netlink
!= cached_value
:
2254 self
.logger
.info('%s: %s: %s: no configuration detected, resetting to default %s'
2255 % (ifname
, brport_name
, attr_name
, default
))
2256 self
.logger
.debug('(cache %s)' % cached_value
)
2257 brports_ifla_info_slave_data
[brport_name
][nl_attr
] = default_netlink
2259 # is the current bridge (ifaceobj) a QinQ bridge?
2260 # This variable is initialized to None and will be
2261 # change to True/False, so that the check is only
2265 # applying bridge port configuration via netlink
2266 for brport_name
, brport_ifla_info_slave_data
in list(brports_ifla_info_slave_data
.items()):
2268 brport_ifaceobj
= brport_ifaceobj_dict
.get(brport_name
)
2270 and brport_ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
2271 and brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
):
2272 # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
2273 # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
2274 kind
, ifla_info_data
= self
.sync_bridge_learning_to_vxlan_brport(ifaceobj
.name
,
2277 brport_ifla_info_slave_data
,
2278 bridge_ports_learning
.get(brport_name
),
2279 cached_bridge_ports_learning
.get(brport_name
))
2281 if (self
.vxlan_bridge_igmp_snooping_enable_port_mcrouter
and utils
.get_boolean_from_string(
2282 self
.get_bridge_mcsnoop_value(ifaceobj
)
2283 )) or cached_bridge_mcsnoop
:
2284 # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
2285 # is on and mcsnoop is on (or mcsnoop is already enabled on the
2286 # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
2287 if not brport_ifla_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
) \
2288 and self
.cache
.get_bridge_port_multicast_router(brport_name
) != 2:
2289 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_MULTICAST_ROUTER
] = 2
2290 self
.logger
.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname
, brport_name
))
2293 # handling attribute: bridge-arp-nd-suppress
2294 # defaults to bridge-vxlan-arp-nd-suppress policy (default False)
2296 user_config_neigh_suppress
= bridge_ports_vxlan_arp_suppress
.get(brport_name
)
2298 if user_config_neigh_suppress
is None:
2300 if qinq_bridge
is None:
2301 # QinQ bridge hasn't been checked yet
2302 qinq_bridge
= self
.is_qinq_bridge(
2306 brport_ifaceobj_dict
,
2311 # exclude QinQ bridge from arp-nd-suppress default policy on
2312 config_neigh_suppress
= 0
2313 self
.logger
.info("%s: QinQ bridge detected: %s: set bridge-arp-nd-suppress off" % (ifname
, brport_name
))
2315 config_neigh_suppress
= self
.bridge_vxlan_arp_nd_suppress_int
2317 config_neigh_suppress
= int(utils
.get_boolean_from_string(user_config_neigh_suppress
))
2319 brport_neigh_suppress_cached_value
= self
.cache
.get_link_info_slave_data_attribute(
2321 Link
.IFLA_BRPORT_NEIGH_SUPPRESS
2324 if config_neigh_suppress
!= brport_neigh_suppress_cached_value
:
2325 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_NEIGH_SUPPRESS
] = config_neigh_suppress
2327 if not user_config_neigh_suppress
:
2328 # if the configuration is not explicitely defined by the user
2329 # we need report that the default behavior is enabled by policy
2331 "%s: set bridge-arp-nd-suppress %s by default on vxlan port (%s)"
2332 % (ifname
, "on" if self
.bridge_vxlan_arp_nd_suppress
else "off", brport_name
)
2335 # the user configuration (or policy) is already configured and running
2336 # we need to remove this attribute from the request dictionary
2338 del brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_NEIGH_SUPPRESS
]
2343 # SINGLE VXLAN - enable IFLA_BRPORT_VLAN_TUNNEL
2346 if brport_ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
:
2347 single_vxlan_device_ifaceobj
= brport_ifaceobj
2348 brport_vlan_tunnel_cached_value
= self
.cache
.get_link_info_slave_data_attribute(
2350 Link
.IFLA_BRPORT_VLAN_TUNNEL
2353 if not brport_vlan_tunnel_cached_value
:
2354 self
.logger
.info("%s: %s: enabling vlan_tunnel on single vxlan device" % (ifname
, brport_name
))
2355 brport_ifla_info_slave_data
[Link
.IFLA_BRPORT_VLAN_TUNNEL
] = 1
2361 if brport_ifla_info_slave_data
or ifla_info_data
:
2363 self
.netlink
.link_set_brport_with_info_slave_data(
2366 ifla_info_data
=ifla_info_data
,
2367 ifla_info_slave_data
=brport_ifla_info_slave_data
2369 except Exception as e
:
2370 self
.logger
.warning('%s: %s: %s' % (ifname
, brport_name
, str(e
)))
2372 self
.bridge_process_vidinfo_mcqv4src_maxwait(ifaceobj
)
2374 except Exception as e
:
2375 self
.log_error(str(e
), ifaceobj
)
2377 if single_vxlan_device_ifaceobj
:
2378 self
.apply_bridge_port_vlan_vni_map(single_vxlan_device_ifaceobj
)
2381 def range_to_string(range_start
, range_end
):
2382 return "%s" % range_start
if range_start
== range_end
else "%s-%s" % (range_start
, range_end
)
2384 def range_list_to_string(self
, ifname
, vni_list
):
2385 range_list
= [v
for v
in utils
.ints_to_ranges(vni_list
)]
2387 if len(range_list
) != 1 and len(range_list
[0]) > 0:
2388 self
.logger
.debug("%s: vlan-vni-map has duplicated ranges: %s" % (ifname
, json
.dumps(range_list
, indent
=4)))
2389 self
.log_error("misconfiguration detected - see debug output for details")
2391 return self
.range_to_string(range_list
[0][0], range_list
[0][1])
2393 def check_duplicate_vnis(self
, ifaceobj
, vlan_vni_dict
):
2396 for key
, value
in vlan_vni_dict
.items():
2397 rev
.setdefault(value
, set()).add(key
)
2399 duplicates
= [(key
, values
) for key
, values
in rev
.items() if len(values
) > 1]
2402 err_msg
= ["duplicate vnis detected - see details below"]
2404 for vni
, vlans
in duplicates
:
2405 err_msg
.append("\tvni %s assigned to vlans: %s" % (vni
, ", ".join(map(str, vlans
))))
2407 self
.log_error("\n".join(err_msg
), ifaceobj
)
2412 def get_vlan_vni_ranges_from_dict(self
, ifname
, vlan_vni_dict
):
2414 Since bridge-vlan-vni-map is a multiline attribute, we expend all the ranges
2415 and have all the vlan-vni mapping in vlan_vni_dict. We need to reconstruct the
2416 ranges to execute iproute2 commands.
2418 i.e. for a multiline vlan-vni configuration:
2419 bridge-vlan-vni-map 1=1
2420 bridge-vlan-vni-map 2=2
2421 bridge-vlan-vni-map 3=3
2422 bridge-vlan-vni-map 4=4
2424 we will only execute a single ranged-command: vlan add dev vxlan48 vid 1-4 tunnel_info id 1-4
2426 If we find duplicated vlan/vnis in ranges we raise an exception
2428 vlan_vni_ranges
= {}
2430 def list_to_range(vlan_list
, vni_list
, range_dict
):
2431 if not vlan_list
and not vni_list
:
2433 vlans
= self
.range_list_to_string(ifname
, vlan_list
)
2434 vnis
= self
.range_list_to_string(ifname
, vni_list
)
2435 range_dict
[vlans
] = vnis
2437 current_vlan_range
= []
2438 current_vni_range
= []
2440 for vlan
in sorted(vlan_vni_dict
.keys()):
2441 vni
= vlan_vni_dict
[vlan
]
2443 if not current_vlan_range
:
2444 current_vlan_range
.append(vlan
)
2445 current_vni_range
.append(vni
)
2448 if vlan
- 1 == current_vlan_range
[-1] and vni
- 1 == current_vni_range
[-1]:
2449 current_vlan_range
.append(vlan
)
2450 current_vni_range
.append(vni
)
2452 list_to_range(current_vlan_range
, current_vni_range
, vlan_vni_ranges
)
2453 current_vlan_range
= [vlan
]
2454 current_vni_range
= [vni
]
2456 list_to_range(current_vlan_range
, current_vni_range
, vlan_vni_ranges
)
2457 return vlan_vni_ranges
2459 def check_bridge_vlan_vni_map_reserved(self
, ifaceobj
, vlan_to_add
):
2460 for vlan
in sorted(vlan_to_add
):
2461 self
._handle
_reserved
_vlan
(vlan
, ifaceobj
.name
)
2463 def apply_bridge_port_vlan_vni_map(self
, ifaceobj
):
2465 bridge vlan add vid <vlan-id> dev vxlan0
2466 bridge vlan add dev vxlan0 vid <vlan-id> tunnel_info id <vni>
2468 vxlan_name
= ifaceobj
.name
2470 self
.iproute2
.batch_start()
2472 bridge_vlan_tunnel_info_running_config
= self
.iproute2
.bridge_vlan_tunnel_show(vxlan_name
)
2473 all_user_config
= {}
2475 for bridge_vlan_vni_map_entry
in ifaceobj
.get_attr_value("bridge-vlan-vni-map"):
2476 if not bridge_vlan_vni_map_entry
:
2479 for vlan_vni_map_entry
in bridge_vlan_vni_map_entry
.split():
2481 vlans_str
, vni_str
= utils
.get_vlan_vni_in_map_entry(vlan_vni_map_entry
)
2483 return self
.__warn
_bridge
_vlan
_vni
_map
_syntax
_error
(vxlan_name
, vlan_vni_map_entry
)
2485 # we need to convert vlan_str and vni_str back to a map {vlan: vni}
2486 for vlan
, vni
in zip(utils
.ranges_to_ints([vlans_str
]), utils
.ranges_to_ints([vni_str
])):
2488 if vlan
in all_user_config
:
2489 self
.log_error("duplicate vlan found: %s" % vlan
, ifaceobj
)
2491 all_user_config
[vlan
] = vni
2493 vlan_vni_to_remove
= {}
2494 for k
, v
in set(bridge_vlan_tunnel_info_running_config
.items()) - set(all_user_config
.items()):
2495 vlan_vni_to_remove
[k
] = v
2497 vlan_vni_to_add
= {}
2498 for k
, v
in set(all_user_config
.items()) - set(bridge_vlan_tunnel_info_running_config
.items()):
2499 vlan_vni_to_add
[k
] = v
2501 vlan_vni_ranges_to_remove
= self
.get_vlan_vni_ranges_from_dict(ifaceobj
.name
, vlan_vni_to_remove
)
2503 # check if we have duplicated vnis in the user configuration
2504 self
.check_duplicate_vnis(ifaceobj
, vlan_vni_to_add
)
2506 # check reserved vlans
2507 self
.check_bridge_vlan_vni_map_reserved(ifaceobj
, vlan_vni_to_add
.keys())
2509 vlan_vni_ranges_to_add
= self
.get_vlan_vni_ranges_from_dict(ifaceobj
.name
, vlan_vni_to_add
)
2511 for vlan_range
, vni_range
in vlan_vni_ranges_to_remove
.items():
2512 self
.iproute2
.bridge_vlan_del_vid_list_self(vxlan_name
, [vlan_range
], False)
2513 self
.iproute2
.bridge_vlan_del_vlan_tunnel_info(vxlan_name
, vlan_range
, vni_range
)
2515 for vlan_range
, vni_range
in vlan_vni_ranges_to_add
.items():
2516 self
.iproute2
.bridge_vlan_add_vid_list_self(vxlan_name
, [vlan_range
], False)
2517 self
.iproute2
.bridge_vlan_add_vlan_tunnel_info(vxlan_name
, vlan_range
, vni_range
)
2519 self
.iproute2
.batch_commit()
2520 except Exception as e
:
2521 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2522 raise BridgeVlanVniMapError("%s: error while processing bridge-vlan-vni-map: %s" % (vxlan_name
, str(e
)))
2524 def __warn_bridge_vlan_vni_map_syntax_error(self
, ifname
, user_config_vlan_vni_map
):
2525 self
.logger
.warning("%s: syntax error: bridge-vlan-vni-map %s" % (ifname
, user_config_vlan_vni_map
))
2527 def is_qinq_bridge(self
, ifaceobj
, brport_name
, running_brports
, brport_ifaceobj_dict
, ifaceobj_getfunc
):
2528 """ Detect QinQ bridge
2529 Potential improvement: We could add a ifaceobj.link_privflags called
2530 BRIDGE_QINQ but for now it is not necessary.
2533 # bridge-vlan-aware case
2534 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
:
2535 return (ifaceobj
.get_attr_value_first("bridge-vlan-protocol") or "").lower() == "802.1ad"
2539 for qinq_running_brport
in running_brports
:
2540 if qinq_running_brport
== brport_name
:
2543 qinq_running_brport_ifaceobj
= brport_ifaceobj_dict
.get(qinq_running_brport
)
2545 if not qinq_running_brport_ifaceobj
:
2548 if qinq_running_brport_ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
:
2549 for lower_iface
in qinq_running_brport_ifaceobj
.lowerifaces
or []:
2550 for lower_ifaceobj
in ifaceobj_getfunc(lower_iface
) or []:
2551 if (lower_ifaceobj
.get_attr_value_first("vlan-protocol") or "").lower() == "802.1ad":
2555 def bridge_process_vidinfo_mcqv4src_maxwait(self
, ifaceobj
):
2556 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
2557 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
2558 self
._process
_bridge
_maxwait
(ifaceobj
, self
._get
_bridge
_port
_list
(ifaceobj
))
2560 def ifla_brport_group_fwd_mask(self
, ifname
, brport_name
, brports_ifla_info_slave_data
, user_config
, cached_ifla_brport_group_fwd_mask
):
2562 Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
2563 Since this is the only ifupdown2 attribute dealing with more than 1 netlink
2564 field we need to have special handling for that.
2566 ifla_brport_group_fwd_mask
= 0
2567 ifla_brport_group_fwd_maskhi
= 0
2570 for group
in user_config
.replace(",", " ").split():
2574 callback
= self
.l2protocol_tunnel_callback
.get(group
)
2576 if not callable(callback
):
2577 self
.logger
.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname
, brport_name
, group
))
2579 ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
= callback(ifla_brport_group_fwd_mask
, ifla_brport_group_fwd_maskhi
)
2581 # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
2582 cached_ifla_brport_group_fwd_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
2584 log_mask_change
= True
2585 # if user specify bridge-l2protocol-tunnel stp cdp
2586 # we need to set both MASK and MASKHI but we only want to log once
2588 if cached_ifla_brport_group_fwd_mask
is None:
2589 cached_ifla_brport_group_fwd_mask
= 0
2590 if cached_ifla_brport_group_fwd_maskhi
is None:
2591 cached_ifla_brport_group_fwd_maskhi
= 0
2593 # if the cache value is None it means that the kernel doesn't support this attribute
2594 # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
2596 if ifla_brport_group_fwd_mask
!= cached_ifla_brport_group_fwd_mask
:
2598 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2599 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask
)
2600 log_mask_change
= False
2601 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASK
] = ifla_brport_group_fwd_mask
2603 if ifla_brport_group_fwd_maskhi
!= cached_ifla_brport_group_fwd_maskhi
:
2605 self
.logger
.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname
, brport_name
, user_config
))
2606 self
.logger
.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi
)
2607 brports_ifla_info_slave_data
[brport_name
][Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
] = ifla_brport_group_fwd_maskhi
2609 def get_bridge_mtu(self
, ifaceobj
):
2610 user_config_mtu
= ifaceobj
.get_attr_value_first("mtu")
2612 if not user_config_mtu
:
2613 user_config_mtu
= policymanager
.policymanager_api
.get_attr_default(
2614 module_name
="address",
2620 int(user_config_mtu
)
2621 self
.logger
.info("%s: set bridge mtu %s" % (ifaceobj
.name
, user_config_mtu
))
2622 return str(user_config_mtu
)
2623 except Exception as e
:
2624 self
.logger
.warning("%s: invalid bridge mtu %s: %s" % (ifaceobj
.name
, user_config_mtu
, str(e
)))
2627 def up_bridge(self
, ifaceobj
, ifaceobj_getfunc
):
2628 ifname
= ifaceobj
.name
2630 if ifupdownflags
.flags
.PERFMODE
:
2633 link_exists
= self
.cache
.link_exists(ifaceobj
.name
)
2636 self
.netlink
.link_add_bridge(ifname
)
2637 link_just_created
= True
2639 bridge_mtu
= self
.get_bridge_mtu(ifaceobj
)
2641 self
.sysfs
.link_set_mtu(ifname
, bridge_mtu
, int(bridge_mtu
))
2643 link_just_created
= False
2644 self
.logger
.info('%s: bridge already exists' % ifname
)
2646 bridge_vlan_aware
= self
.up_check_bridge_vlan_aware(ifaceobj
, ifaceobj_getfunc
, link_just_created
)
2648 self
.up_apply_bridge_settings(ifaceobj
, link_just_created
, bridge_vlan_aware
)
2651 newly_enslaved_ports
= self
._add
_ports
(ifaceobj
, ifaceobj_getfunc
)
2652 self
.up_apply_brports_attributes(ifaceobj
, ifaceobj_getfunc
, bridge_vlan_aware
,
2653 newly_enslaved_ports
=newly_enslaved_ports
)
2654 except BridgeVlanVniMapError
:
2656 except Exception as e
:
2657 self
.logger
.warning('%s: apply bridge ports settings: %s' % (ifname
, str(e
)))
2661 running_ports
= self
.cache
.get_slaves(ifaceobj
.name
)
2662 if not running_ports
:
2664 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
2665 ifaceobj_getfunc
=ifaceobj_getfunc
,
2666 bridge_vlan_aware
=bridge_vlan_aware
)
2667 except exceptions
.ReservedVlanException
as e
:
2669 except Exception as e
:
2670 self
.logger
.warning('%s: apply bridge settings: %s' % (ifname
, str(e
)))
2672 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2673 self
.iproute2
.batch_start()
2674 for p
in running_ports
:
2675 ifaceobj_list
= ifaceobj_getfunc(p
)
2676 if (ifaceobj_list
and ifaceobj_list
[0].link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
):
2677 self
.iproute2
.link_down(p
)
2679 self
.iproute2
.link_up(p
)
2681 self
.iproute2
.batch_commit()
2682 except Exception as e
:
2683 # link set up on bridge ports failed - ignore and log debug
2684 self
.logger
.debug("%s: %s" % (ifname
, str(e
)))
2687 self
._up
_bridge
_mac
(ifaceobj
, ifaceobj_getfunc
)
2688 except Exception as e
:
2689 self
.logger
.warning('%s: setting bridge mac address: %s' % (ifaceobj
.name
, str(e
)))
2691 def _get_bridge_mac(self
, ifaceobj
, ifname
, ifaceobj_getfunc
):
2692 bridge_mac_iface
= self
.bridge_mac_iface
.get(ifname
)
2694 if bridge_mac_iface
and bridge_mac_iface
[0] and bridge_mac_iface
[1]:
2695 return bridge_mac_iface
2697 if self
.bridge_mac_iface_list
:
2698 self
.logger
.debug('bridge mac iface list: %s' % self
.bridge_mac_iface_list
)
2700 for bridge_mac_intf
in self
.bridge_mac_iface_list
:
2701 ifaceobj_list
= ifaceobj_getfunc(bridge_mac_intf
)
2705 for obj
in ifaceobj_list
:
2706 iface_user_configured_hwaddress
= utils
.strip_hwaddress(obj
.get_attr_value_first('hwaddress'))
2707 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2708 if iface_user_configured_hwaddress
:
2709 iface_mac
= iface_user_configured_hwaddress
2711 if not iface_mac
and not self
.cache
.link_exists(bridge_mac_intf
):
2715 iface_mac
= self
.cache
.get_link_address(bridge_mac_intf
)
2716 # if hwaddress attribute is not configured we use the running mac addr
2718 self
.bridge_mac_iface
[ifname
] = (bridge_mac_intf
, iface_mac
)
2719 return self
.bridge_mac_iface
[ifname
]
2720 elif self
.bridge_set_static_mac_from_port
:
2721 # no policy was provided, we need to get the first physdev or bond ports
2722 # and use its hwaddress to set the bridge mac
2724 # first we need to make sure that the bridge mac is not already inherited from one of it's port
2725 bridge_ports
= self
._get
_bridge
_port
_list
_user
_ordered
(ifaceobj
)
2726 current_mac
= self
.cache
.get_link_address(ifname
)
2728 for port
in bridge_ports
or []:
2729 if not self
.is_vxlan(ifaceobj_getfunc(port
)):
2730 port_mac
= self
.cache
.get_link_address(port
)
2732 if current_mac
== port_mac
:
2733 self
.logger
.info("bridge mac is already inherited from %s" % port
)
2734 self
.bridge_mac_iface
[ifname
] = (port
, port_mac
)
2735 return self
.bridge_mac_iface
[ifname
]
2737 for port
in bridge_ports
or []:
2738 # iterate through the bridge-port list
2739 for port_obj
in ifaceobj_getfunc(port
) or []:
2740 # check if the port is a physdev (link_kind is null) or a bon
2741 if port_obj
.link_kind
!= ifaceLinkKind
.VXLAN
:
2742 iface_user_configured_hwaddress
= utils
.strip_hwaddress(port_obj
.get_attr_value_first('hwaddress'))
2743 # if user did configured 'hwaddress' we need to use this value instead of the cached value.
2744 if iface_user_configured_hwaddress
:
2745 iface_mac
= iface_user_configured_hwaddress
.lower()
2746 # we need to "normalize" the user provided MAC so it can match with
2747 # what we have in the cache (data retrieved via a netlink dump by
2748 # nlmanager). nlmanager return all macs in lower-case
2750 iface_mac
= self
.cache
.get_link_address(port
)
2753 self
.bridge_mac_iface
[ifname
] = (port
, iface_mac
)
2754 return self
.bridge_mac_iface
[ifname
]
2759 def is_vxlan(port_obj_list
):
2760 # checking if the port is a vxlan by checking the ifaceobjs
2761 # instead of checking to cache (saving on locking time)
2762 for _port_obj
in port_obj_list
or []:
2763 if _port_obj
.link_kind
== ifaceLinkKind
.VXLAN
:
2767 def _add_bridge_mac_to_fdb(self
, ifaceobj
, bridge_mac
):
2768 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
and bridge_mac
and ifaceobj
.get_attr_value('address'):
2769 self
.iproute2
.bridge_fdb_add(ifaceobj
.name
, bridge_mac
, vlan
=None, bridge
=True, remote
=None)
2771 def _up_bridge_mac(self
, ifaceobj
, ifaceobj_getfunc
):
2773 We have a day one bridge mac changing problem with changing ports
2774 (basically bridge mac changes when the port it inherited the mac from
2777 We have discussed this problem many times before and tabled it.
2778 The issue has aggravated with vxlan bridge ports having auto-generated
2779 random macs...which change on every reboot.
2781 ifupdown2 extract from policy files an iface to select a mac from and
2782 configure it automatically.
2784 if ifaceobj
.get_attr_value('hwaddress'):
2785 # if the user configured a static hwaddress
2786 # there is no need to assign one
2789 ifname
= ifaceobj
.name
2790 mac_intf
, bridge_mac
= self
._get
_bridge
_mac
(ifaceobj
, ifname
, ifaceobj_getfunc
)
2791 self
.logger
.debug("%s: _get_bridge_mac returned (%s, %s)"
2792 %(ifname
, mac_intf
, bridge_mac
))
2795 # if an interface is configured with the following attribute:
2796 # hwaddress 08:00:27:42:42:4
2797 # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
2798 # from the kernel. The only way to counter that is to convert all mac to int
2799 # and compare the ints, it will increase perfs and be safer.
2800 cached_value
= self
.cache
.get_link_address(ifname
)
2801 self
.logger
.debug('%s: cached hwaddress value: %s' % (ifname
, cached_value
))
2802 bridge_mac_int
= utils
.mac_str_to_int(bridge_mac
)
2803 if cached_value
and utils
.mac_str_to_int(cached_value
) == bridge_mac_int
:
2804 # the bridge mac is already set to the bridge_mac_intf's mac
2807 self
.logger
.info('%s: setting bridge mac to port %s mac' % (ifname
, mac_intf
))
2809 self
.netlink
.link_set_address(ifname
, bridge_mac
, bridge_mac_int
) # force=True
2810 except Exception as e
:
2811 self
.logger
.info('%s: %s' % (ifname
, str(e
)))
2812 # log info this error because the user didn't explicitly configured this
2814 self
._add
_bridge
_mac
_to
_fdb
(ifaceobj
, self
.cache
.get_link_address(ifname
))
2816 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
2817 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
:
2818 self
.up_bridge_port(ifaceobj
, ifaceobj_getfunc
)
2820 elif ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
:
2821 self
.up_bridge(ifaceobj
, ifaceobj_getfunc
)
2824 bridge_attributes
= list(self
._modinfo
.get('attrs', {}).keys())
2826 for ifaceobj_config_attr
in list(ifaceobj
.config
.keys()):
2827 if ifaceobj_config_attr
in bridge_attributes
:
2828 self
.logger
.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
2829 % (ifaceobj
.name
, ifaceobj_config_attr
))
2831 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
2832 if not self
._is
_bridge
(ifaceobj
):
2834 ifname
= ifaceobj
.name
2835 if not self
.cache
.link_exists(ifname
):
2839 self
.netlink
.link_del(self
.get_dummy_brport_name_for_bridge(ifname
))
2844 running_ports
= self
.cache
.get_slaves(ifname
)
2846 self
.handle_ipv6(running_ports
, '0')
2847 if ifaceobj
.link_type
!= ifaceLinkType
.LINK_NA
:
2848 for p
in running_ports
:
2849 self
.netlink
.link_down(p
)
2850 except Exception as e
:
2851 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
)
2853 self
.netlink
.link_del(ifname
)
2854 except Exception as e
:
2855 ifaceobj
.set_status(ifaceStatus
.ERROR
)
2856 self
.logger
.error(str(e
))
2857 # netlink exception already contains the ifname
2859 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
2862 running_bridge_port_vids
= ''
2865 _
, running_vids
= self
.cache
.get_pvid_and_vids(p
)
2867 running_bridge_port_vids
+= ' %s=%s' %(p
,
2868 ','.join(running_vids
))
2871 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
2873 running_bridge_port_pvid
= ''
2876 running_pvid
= self
.cache
.get_pvid(p
)
2878 running_bridge_port_pvid
+= ' %s=%s' %(p
,
2882 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvid
2884 _
, running_bridge_vids
= self
.cache
.get_pvid_and_vids(ifaceobjrunning
.name
)
2885 if running_bridge_vids
:
2886 running_attrs
['bridge-vids'] = ','.join(utils
.compress_into_ranges(running_bridge_vids
))
2887 return running_attrs
2889 def _query_running_vidinfo(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2893 # 'bridge-vids' under the bridge is all about 'vids' on the port.
2894 # so query the ports
2895 running_bridgeport_vids
= []
2896 running_bridgeport_pvids
= []
2897 for bport
in bridgeports
:
2898 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2900 running_bridgeport_vids
.append(' '.join(vids
))
2902 running_bridgeport_pvids
.append(pvid
)
2905 if running_bridgeport_vids
:
2906 (vidval
, freq
) = Counter(running_bridgeport_vids
).most_common()[0]
2907 if freq
== len(bridgeports
):
2908 running_attrs
['bridge-vids'] = vidval
2909 bridge_vids
= vidval
.split()
2912 if running_bridgeport_pvids
:
2913 (vidval
, freq
) = Counter(running_bridgeport_pvids
).most_common()[0]
2914 if freq
== len(bridgeports
) and vidval
!= '1':
2915 running_attrs
['bridge-pvid'] = vidval
2916 bridge_pvid
= vidval
.split()[0]
2918 # Go through all bridge ports and find their vids
2919 for bport
in bridgeports
:
2920 bportifaceobj
= ifaceobj_getfunc(bport
)
2921 if not bportifaceobj
:
2925 (vids
, pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(bport
)
2926 if vids
and vids
!= bridge_vids
:
2928 if pvid
and pvid
!= bridge_pvid
:
2930 if bport_vids
and bport_pvid
in bport_vids
:
2931 bport_vids
.remove(bport_pvid
)
2932 if (not bport_vids
and bport_pvid
and bport_pvid
!= '1'):
2933 bportifaceobj
[0].replace_config('bridge-access', bport_pvid
)
2934 bportifaceobj
[0].delete_config('bridge-pvid')
2935 bportifaceobj
[0].delete_config('bridge-vids')
2937 if bport_pvid
and bport_pvid
!= '1':
2938 bportifaceobj
[0].replace_config('bridge-pvid', bport_pvid
)
2940 # delete any stale bridge-vids under ports
2941 bportifaceobj
[0].delete_config('bridge-pvid')
2943 bportifaceobj
[0].replace_config('bridge-vids',
2944 ' '.join(bport_vids
))
2946 # delete any stale bridge-vids under ports
2947 bportifaceobj
[0].delete_config('bridge-vids')
2948 return running_attrs
2950 def _query_running_mcqv4src(self
, ifaceobjrunning
):
2951 running_mcqv4src
= self
.sysfs
.bridge_get_mcqv4src(ifaceobjrunning
.name
)
2952 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in list(running_mcqv4src
.items())]
2954 mcq
= ' '.join(mcqs
)
2957 def _query_running_attrs(self
, ifaceobjrunning
, ifaceobj_getfunc
,
2958 bridge_vlan_aware
=False):
2960 ifname
= ifaceobjrunning
.name
2965 if self
.systcl_get_net_bridge_stp_user_space() == '1':
2967 except Exception as e
:
2968 self
.logger
.info('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
2970 bridge_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
2973 # Fill bridge_ports and bridge stp attributes first
2977 bridgeattrdict
["bridge-ports"] = [" ".join(self
.cache
.get_slaves(ifname
))]
2982 cached_stp
= bool(bridge_ifla_info_data
.get(Link
.IFLA_BR_STP_STATE
))
2984 if cached_stp
!= utils
.get_boolean_from_string(
2985 self
.get_mod_subattr("bridge-stp", "default")
2987 bridgeattrdict
['bridge-stp'] = ["yes" if cached_stp
else "no"]
2989 skip_kernel_stp_attrs
= cached_stp
and userspace_stp
2991 if skip_kernel_stp_attrs
:
2992 bridge_attributes_map
= {
2993 "bridge-mcqifaddr": Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
,
2994 "bridge-mcquerier": Link
.IFLA_BR_MCAST_QUERIER
,
2995 "bridge-mcrouter": Link
.IFLA_BR_MCAST_ROUTER
,
2996 "bridge-mcstats": Link
.IFLA_BR_MCAST_STATS_ENABLED
,
2997 "bridge-mcsnoop": Link
.IFLA_BR_MCAST_SNOOPING
,
2998 "bridge-mclmc": Link
.IFLA_BR_MCAST_LAST_MEMBER_CNT
,
2999 "bridge-mclmi": Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
,
3000 "bridge-mcqri": Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
,
3001 "bridge-mcqpi": Link
.IFLA_BR_MCAST_QUERIER_INTVL
,
3002 "bridge-mcsqc": Link
.IFLA_BR_MCAST_STARTUP_QUERY_CNT
,
3003 "bridge-mcsqi": Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
,
3004 "bridge-mcmi": Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
,
3005 "bridge-mcqi": Link
.IFLA_BR_MCAST_QUERY_INTVL
,
3008 bridge_attributes_map
= dict(self
._ifla
_br
_attributes
_map
)
3010 del bridge_attributes_map
[Link
.IFLA_BR_STP_STATE
]
3017 cached_vlan_stats
= bridge_ifla_info_data
.get(Link
.IFLA_BR_VLAN_STATS_ENABLED
)
3019 if cached_vlan_stats
!= utils
.get_boolean_from_string(
3020 self
.get_mod_subattr("bridge-vlan-stats", "default")
3022 bridgeattrdict
['bridge-vlan-stats'] = ["on" if cached_vlan_stats
else "off"]
3025 del bridge_attributes_map
[Link
.IFLA_BR_VLAN_STATS_ENABLED
]
3029 lambda_nl_value_int_divide100
= lambda x
: str(x
// 100)
3030 lambda_nl_value_to_yes_no_boolean
= lambda x
: "yes" if x
else "no"
3032 bridge_attr_value_netlink_to_string_dict
= {
3033 Link
.IFLA_BR_VLAN_PROTOCOL
: lambda x
: x
.lower(), # return lower case vlan protocol
3034 Link
.IFLA_BR_AGEING_TIME
: lambda_nl_value_int_divide100
,
3035 Link
.IFLA_BR_MAX_AGE
: lambda_nl_value_int_divide100
,
3036 Link
.IFLA_BR_FORWARD_DELAY
: lambda_nl_value_int_divide100
,
3037 Link
.IFLA_BR_HELLO_TIME
: lambda_nl_value_int_divide100
,
3038 Link
.IFLA_BR_MCAST_MEMBERSHIP_INTVL
: lambda_nl_value_int_divide100
,
3039 Link
.IFLA_BR_MCAST_STARTUP_QUERY_INTVL
: lambda_nl_value_int_divide100
,
3040 Link
.IFLA_BR_MCAST_LAST_MEMBER_INTVL
: lambda_nl_value_int_divide100
,
3041 Link
.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
: lambda_nl_value_int_divide100
,
3042 Link
.IFLA_BR_MCAST_QUERIER_INTVL
: lambda_nl_value_int_divide100
,
3043 Link
.IFLA_BR_MCAST_QUERY_INTVL
: lambda_nl_value_int_divide100
,
3044 Link
.IFLA_BR_VLAN_FILTERING
: lambda_nl_value_to_yes_no_boolean
,
3045 Link
.IFLA_BR_MCAST_QUERY_USE_IFADDR
: lambda_nl_value_to_yes_no_boolean
,
3046 Link
.IFLA_BR_MCAST_SNOOPING
: lambda_nl_value_to_yes_no_boolean
,
3047 Link
.IFLA_BR_MCAST_QUERIER
: lambda_nl_value_to_yes_no_boolean
,
3048 Link
.IFLA_BR_MCAST_ROUTER
: lambda_nl_value_to_yes_no_boolean
,
3051 for attr_name
, attr_nl
in bridge_attributes_map
.items():
3052 default_value
= self
.get_mod_subattr(attr_name
, "default")
3053 cached_value
= bridge_ifla_info_data
.get(attr_nl
)
3055 if cached_value
is None:
3058 cached_value_string
= bridge_attr_value_netlink_to_string_dict
.get(attr_nl
, str)(cached_value
)
3060 if default_value
!= cached_value_string
:
3061 bridgeattrdict
[attr_name
] = [cached_value_string
]
3063 if bridge_vlan_aware
:
3066 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
,
3070 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
3073 bridgeattrdict
.update({k
: [v
] for k
, v
in list(bridgevidinfo
.items())
3076 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
3078 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
3080 if skip_kernel_stp_attrs
:
3081 return bridgeattrdict
3083 # Do this only for vlan-UNAWARE-bridge
3084 if ports
and not bridge_vlan_aware
:
3085 portconfig
= {'bridge-pathcosts' : '',
3086 'bridge-portprios' : '',
3087 'bridge-learning' : '',
3088 'bridge-unicast-flood' : '',
3089 'bridge-multicast-flood' : '',
3090 'bridge-broadcast-flood' : '',
3091 'bridge-arp-nd-suppress' : '',
3093 for p
, v
in list(ports
.items()):
3094 v
= str(self
.cache
.get_brport_cost(p
))
3095 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
3097 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
3099 v
= str(self
.cache
.get_brport_priority(p
))
3100 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
3102 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
3104 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_learning(p
))
3106 v
!= self
.get_mod_subattr('bridge-learning', 'default')):
3107 portconfig
['bridge-learning'] += ' %s=%s' %(p
, v
)
3109 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_unicast_flood(p
))
3111 v
!= self
.get_mod_subattr('bridge-unicast-flood',
3113 portconfig
['bridge-unicast-flood'] += ' %s=%s' %(p
, v
)
3115 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_multicast_flood(p
))
3117 v
!= self
.get_mod_subattr('bridge-multicast-flood',
3119 portconfig
['bridge-multicast-flood'] += ' %s=%s' %(p
, v
)
3121 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_broadcast_flood(p
))
3123 v
!= self
.get_mod_subattr('bridge-broadcast-flood',
3125 portconfig
['bridge-broadcast-flood'] += ' %s=%s' %(p
, v
)
3127 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_neigh_suppress(p
))
3129 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress',
3131 portconfig
['bridge-arp-nd-suppress'] += ' %s=%s' %(p
, v
)
3133 bridgeattrdict
.update({k
: [v
] for k
, v
in list(portconfig
.items())
3136 return bridgeattrdict
3138 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
3139 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
3140 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
3142 mcqs
= attrval
.split()
3144 mcqsout
= ' '.join(mcqs
)
3145 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
3146 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
3148 def _query_check_bridge_vidinfo(self
, ifname
, ifaceobj
, ifaceobjcurr
):
3152 bridge_port_vids_user_config
= ifaceobj
.get_attr_value_first("bridge-port-vids")
3153 if bridge_port_vids_user_config
:
3155 port_list
= self
.parse_port_list(ifname
, bridge_port_vids_user_config
)
3158 self
.log_warn("%s: could not parse 'bridge-port-vids %s'"
3159 % (ifname
, bridge_port_vids_user_config
))
3160 ifaceobjcurr
.update_config_with_status("bridge-port-vids", "ERROR", 1)
3164 for port_config
in port_list
:
3166 port
, vids_raw
= port_config
.split("=")
3167 packed_vids
= vids_raw
.split(",")
3169 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(port
)
3171 if not utils
.compare_ids(packed_vids
, running_vids
, pvid
=running_pvid
, expand_range
=False):
3174 except Exception as e
:
3175 self
.log_warn("%s: failure checking vid %s (%s)" % (ifname
, port_config
, str(e
)))
3177 ifaceobjcurr
.update_config_with_status("bridge-port-vids", bridge_port_vids_user_config
, error
)
3182 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
3184 portlist
= self
.parse_port_list(ifaceobj
.name
, attrval
)
3186 self
.log_warn('%s: could not parse \'bridge-port-pvids %s\''
3187 % (ifname
, attrval
))
3191 running_pvid_config
= []
3193 (port
, pvid
) = p
.split('=')
3194 running_pvid
, _
= self
.cache
.get_pvid_and_vids(port
)
3196 running_pvid_config
.append("%s=%s" % (port
, running_pvid
))
3198 if running_pvid
!= int(pvid
):
3201 ifaceobjcurr
.update_config_with_status(
3202 "bridge-port-pvids",
3203 " ".join(running_pvid_config
),
3207 vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
3209 ifaceobjcurr
.update_config_with_status(vids
[0], vids
[1], -1)
3211 def _query_check_snooping_wdefault(self
, ifaceobj
):
3212 if (ifupdownflags
.flags
.WITHDEFAULTS
3213 and not self
._vxlan
_bridge
_default
_igmp
_snooping
3214 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VXLAN
):
3215 ifaceobj
.replace_config('bridge-mcsnoop', 'no')
3217 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
3218 if not self
._is
_bridge
(ifaceobj
):
3221 ifname
= ifaceobj
.name
3223 if not self
.cache
.bridge_exists(ifname
):
3224 self
.logger
.info("%s: bridge: does not exist" % (ifname
))
3227 self
._query
_check
_snooping
_wdefault
(ifaceobj
)
3229 user_config_attributes
= self
.dict_key_subset(ifaceobj
.config
, self
.get_mod_attrs())
3231 # add default attributes if --with-defaults is set
3232 if ifupdownflags
.flags
.WITHDEFAULTS
and 'bridge-stp' not in user_config_attributes
:
3233 user_config_attributes
.append('bridge-stp')
3235 if not user_config_attributes
:
3238 if "bridge-ports" in user_config_attributes
:
3239 self
.query_check_bridge_ports(ifaceobj
, ifaceobjcurr
, self
.cache
.get_slaves(ifname
), ifaceobj_getfunc
)
3241 if "bridge-ports-condone-regex" in user_config_attributes
:
3242 ifaceobjcurr
.update_config_with_status(
3243 "bridge-ports-condone-regex",
3244 self
._get
_bridge
_port
_condone
_regex
(ifaceobj
, True),
3248 # Those attributes require separate handling
3249 filter_attributes
= [
3256 "bridge-port-pvids",
3257 "bridge-l2protocol-tunnel",
3258 "bridge-ports-condone-regex"
3261 ignore_attributes
= (
3262 # bridge-pvid and bridge-vids on a bridge does not correspond
3263 # directly to a running config on the bridge. They correspond to
3264 # default values for the bridge ports. And they are already checked
3265 # against running config of the bridge port and reported against a
3266 # bridge port. So, ignore these attributes under the bridge. Use '2'
3267 # for ignore today. XXX: '2' will be mapped to a defined value in
3268 # subsequent patches.
3270 "bridge-allow-untagged",
3272 for attr
in ignore_attributes
:
3273 if attr
in user_config_attributes
:
3274 ifaceobjcurr
.update_config_with_status(attr
, ifaceobj
.get_attr_value_first(attr
), 2)
3275 filter_attributes
.append(attr
)
3277 bridge_config
= set(user_config_attributes
).difference(filter_attributes
)
3278 cached_ifla_info_data
= self
.cache
.get_link_info_data(ifname
)
3280 self
._query
_check
_bridge
_attributes
(ifaceobj
, ifaceobjcurr
, bridge_config
, cached_ifla_info_data
)
3281 self
._query
_check
_brport
_attributes
_on
_bridge
(ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
)
3282 self
._query
_check
_bridge
_vidinfo
(ifname
, ifaceobj
, ifaceobjcurr
)
3283 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
3284 self
._query
_check
_l2protocol
_tunnel
_on
_bridge
(ifname
, ifaceobj
, ifaceobjcurr
)
3286 def _query_check_bridge_always_up(self
, ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
):
3287 bridge_always_up
= ifaceobj
.get_attr_value_first("bridge-always-up")
3289 if bridge_always_up
:
3290 bridge_config
.remove("bridge-always-up")
3292 if utils
.get_boolean_from_string(bridge_always_up
):
3294 link_exists
= self
.cache
.link_exists(self
.get_dummy_brport_name_for_bridge(ifname
))
3298 ifaceobjcurr
.update_config_with_status(
3300 "yes" if link_exists
else "no",
3304 def _query_check_bridge_attributes(self
, ifaceobj
, ifaceobjcurr
, bridge_config
, cached_ifla_info_data
):
3305 for attr
in list(bridge_config
):
3306 query_check_handler
, netlink_attr
= self
._bridge
_attribute
_query
_check
_handler
.get(attr
, (None, None))
3308 if callable(query_check_handler
):
3309 query_check_handler(attr
, ifaceobj
.get_attr_value_first(attr
), ifaceobjcurr
, cached_ifla_info_data
.get(netlink_attr
))
3310 bridge_config
.remove(attr
)
3312 self
._query
_check
_bridge
_always
_up
(ifaceobj
.name
, ifaceobj
, ifaceobjcurr
, bridge_config
)
3314 def _query_check_brport_attributes_on_bridge(self
, ifname
, ifaceobj
, ifaceobjcurr
, bridge_config
):
3315 brports_info_slave_data
= {}
3316 # bridge_config should only have bridge-port-list attributes
3317 for attr
in bridge_config
:
3318 attr_nl
= self
._ifla
_brport
_attributes
_map
.get(attr
)
3319 brport_query_check_handler
= self
._brport
_attribute
_query
_check
_handler
.get(attr
)
3321 if not attr_nl
or not brport_query_check_handler
:
3322 self
.logger
.warning("%s: query-check: missing handler for attribute: %s (%s)" % (ifname
, attr
, attr_nl
))
3328 for port_config
in self
.parse_port_list(ifname
, ifaceobj
.get_attr_value_first(attr
)) or []:
3329 port
, config
= port_config
.split("=")
3331 if not port
in brports_info_slave_data
:
3332 info_slave_data
= brports_info_slave_data
[port
] = self
.cache
.get_link_info_slave_data(port
)
3334 info_slave_data
= brports_info_slave_data
[port
]
3336 port_config
, port_status
= brport_query_check_handler(port
, config
, info_slave_data
.get(attr_nl
))
3338 running_config
.append(port_config
)
3343 ifaceobjcurr
.update_config_with_status(
3345 " ".join(running_config
),
3350 def _query_check_br_attr_wait(attr
, wait_value
, ifaceobjcurr
, __
):
3351 ifaceobjcurr
.update_config_with_status(attr
, wait_value
, 0)
3353 def _query_check_br_attr_stp(self
, attr
, stp_value
, ifaceobjcurr
, cached_value
):
3355 if ifupdownflags
.flags
.WITHDEFAULTS
:
3356 stp_value
= "on" if self
.default_stp_on
else "off"
3360 user_config_to_nl
= utils
.get_boolean_from_string(stp_value
)
3362 ifaceobjcurr
.update_config_with_status(
3364 "yes" if cached_value
else "no",
3365 user_config_to_nl
!= bool(cached_value
)
3369 def _query_check_br_attr_int(attr
, user_config
, ifaceobjcurr
, cached_value
):
3370 ifaceobjcurr
.update_config_with_status(
3373 int(user_config
) != cached_value
3377 def _query_check_br_attr_int_divided100(attr
, user_config
, ifaceobjcurr
, cached_value
):
3378 value
= cached_value
// 100
3379 ifaceobjcurr
.update_config_with_status(
3382 int(user_config
) != value
3386 def _query_check_br_attr_boolean(attr
, user_config
, ifaceobjcurr
, cached_value
):
3387 ifaceobjcurr
.update_config_with_status(
3389 "yes" if cached_value
else "no",
3390 utils
.get_boolean_from_string(user_config
) != cached_value
3394 def _query_check_br_attr_boolean_on_off(attr
, user_config
, ifaceobjcurr
, cached_value
):
3395 ifaceobjcurr
.update_config_with_status(
3397 "on" if cached_value
else "off",
3398 utils
.get_boolean_from_string(user_config
) != cached_value
3402 def _query_check_br_attr_string(attr
, user_config
, ifaceobjcurr
, cached_value
):
3403 ifaceobjcurr
.update_config_with_status(
3406 user_config
.lower() != cached_value
3410 def _query_check_brport_attr_boolean_on_off(port
, user_config
, cached_value
):
3411 return "%s=%s" % (port
, "on" if cached_value
else "off"), utils
.get_boolean_from_string(user_config
) != cached_value
3414 def _query_check_brport_attr_boolean_yes_no(port
, user_config
, cached_value
):
3415 return "%s=%s" % (port
, "yes" if cached_value
else "no"), utils
.get_boolean_from_string(user_config
) != cached_value
3418 def _query_check_brport_attr_int(port
, user_config
, cached_value
):
3419 return "%s=%s" % (port
, cached_value
), int(user_config
) != cached_value
3422 def _query_check_brport_attr_portmcrouter(cls
, port
, user_config
, cached_value
):
3424 "%s=%s" % (port
, cls
._ifla
_brport
_multicast
_router
_dict
_int
_to
_str
.get(cached_value
)),
3425 cls
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(user_config
) != cached_value
3428 ####################################################################################################################
3430 def query_check_bridge_ports(self
, ifaceobj
, ifaceobjcurr
, running_port_list
, ifaceobj_getfunc
):
3432 # if bridge-always-up is set we need to remove the dummy brport from the running_port_list
3433 if utils
.get_boolean_from_string(ifaceobj
.get_attr_value_first("bridge-always-up")):
3435 running_port_list
.remove(self
.get_dummy_brport_name_for_bridge(ifaceobj
.name
))
3439 bridge_all_ports
= []
3440 for obj
in ifaceobj_getfunc(ifaceobj
.name
) or []:
3441 bridge_all_ports
.extend(self
._get
_bridge
_port
_list
(obj
) or [])
3443 if not running_port_list
and not bridge_all_ports
:
3447 port_list
= self
._get
_ifaceobj
_bridge
_ports
(ifaceobj
).split()
3448 # we want to display the same bridge-ports list as provided
3449 # in the interfaces file but if this list contains regexes or
3450 # globs, for now, we won't try to change it.
3451 if 'regex' in port_list
or 'glob' in port_list
:
3452 port_list
= running_port_list
3455 for i
in range(0, len(port_list
)):
3456 if port_list
[i
] in running_port_list
:
3457 ordered
.append(port_list
[i
])
3460 port_list
= running_port_list
3462 difference
= set(running_port_list
).symmetric_difference(bridge_all_ports
)
3463 bridge_port_condone_regex
= self
._get
_bridge
_port
_condone
_regex
(ifaceobj
)
3465 if bridge_port_condone_regex
:
3466 # Drop any condoned port from the difference set
3467 condone_ports
= [port
for port
in difference
if bridge_port_condone_regex
.match(port
)]
3469 for port
in condone_ports
:
3471 difference
.remove(port
)
3475 # Tag all condoned ports in brackets in output
3476 if port
not in bridge_all_ports
:
3477 port_list
.append("(%s)" % port
)
3479 ifaceobjcurr
.update_config_with_status(
3481 " ".join(port_list
) if port_list
else "",
3482 0 if not difference
else 1
3485 def get_ifaceobj_bridge_vids(self
, ifaceobj
):
3486 vids
= ('bridge-vids', ifaceobj
.get_attr_value_first('bridge-vids'))
3488 vids
= ('bridge-trunk', ifaceobj
.get_attr_value_first('bridge-trunk'))
3491 def get_ifaceobj_bridge_vids_value(self
, ifaceobj
):
3492 return self
.get_ifaceobj_bridge_vids(ifaceobj
)[1]
3494 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
3495 ifaceobjs
= ifaceobj_getfunc(bridgename
)
3496 for ifaceobj
in ifaceobjs
:
3497 vids
= self
.get_ifaceobj_bridge_vids_value(ifaceobj
)
3498 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
3501 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
3502 ifaceobjs
= ifaceobj_getfunc(bridgename
)
3504 for ifaceobj
in ifaceobjs
:
3505 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
3510 def _query_check_bridge_port_vidinfo(self
, ifname
, bridge_name
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
):
3511 running_pvid
, running_vids
= self
.cache
.get_pvid_and_vids(ifname
)
3513 if (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.SINGLE_VXLAN
):
3519 brport_vid_access_user_config
= ifaceobj
.get_attr_value_first("bridge-access")
3521 if brport_vid_access_user_config
:
3523 vid_int
= int(brport_vid_access_user_config
)
3524 except ValueError as e
:
3525 ifaceobjcurr
.update_config_with_status("bridge-access", brport_vid_access_user_config
, 1)
3526 raise Exception("%s: bridge-access invalid value: %s" % (ifname
, str(e
)))
3528 ifaceobjcurr
.update_config_with_status(
3531 running_pvid
!= vid_int
or running_vids
[0] != vid_int
3538 brport_pvid_user_config
= ifaceobj
.get_attr_value_first("bridge-pvid")
3540 if brport_pvid_user_config
:
3542 pvid
= int(brport_pvid_user_config
)
3543 except ValueError as e
:
3544 ifaceobjcurr
.update_config_with_status("bridge-pvid", brport_pvid_user_config
, 1)
3545 raise Exception("%s: bridge-pvid invalid value: %s" % (ifname
, str(e
)))
3547 ifaceobjcurr
.update_config_with_status(
3550 running_pvid
!= pvid
3552 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
3553 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
3554 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
3555 # if the interface has multiple iface sections,
3556 # we check the below only for the oldest sibling
3557 # or the last iface section
3559 pvid
= int(self
._get
_bridge
_pvid
(bridge_name
, ifaceobj_getfunc
))
3560 except (TypeError, ValueError):
3563 if not running_pvid
or running_pvid
!= pvid
:
3564 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3565 ifaceobjcurr
.status_str
= 'bridge pvid error'
3566 elif not running_pvid
or running_pvid
!= 1:
3567 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3568 ifaceobjcurr
.status_str
= 'bridge pvid error'
3570 attr_name
, vids
= self
.get_ifaceobj_bridge_vids(ifaceobj
)
3572 vids
= re
.split(r
'[\s\t]\s*', vids
)
3574 # Special treatment to make sure that the vlans mapped with vnis
3575 # (in single-vxlan context) are not mistaken for regular vlans.
3576 # We need to proactively remove them from the "running_vids"
3577 vlans_mapped_with_vnis
= self
.get_bridge_vlans_mapped_to_vnis_as_integer_list(ifaceobj
)
3578 new_running_vids
= []
3579 user_config_vids
= utils
.ranges_to_ints(vids
)
3580 for v
in running_vids
:
3581 if v
in user_config_vids
:
3582 new_running_vids
.append(v
)
3583 elif v
not in vlans_mapped_with_vnis
:
3584 new_running_vids
.append(v
)
3585 running_vids
= new_running_vids
3586 #####################################################################
3588 if not running_vids
or not utils
.compare_ids(vids
, running_vids
, running_pvid
, expand_range
=False):
3589 running_vids
= [str(o
) for o
in running_vids
]
3590 ifaceobjcurr
.update_config_with_status(attr_name
,
3591 ' '.join(running_vids
), 1)
3593 ifaceobjcurr
.update_config_with_status(attr_name
,
3595 elif (not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
) or
3596 ((ifaceobj
.flags
& iface
.HAS_SIBLINGS
) and
3597 (ifaceobj
.flags
& iface
.OLDEST_SIBLING
))):
3598 # if the interface has multiple iface sections,
3599 # we check the below only for the oldest sibling
3600 # or the last iface section
3602 # check if it matches the bridge vids
3603 bridge_vids
= self
._get
_bridge
_vids
(bridge_name
, ifaceobj_getfunc
)
3604 if (bridge_vids
and (not running_vids
or
3605 not utils
.compare_ids(bridge_vids
, running_vids
, running_pvid
, expand_range
=False))):
3606 ifaceobjcurr
.status
= ifaceStatus
.ERROR
3607 ifaceobjcurr
.status_str
= 'bridge vid error'
3609 _query_check_brport_attributes
= (
3616 "bridge-portmcrouter",
3619 "bridge-unicast-flood",
3620 "bridge-multicast-flood",
3621 "bridge-broadcast-flood",
3622 "bridge-arp-nd-suppress",
3623 "bridge-l2protocol-tunnel"
3626 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
3629 ifname
= ifaceobj
.name
3631 if not self
.cache
.link_is_bridge_port(ifname
):
3632 # Mark all bridge brport attributes as failed
3633 ifaceobjcurr
.check_n_update_config_with_status_many(
3634 ifaceobj
, self
._query
_check
_brport
_attributes
, 1
3638 bridge_name
= self
.cache
.get_bridge_name_from_port(ifname
)
3640 self
.logger
.warning("%s: unable to determine bridge name" % ifname
)
3643 if self
.cache
.bridge_is_vlan_aware(bridge_name
):
3644 self
._query
_check
_bridge
_port
_vidinfo
(ifname
, bridge_name
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
3646 brport_info_slave_data
= self
.cache
.get_link_info_slave_data(ifname
)
3651 portmcfl
= ifaceobj
.get_attr_value_first("bridge-portmcfl")
3654 cached_value
= brport_info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
)
3656 ifaceobjcurr
.update_config_with_status(
3658 "yes" if cached_value
else "no",
3659 utils
.get_boolean_from_string(portmcfl
) != cached_value
3663 # bridge-portmcrouter
3665 portmcrouter
= ifaceobj
.get_attr_value_first("bridge-portmcrouter")
3668 cached_value
= brport_info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
)
3670 ifaceobjcurr
.update_config_with_status(
3671 "bridge-portmcrouter",
3672 self
._ifla
_brport
_multicast
_router
_dict
_int
_to
_str
.get(cached_value
),
3673 self
._ifla
_brport
_multicast
_router
_dict
_to
_int
.get(portmcrouter
) != cached_value
3678 # bridge-unicast-flood
3679 # bridge-multicast-flood
3680 # bridge-broadcast-flood
3681 # bridge-arp-nd-suppress
3683 for attr_name
, attr_nl
in (
3684 ("bridge-learning", Link
.IFLA_BRPORT_LEARNING
),
3685 ("bridge-unicast-flood", Link
.IFLA_BRPORT_UNICAST_FLOOD
),
3686 ("bridge-multicast-flood", Link
.IFLA_BRPORT_MCAST_FLOOD
),
3687 ("bridge-broadcast-flood", Link
.IFLA_BRPORT_BCAST_FLOOD
),
3688 ("bridge-arp-nd-suppress", Link
.IFLA_BRPORT_NEIGH_SUPPRESS
),
3690 attribute_value
= ifaceobj
.get_attr_value_first(attr_name
)
3692 if not attribute_value
:
3695 cached_value
= brport_info_slave_data
.get(attr_nl
)
3697 ifaceobjcurr
.update_config_with_status(
3699 "on" if cached_value
else "off",
3700 utils
.get_boolean_from_string(attribute_value
) != cached_value
3707 for attr_name
, attr_nl
in (
3708 ("bridge-pathcosts", Link
.IFLA_BRPORT_COST
),
3709 ("bridge-portprios", Link
.IFLA_BRPORT_PRIORITY
),
3711 attribute_value
= ifaceobj
.get_attr_value_first(attr_name
)
3713 if not attribute_value
:
3716 cached_value
= brport_info_slave_data
.get(attr_nl
)
3719 ifaceobjcurr
.update_config_with_status(
3722 int(attribute_value
) != cached_value
3724 except ValueError as e
:
3725 ifaceobjcurr
.update_config_with_status(attr_name
, str(cached_value
), 1)
3726 raise Exception("%s: %s invalid value: %s" % (ifname
, attr_name
, str(e
)))
3728 self
._query
_check
_l2protocol
_tunnel
_on
_port
(ifaceobj
, ifaceobjcurr
)
3731 # bridge-vlan-vni-map
3733 cached_vlans
, cached_vnis
= self
.get_vlan_vni_ranges(self
.cache
.get_vlan_vni(ifaceobj
.name
))
3735 for bridge_vlan_vni_map_entry
in ifaceobj
.get_attr_value("bridge-vlan-vni-map") or []:
3738 for vlan_vni
in bridge_vlan_vni_map_entry
.split():
3740 vlans_str
, vni_str
= utils
.get_vlan_vni_in_map_entry(vlan_vni
)
3743 self
.__warn
_bridge
_vlan
_vni
_map
_syntax
_error
(ifname
, vlan_vni
)
3747 # if we already have detected an error on this entry there's
3748 # no point doing anything else than syntax check on the rest
3751 vlans_list
= utils
.ranges_to_ints([vlans_str
])
3752 vnis_list
= utils
.ranges_to_ints([vni_str
])
3755 for i
, vlan
in enumerate(vlans_list
):
3756 index
= cached_vnis
.index(vlan
)
3758 if vlan
!= cached_vnis
[index
] or vnis_list
[i
] != cached_vlans
[index
]:
3763 ifaceobjcurr
.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map_entry
, fail
)
3766 def get_vlan_vni_ranges(bridge_vlan_tunnel
, compress
=False):
3770 if not bridge_vlan_tunnel
:
3773 tunnel_vlan_range
= None
3774 tunnel_vni_range
= None
3776 for tunnel_vlan
, tunnel_vni
, tunnel_flags
in bridge_vlan_tunnel
:
3778 if tunnel_flags
& Link
.BRIDGE_VLAN_INFO_RANGE_BEGIN
:
3779 tunnel_vlan_range
= tunnel_vlan
3780 tunnel_vni_range
= tunnel_vni
3782 elif tunnel_flags
& Link
.BRIDGE_VLAN_INFO_RANGE_END
:
3785 vlans
.append("%s-%s" % (tunnel_vlan_range
, tunnel_vlan
))
3786 vnis
.append("%s-%s" % (tunnel_vni_range
, tunnel_vni
))
3788 vlans
.extend(range(tunnel_vlan_range
, tunnel_vlan
+ 1))
3789 vnis
.extend(range(tunnel_vni_range
, tunnel_vni
+ 1))
3792 vlans
.append(tunnel_vlan
)
3793 vnis
.append(tunnel_vni
)
3797 def _query_check_l2protocol_tunnel_on_port(self
, ifaceobj
, ifaceobjcurr
):
3798 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
3800 if user_config_l2protocol_tunnel
:
3803 self
._query
_check
_l2protocol
_tunnel
(ifaceobj
.name
, user_config_l2protocol_tunnel
)
3804 except Exception as e
:
3805 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
3807 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
3809 def _query_check_l2protocol_tunnel_on_bridge(self
, ifname
, ifaceobj
, ifaceobjcurr
):
3811 In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
3812 We need to make sure that all ports comply with the mask given under the bridge
3814 user_config_l2protocol_tunnel
= ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
3816 if user_config_l2protocol_tunnel
:
3817 if '=' in user_config_l2protocol_tunnel
:
3819 config_per_port_dict
= self
.parse_interface_list_value(user_config_l2protocol_tunnel
)
3820 brport_list
= list(config_per_port_dict
.keys())
3822 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, 1)
3825 config_per_port_dict
= {}
3826 brport_list
= self
.cache
.get_slaves(ifname
)
3829 for brport_name
in brport_list
:
3830 self
._query
_check
_l2protocol
_tunnel
(
3832 config_per_port_dict
.get(brport_name
) if config_per_port_dict
else user_config_l2protocol_tunnel
3835 except Exception as e
:
3836 self
.logger
.debug('query: %s: %s' % (ifaceobj
.name
, str(e
)))
3838 ifaceobjcurr
.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel
, result
)
3840 def _query_check_l2protocol_tunnel(self
, brport_name
, user_config_l2protocol_tunnel
):
3841 cached_ifla_brport_group_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
3842 cached_ifla_brport_group_mask
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASK
)
3844 for protocol
in re
.split(',|\s*', user_config_l2protocol_tunnel
):
3845 callback
= self
.query_check_l2protocol_tunnel_callback
.get(protocol
)
3847 if callable(callback
):
3848 if not callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3849 raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
3850 % (brport_name
, protocol
, cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
))
3852 def _query_running_bridge_l2protocol_tunnel(self
, brport_name
, brport_ifaceobj
=None, bridge_ifaceobj
=None):
3853 cached_ifla_brport_group_maskhi
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASKHI
)
3854 cached_ifla_brport_group_mask
= self
.cache
.get_link_info_slave_data_attribute(brport_name
, Link
.IFLA_BRPORT_GROUP_FWD_MASK
)
3855 running_protocols
= []
3856 for protocol_name
, callback
in list(self
.query_check_l2protocol_tunnel_callback
.items()):
3857 if protocol_name
== 'all' and callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3858 running_protocols
= list(self
.query_check_l2protocol_tunnel_callback
.keys())
3859 running_protocols
.remove('all')
3861 elif callback(cached_ifla_brport_group_mask
, cached_ifla_brport_group_maskhi
):
3862 running_protocols
.append(protocol_name
)
3863 if running_protocols
:
3865 brport_ifaceobj
.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols
))
3866 elif bridge_ifaceobj
:
3867 current_config
= bridge_ifaceobj
.get_attr_value_first('bridge-l2protocol-tunnel')
3870 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config
, brport_name
, ','.join(running_protocols
)))
3872 bridge_ifaceobj
.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name
, ','.join(running_protocols
)))
3874 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
3875 if self
._is
_bridge
(ifaceobj
):
3876 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
3878 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
3881 def _query_running_bridge(self
, ifaceobjrunning
, ifaceobj_getfunc
):
3882 if self
.cache
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
3883 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
3884 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
3887 bridge_vlan_aware
=True))
3889 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
3890 ifaceobjrunning
, None))
3892 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
3893 if self
.systcl_get_net_bridge_stp_user_space() == '1':
3896 v
= str(self
.cache
.get_brport_cost(ifaceobjrunning
.name
))
3897 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
3898 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
3900 v
= str(self
.cache
.get_brport_priority(ifaceobjrunning
.name
))
3901 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
3902 ifaceobjrunning
.update_config('bridge-portprios', v
)
3904 def _query_running_bridge_port(self
, ifaceobjrunning
,
3905 ifaceobj_getfunc
=None):
3907 bridgename
= self
.cache
.get_bridge_name_from_port(
3908 ifaceobjrunning
.name
)
3912 self
.logger
.warning('%s: unable to find bridgename'
3913 %ifaceobjrunning
.name
)
3916 if not self
.cache
.bridge_is_vlan_aware(bridgename
):
3918 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, bridge_ifaceobj
=ifaceobj_getfunc(bridgename
)[0])
3919 except Exception as e
:
3920 self
.logger
.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning
.name
, str(e
)))
3923 self
._query
_running
_bridge
_l2protocol
_tunnel
(ifaceobjrunning
.name
, brport_ifaceobj
=ifaceobjrunning
)
3925 (bridge_port_vids
, bridge_port_pvid
) = self
._get
_running
_vids
_n
_pvid
_str
(
3926 ifaceobjrunning
.name
)
3927 if bridge_port_vids
and bridge_port_pvid
in bridge_port_vids
:
3928 bridge_port_vids
.remove(bridge_port_pvid
)
3930 bridgeifaceobjlist
= ifaceobj_getfunc(bridgename
)
3931 if bridgeifaceobjlist
:
3932 bridge_vids
= bridgeifaceobjlist
[0].get_attr_value('bridge-vids')
3933 bridge_pvid
= bridgeifaceobjlist
[0].get_attr_value_first('bridge-pvid')
3935 if not bridge_port_vids
and bridge_port_pvid
:
3936 # must be an access port
3937 if bridge_port_pvid
!= '1':
3938 ifaceobjrunning
.update_config('bridge-access',
3941 if bridge_port_vids
:
3942 if (not bridge_vids
or bridge_port_vids
!= bridge_vids
):
3943 ifaceobjrunning
.update_config('bridge-vids',
3944 ' '.join(bridge_port_vids
))
3945 if bridge_port_pvid
and bridge_port_pvid
!= '1':
3946 if (not bridge_pvid
or (bridge_port_pvid
!= bridge_pvid
)):
3947 ifaceobjrunning
.update_config('bridge-pvid',
3950 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_learning(ifaceobjrunning
.name
))
3951 if v
and v
!= self
.get_mod_subattr('bridge-learning', 'default'):
3952 ifaceobjrunning
.update_config('bridge-learning', v
)
3954 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_unicast_flood(ifaceobjrunning
.name
))
3955 if v
and v
!= self
.get_mod_subattr('bridge-unicast-flood', 'default'):
3956 ifaceobjrunning
.update_config('bridge-unicast-flood', v
)
3958 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_multicast_flood(ifaceobjrunning
.name
))
3959 if v
and v
!= self
.get_mod_subattr('bridge-multicast-flood', 'default'):
3960 ifaceobjrunning
.update_config('bridge-multicast-flood', v
)
3962 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_broadcast_flood(ifaceobjrunning
.name
))
3963 if v
and v
!= self
.get_mod_subattr('bridge-broadcast-flood', 'default'):
3964 ifaceobjrunning
.update_config('bridge-broadcast-flood', v
)
3966 v
= utils
.get_onff_from_onezero(self
.cache
.get_brport_neigh_suppress(ifaceobjrunning
.name
))
3967 # Display running 'arp-nd-suppress' only on vxlan ports
3968 # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
3969 # otherwise, display on all bridge-ports
3971 bportifaceobj
= ifaceobj_getfunc(ifaceobjrunning
.name
)[0]
3973 v
!= self
.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
3974 (not self
.arp_nd_suppress_only_on_vxlan
or
3975 (self
.arp_nd_suppress_only_on_vxlan
and
3976 bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
))):
3977 ifaceobjrunning
.update_config('bridge-arp-nd-suppress', v
)
3979 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
3982 # bridge-vlan-vni-map
3985 # there's a mix-up vlan_vni should return vlans/vnis and not vnis/vlans
3986 # ifquery-check is also using this function and has already code to work
3987 # around the issue, so to fix our ordering problem we will simply and
3988 # temporarily, swap the two return values
3989 cached_vnis
, cached_vlans
= self
.get_vlan_vni_ranges(
3990 self
.cache
.get_vlan_vni(ifaceobjrunning
.name
), compress
=True
3993 if cached_vlans
and cached_vnis
:
3994 ifaceobjrunning
.update_config(
3995 "bridge-vlan-vni-map",
3996 " ".join(["%s=%s" % (vlan
, vni
) for vlan
, vni
in zip(cached_vlans
, cached_vnis
)])
3998 except Exception as e
:
3999 self
.logger
.debug("bridge-vlan-vni-map: exception: %s" % str(e
))
4001 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
4003 if self
.cache
.bridge_exists(ifaceobjrunning
.name
):
4004 self
._query
_running
_bridge
(ifaceobjrunning
, ifaceobj_getfunc
)
4005 elif self
.cache
.link_is_bridge_port(ifaceobjrunning
.name
):
4006 self
._query
_running
_bridge
_port
(ifaceobjrunning
, ifaceobj_getfunc
)
4007 except Exception as e
:
4008 raise Exception('%s: %s' % (ifaceobjrunning
.name
, str(e
)))
4010 def _query(self
, ifaceobj
, **kwargs
):
4011 """ add default policy attributes supported by the module """
4013 if self
.bridge_vxlan_arp_nd_suppress \
4014 and ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT \
4015 and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
4016 ifaceobj
.update_config("bridge-arp-nd-suppress", "on")
4018 if (not (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
) or
4019 ifaceobj
.get_attr_value_first('bridge-stp')):
4021 if self
.default_stp_on
:
4022 ifaceobj
.update_config('bridge-stp', 'yes')
4028 'query-checkcurr': _query_check
,
4029 'query-running': _query_running
,
4034 """ returns list of ops supported by this module """
4035 return list(self
._run
_ops
.keys())
4037 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
4038 """ run bridge configuration on the interface object passed as
4039 argument. Can create bridge interfaces if they dont exist already
4042 **ifaceobj** (object): iface object
4044 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
4048 **query_ifaceobj** (object): query check ifaceobject. This is only
4049 valid when op is 'query-checkcurr'. It is an object same as
4050 ifaceobj, but contains running attribute values and its config
4051 status. The modules can use it to return queried running state
4052 of interfaces. status is success if the running state is same
4053 as user required state in ifaceobj. error otherwise.
4055 op_handler
= self
._run
_ops
.get(operation
)
4059 if (not self
.requirements
.bridge_utils_is_installed
4060 and (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
or ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
)
4061 and self
.bridge_utils_missing_warning
):
4062 self
.logger
.warning('%s: missing - bridge operation may not work as expected. '
4063 'Please check if \'bridge-utils\' package is installed' % utils
.brctl_cmd
)
4064 self
.bridge_utils_missing_warning
= False
4066 # make sure BRIDGE_VXLAN is set if we have a vxlan port
4067 self
._re
_evaluate
_bridge
_vxlan
(ifaceobj
, ifaceobj_getfunc
)
4069 if operation
== 'query-checkcurr':
4070 op_handler(self
, ifaceobj
, query_ifaceobj
,
4071 ifaceobj_getfunc
=ifaceobj_getfunc
)
4073 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)