]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - ifupdown2/addons/bridge.py
addons: bridge: check kernel state for igmp snooping on vxlan brport
[mirror_ifupdown2.git] / ifupdown2 / addons / bridge.py
index ebc9fbf18402bf747978f678d4f8fa882792f28b..9677b3bc1d2d08561bbec3206561daf0bb8ffa7b 100644 (file)
@@ -1,19 +1,50 @@
 #!/usr/bin/python
 #
-# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
+# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
 #
 
-from sets import Set
-from ifupdown.iface import *
-from ifupdownaddons.modulebase import moduleBase
-from ifupdownaddons.bridgeutils import brctl
-from ifupdownaddons.iproute2 import iproute2
-from collections import Counter
-import ifupdown.rtnetlink_api as rtnetlink_api
-import itertools
 import re
 import time
+import itertools
+
+from sets import Set
+from collections import Counter
+
+try:
+    import ifupdown2.ifupdown.exceptions as exceptions
+    import ifupdown2.ifupdown.policymanager as policymanager
+    import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
+
+    from ifupdown2.nlmanager.nlmanager import Link
+
+    from ifupdown2.ifupdown.iface import *
+    from ifupdown2.ifupdown.utils import utils
+    from ifupdown2.ifupdown.netlink import netlink
+
+    from ifupdown2.ifupdownaddons.cache import *
+    from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
+    from ifupdown2.ifupdownaddons.modulebase import moduleBase
+except ImportError:
+    import ifupdown.exceptions as exceptions
+    import ifupdown.policymanager as policymanager
+    import ifupdown.ifupdownflags as ifupdownflags
+
+    from nlmanager.nlmanager import Link
+
+    from ifupdown.iface import *
+    from ifupdown.utils import utils
+    from ifupdown.netlink import netlink
+
+    from ifupdownaddons.cache import *
+    from ifupdownaddons.LinkUtils import LinkUtils
+    from ifupdownaddons.modulebase import moduleBase
+
+
+class bridgeFlags:
+    PORT_PROCESSED = 0x1
+    PORT_PROCESSED_OVERRIDE = 0x2
+
 
 class bridge(moduleBase):
     """  ifupdown2 addon module to configure linux bridges """
@@ -29,10 +60,15 @@ class bridge(moduleBase):
                         {'help' : 'vlan aware bridge. Setting this ' +
                                   'attribute to yes enables vlan filtering' +
                                   ' on the bridge',
-                         'example' : ['bridge-vlan-aware yes/no']},
+                         'validvals' : ['yes', 'no'],
+                         'example' : ['bridge-vlan-aware yes/no'],
+                         'default': 'no'
+                         },
                    'bridge-ports' :
                         {'help' : 'bridge ports',
+                         'multivalue' : True,
                          'required' : True,
+                         'validvals': ['<interface-list>', 'none'],
                          'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
                                       'bridge-ports glob swp1-3.100',
                                       'bridge-ports regex (swp[1|2|3].100)']},
@@ -43,107 +79,150 @@ class bridge(moduleBase):
                          'default' : 'no'},
                    'bridge-bridgeprio' :
                         {'help': 'bridge priority',
+                         'validrange' : ['0', '65535'],
                          'example' : ['bridge-bridgeprio 32768'],
                          'default' : '32768'},
                    'bridge-ageing' :
                        {'help': 'bridge ageing',
+                         'validrange' : ['0', '65535'],
                          'example' : ['bridge-ageing 300'],
                          'default' : '300'},
                    'bridge-fd' :
                         { 'help' : 'bridge forward delay',
+                          'validrange' : ['0', '255'],
                           'example' : ['bridge-fd 15'],
                           'default' : '15'},
                    'bridge-gcint' :
                         # XXX: recheck values
                         { 'help' : 'bridge garbage collection interval in secs',
+                          'validrange' : ['0', '255'],
                           'example' : ['bridge-gcint 4'],
-                          'default' : '4'},
+                          'default' : '4',
+                          'compat' : True,
+                          'deprecated': True},
                    'bridge-hello' :
                         { 'help' : 'bridge set hello time',
+                          'validrange' : ['0', '255'],
                           'example' : ['bridge-hello 2'],
                           'default' : '2'},
                    'bridge-maxage' :
                         { 'help' : 'bridge set maxage',
+                          'validrange' : ['0', '255'],
                           'example' : ['bridge-maxage 20'],
                           'default' : '20'},
                    'bridge-pathcosts' :
                         { 'help' : 'bridge set port path costs',
-                          'example' : ['bridge-pathcosts swp1=100 swp2=100'],
+                          'validvals': ['<interface-range-list>'],
+                          'validrange' : ['0', '65535'],
+                          'example' : ['under the port (for vlan aware bridge): bridge-pathcosts 100',
+                                       'under the bridge (for vlan unaware bridge): bridge-pathcosts swp1=100 swp2=100'],
                           'default' : '100'},
                    'bridge-portprios' :
                         { 'help' : 'bridge port prios',
-                          'example' : ['bridge-portprios swp1=32 swp2=32'],
+                          'validvals': ['<interface-range-list>'],
+                          'validrange' : ['0', '65535'],
+                          'example' : ['under the port (for vlan aware bridge): bridge-portprios 32',
+                                       'under the bridge (for vlan unaware bridge): bridge-portprios swp1=32 swp2=32'],
                           'default' : '32'},
                    'bridge-mclmc' :
                         { 'help' : 'set multicast last member count',
+                          'validrange' : ['0', '255'],
                           'example' : ['bridge-mclmc 2'],
                           'default' : '2'},
                     'bridge-mcrouter' :
-                        { 'help' : 'set multicast router',
-                          'default' : '1',
-                          'example' : ['bridge-mcrouter 1']},
+                        { 'help': 'Set bridge multicast routers: 0 - disabled - no, 1 - automatic (queried), 2 - permanently enabled - yes',
+                          'validvals' : ['yes', 'no', '0', '1', '2'],
+                          'example' : ['bridge-mcrouter 1'],
+                          'default': 'yes'
+                          },
                     'bridge-mcsnoop' :
                         { 'help' : 'set multicast snooping',
-                          'default' : '1',
-                          'example' : ['bridge-mcsnoop 1']},
+                          'validvals' : ['yes', 'no', '0', '1'],
+                          'default' : 'yes',
+                          'example' : ['bridge-mcsnoop yes']},
                     'bridge-mcsqc' :
                         { 'help' : 'set multicast startup query count',
+                          'validrange' : ['0', '255'],
                           'default' : '2',
                           'example' : ['bridge-mcsqc 2']},
                     'bridge-mcqifaddr' :
                         { 'help' : 'set multicast query to use ifaddr',
-                          'default' : '0',
-                          'example' : ['bridge-mcqifaddr 0']},
+                          'validvals' : ['yes', 'no', '0', '1'],
+                          'default' : 'no',
+                          'example' : ['bridge-mcqifaddr no']},
                     'bridge-mcquerier' :
                         { 'help' : 'set multicast querier',
-                          'default' : '0',
-                          'example' : ['bridge-mcquerier 0']},
+                          'validvals' : ['yes', 'no', '0', '1'],
+                          'default' : 'no',
+                          'example' : ['bridge-mcquerier no']},
                     'bridge-hashel' :
                         { 'help' : 'set hash elasticity',
-                          'default' : '4096',
+                          'validrange' : ['0', '4096'],
+                          'default' : '4',
                           'example' : ['bridge-hashel 4096']},
                     'bridge-hashmax' :
                         { 'help' : 'set hash max',
-                          'default' : '4096',
+                          'validrange' : ['0', '4096'],
+                          'default' : '512',
                           'example' : ['bridge-hashmax 4096']},
                     'bridge-mclmi' :
                         { 'help' : 'set multicast last member interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '1',
                           'example' : ['bridge-mclmi 1']},
                     'bridge-mcmi' :
                         { 'help' : 'set multicast membership interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '260',
                           'example' : ['bridge-mcmi 260']},
                     'bridge-mcqpi' :
                         { 'help' : 'set multicast querier interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '255',
                           'example' : ['bridge-mcqpi 255']},
                     'bridge-mcqi' :
                         { 'help' : 'set multicast query interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '125',
                           'example' : ['bridge-mcqi 125']},
                     'bridge-mcqri' :
                         { 'help' : 'set multicast query response interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '10',
                           'example' : ['bridge-mcqri 10']},
                     'bridge-mcsqi' :
                         { 'help' : 'set multicast startup query interval (in secs)',
+                          'validrange' : ['0', '255'],
                           'default' : '31',
                           'example' : ['bridge-mcsqi 31']},
                     'bridge-mcqv4src' :
                         { 'help' : 'set per VLAN v4 multicast querier source address',
+                          'validvals' : ['<number-ipv4-list>', ],
+                          'multivalue' : True,
                           'compat' : True,
                           'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
-                    'bridge-portmcrouter' :
-                        { 'help' : 'set port multicast routers',
-                          'default' : '1',
-                          'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
-                                       'under the port: bridge-portmcrouter 1']},
+                     'bridge-portmcrouter':
+                         {
+                             'help': 'Set port multicast routers: 0 - disabled, 1 - automatic (queried), 2 - permanently enabled',
+                             'validvals': ['<interface-disabled-automatic-enabled>'],
+                             'example': [
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter 0',
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter 1',
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter 2',
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter disabled',
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter automatic',
+                                 'under the port (for vlan aware bridge): bridge-portmcrouter enabled',
+                                 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=0 swp2=1 swp2=2',
+                                 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=disabled swp2=automatic swp3=enabled',
+                                 'under the bridge (for vlan unaware bridge): bridge-portmcrouter swp1=2 swp2=disabled swp3=1',
+                             ]
+                         },
                     'bridge-portmcfl' :
                         { 'help' : 'port multicast fast leave.',
-                          'default' : '0',
-                          'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
-                                       'under the port: bridge-portmcfl 0']},
+                          'validvals': ['<interface-yes-no-0-1-list>'],
+                          'default' : 'no',
+                          'example' : ['under the port (for vlan aware bridge): bridge-portmcfl no',
+                                       'under the bridge (for vlan unaware bridge): bridge-portmcfl swp1=no swp2=no']},
                     'bridge-waitport' :
                         { 'help' : 'wait for a max of time secs for the' +
                                 ' specified ports to become available,' +
@@ -154,14 +233,16 @@ class bridge(moduleBase):
                                 'regex or \"all\" on bridge_ports,' +
                                 'as it wouldnt work.',
                           'default' : '0',
+                          'validvals': ['<number-interface-list>'],
                           'example' : ['bridge-waitport 4 swp1 swp2']},
                     'bridge-maxwait' :
                         { 'help' : 'forces to time seconds the maximum time ' +
-                                'that the Debian bridge setup  scripts will ' +
+                                'that the Debian bridge setup scripts will ' +
                                 'wait for the bridge ports to get to the ' +
                                 'forwarding status, doesn\'t allow factional ' +
                                 'part. If it is equal to 0 then no waiting' +
                                 ' is done',
+                          'validrange' : ['0', '255'],
                           'default' : '0',
                           'example' : ['bridge-maxwait 3']},
                     'bridge-vids' :
@@ -169,17 +250,30 @@ class bridge(moduleBase):
                                    'under the bridge or under the port. ' +
                                    'If specified under the bridge the ports ' +
                                    'inherit it unless overridden by a ' +
-                                   'bridge-vids attribuet under the port',
+                                   'bridge-vids attribute under the port',
+                          'multivalue' : True,
+                          'validvals': ['<number-comma-range-list>'],
                           'example' : ['bridge-vids 4000',
-                                       'bridge-vids 2000 2200-3000']},
+                                       'bridge-vids 2000 2200-3000'],
+                          'aliases': ['bridge-trunk']},
                     'bridge-pvid' :
                         { 'help' : 'bridge port pvid. Must be specified under' +
                                    ' the bridge port',
+                          'validrange' : ['0', '4096'],
                           'example' : ['bridge-pvid 1']},
                     'bridge-access' :
                         { 'help' : 'bridge port access vlan. Must be ' +
                                    'specified under the bridge port',
+                          'validrange' : ['1', '4094'],
                           'example' : ['bridge-access 300']},
+                    'bridge-allow-untagged' :
+                        { 'help' : 'indicate if the bridge port accepts ' +
+                                   'untagged packets or not.  Must be ' +
+                                   'specified under the bridge port. ' +
+                                   'Default is \'yes\'',
+                          'validvals' : ['yes', 'no'],
+                          'example' : ['bridge-allow-untagged yes'],
+                          'default' : 'yes'},
                     'bridge-port-vids' :
                         { 'help' : 'bridge vlans',
                           'compat': True,
@@ -188,41 +282,593 @@ class bridge(moduleBase):
                         { 'help' : 'bridge port vlans',
                           'compat': True,
                           'example' : ['bridge-port-pvids bond0=100 bond1=200']},
+                    'bridge-learning' :
+                        { 'help' : 'bridge port learning flag',
+                          'validvals': ['on', 'off', '<interface-on-off-list>'],
+                          'default': 'on',
+                          'example' : ['bridge-learning off']},
+                    'bridge-igmp-version' :
+                        { 'help' : 'mcast igmp version',
+                          'validvals': ['2', '3'],
+                          'default' : '2',
+                          'example' : ['bridge-igmp-version 2']},
+                    'bridge-mld-version':
+                        { 'help' : 'mcast mld version',
+                          'validvals': ['1', '2'],
+                          'default' : '1',
+                          'example' : ['bridge-mld-version 1']},
+                    'bridge-unicast-flood' :
+                        { 'help' : 'bridge port unicast flood flag',
+                          'validvals': ['on', 'off', '<interface-on-off-list>'],
+                          'default': 'on',
+                          'example' : ['under the port (for vlan aware bridge): bridge-unicast-flood on',
+                                       'under the bridge (for vlan unaware bridge): bridge-unicast-flood swp1=on swp2=on']},
+                    'bridge-multicast-flood' :
+                        { 'help' : 'bridge port multicast flood flag',
+                          'validvals': ['on', 'off', '<interface-on-off-list>'],
+                          'default': 'on',
+                          'example' : ['under the port (for vlan aware bridge): bridge-multicast-flood on',
+                                       'under the bridge (for vlan unaware bridge): bridge-multicast-flood swp1=on swp2=on']},
+                    'bridge-vlan-protocol' :
+                        { 'help' : 'bridge vlan protocol',
+                          'default' : '802.1q',
+                          'validvals': ['802.1q', '802.1ad'],
+                          'example' : ['bridge-vlan-protocol 802.1q']},
+                    'bridge-vlan-stats' :
+                        { 'help' : 'bridge vlan stats',
+                          'default' : 'off',
+                          'validvals': ['on', 'off'],
+                          'example' : ['bridge-vlan-stats off']},
+                    'bridge-arp-nd-suppress' :
+                        { 'help' : 'bridge port arp nd suppress flag',
+                          'validvals': ['on', 'off', '<interface-on-off-list>'],
+                          'default': 'off',
+                          'example' : ['under the port (for vlan aware bridge): bridge-arp-nd-suppress on',
+                                       'under the bridge (for vlan unaware bridge): bridge-arp-nd-suppress swp1=on swp2=on']},
+                    'bridge-mcstats' :
+                        { 'help' : 'bridge multicast stats',
+                          'default' : 'off',
+                          'validvals': ['on', 'off'],
+                          'example' : ['bridge-mcstats off']},
+                     'bridge-l2protocol-tunnel': {
+                         'help': 'layer 2 protocol tunneling',
+                         'validvals': [ # XXX: lists all combinations, should move to
+                                        # a better representation
+                                        'all',
+                                        'cdp',
+                                        'cdp lacp',
+                                        'cdp lacp lldp',
+                                        'cdp lacp lldp pvst',
+                                        'cdp lacp lldp stp',
+                                        'cdp lacp pvst',
+                                        'cdp lacp pvst stp',
+                                        'cdp lacp stp',
+                                        'cdp lldp',
+                                        'cdp lldp pvst',
+                                        'cdp lldp pvst stp',
+                                        'cdp lldp stp',
+                                        'cdp pvst',
+                                        'cdp pvst stp',
+                                        'cdp stp',
+                                        'lacp',
+                                        'lacp lldp',
+                                        'lacp lldp pvst',
+                                        'lacp lldp pvst stp',
+                                        'lacp lldp stp',
+                                        'lacp pvst',
+                                        'lacp pvst stp',
+                                        'lacp stp',
+                                        'lldp',
+                                        'lldp pvst',
+                                        'lldp pvst stp',
+                                        'lldp stp',
+                                        'pvst',
+                                        'pvst stp',
+                                        'stp',
+                                        '<interface-l2protocol-tunnel-list>'],
+                         'example': [
+                             'under the bridge (for vlan unaware bridge): bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all',
+                             'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lacp stp lldp cdp pvst',
+                             'under the port (for vlan aware bridge): bridge-l2protocol-tunnel lldp pvst',
+                             'under the port (for vlan aware bridge): bridge-l2protocol-tunnel stp',
+                             'under the port (for vlan aware bridge): bridge-l2protocol-tunnel all'
+                         ]
+                     }
                      }}
 
-    # declare some ifaceobj priv_flags.
-    # XXX: This assumes that the priv_flags is owned by this module
-    # which it is not.
-    _BRIDGE_PORT_PROCESSED = 0x1
+    # Netlink attributes not associated with ifupdown2
+    # attributes are left commented-out for a future use
+    # and kept in order :)
+    _ifla_br_attributes_map = (
+        # Link.IFLA_BR_UNSPEC,
+        ('bridge-fd', Link.IFLA_BR_FORWARD_DELAY),
+        ('bridge-hello', Link.IFLA_BR_HELLO_TIME),
+        ('bridge-maxage', Link.IFLA_BR_MAX_AGE),
+        ('bridge-ageing', Link.IFLA_BR_AGEING_TIME),
+        ('bridge-stp', Link.IFLA_BR_STP_STATE),
+        ('bridge-bridgeprio', Link.IFLA_BR_PRIORITY),
+        ('bridge-vlan-aware', Link.IFLA_BR_VLAN_FILTERING),
+        ('bridge-vlan-protocol', Link.IFLA_BR_VLAN_PROTOCOL),
+        # Link.IFLA_BR_GROUP_FWD_MASK,
+        # Link.IFLA_BR_ROOT_ID,
+        # Link.IFLA_BR_BRIDGE_ID,
+        # Link.IFLA_BR_ROOT_PORT,
+        # (Link.IFLA_BR_ROOT_PATH_COST,,
+        # Link.IFLA_BR_TOPOLOGY_CHANGE,
+        # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+        # Link.IFLA_BR_HELLO_TIMER,
+        # Link.IFLA_BR_TCN_TIMER,
+        # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+        # Link.IFLA_BR_GC_TIMER,
+        # Link.IFLA_BR_GROUP_ADDR,
+        # Link.IFLA_BR_FDB_FLUSH,
+        ('bridge-mcrouter', Link.IFLA_BR_MCAST_ROUTER),
+        #('bridge-mcsnoop', Link.IFLA_BR_MCAST_SNOOPING), # requires special handling so we won't loop on this attr
+        ('bridge-mcqifaddr', Link.IFLA_BR_MCAST_QUERY_USE_IFADDR),
+        ('bridge-mcquerier', Link.IFLA_BR_MCAST_QUERIER),
+        ('bridge-hashel', Link.IFLA_BR_MCAST_HASH_ELASTICITY),
+        ('bridge-hashmax', Link.IFLA_BR_MCAST_HASH_MAX),
+        ('bridge-mclmc', Link.IFLA_BR_MCAST_LAST_MEMBER_CNT),
+        ('bridge-mcsqc', Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT),
+        ('bridge-mclmi', Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL),
+        ('bridge-mcmi', Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL),
+        ('bridge-mcqpi', Link.IFLA_BR_MCAST_QUERIER_INTVL),
+        ('bridge-mcqi', Link.IFLA_BR_MCAST_QUERY_INTVL),
+        ('bridge-mcqri', Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL),
+        ('bridge-mcsqi', Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL),
+        # Link.IFLA_BR_NF_CALL_IPTABLES,
+        # Link.IFLA_BR_NF_CALL_IP6TABLES,
+        # Link.IFLA_BR_NF_CALL_ARPTABLES,
+        # Link.IFLA_BR_VLAN_DEFAULT_PVID,
+        # Link.IFLA_BR_PAD,
+        # (Link.IFLA_BR_VLAN_STATS_ENABLED, 'bridge-vlan-stats'), #  already dealt with, in a separate loop
+        ('bridge-igmp-version', Link.IFLA_BR_MCAST_IGMP_VERSION, ),
+        ('bridge-mcstats', Link.IFLA_BR_MCAST_STATS_ENABLED),
+        ('bridge-mld-version', Link.IFLA_BR_MCAST_MLD_VERSION)
+    )
+    # 'bridge-vlan-stats & bridge-mcstat are commented out even though, today
+    # they are supported. It is done this way because this dictionary is used
+    # in a loop, but these attributes require additional work. Thus they are
+    # excluded from this loop without overhead.
+
+    # we are still using the old linkCache we need an easy way
+    # to use this cache with the new full-netlink approach
+    _ifla_br_attributes_old_cache_key_map = dict(
+        (
+            (Link.IFLA_BR_FORWARD_DELAY, 'fd'),
+            (Link.IFLA_BR_HELLO_TIME, 'hello'),
+            (Link.IFLA_BR_MAX_AGE, 'maxage'),
+            (Link.IFLA_BR_AGEING_TIME, 'ageing'),
+            (Link.IFLA_BR_STP_STATE, 'stp'),
+            (Link.IFLA_BR_PRIORITY, 'bridgeprio'),
+            (Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering'),
+            (Link.IFLA_BR_VLAN_PROTOCOL, 'vlan-protocol'),
+            (Link.IFLA_BR_MCAST_ROUTER, 'mcrouter'),
+            (Link.IFLA_BR_MCAST_SNOOPING, 'mcsnoop'),
+            (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, 'mcqifaddr'),
+            (Link.IFLA_BR_MCAST_QUERIER, 'mcquerier'),
+            (Link.IFLA_BR_MCAST_HASH_ELASTICITY, 'hashel'),
+            (Link.IFLA_BR_MCAST_HASH_MAX, 'hashmax'),
+            (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, 'mclmc'),
+            (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, 'mcsqc'),
+            (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, 'mclmi'),
+            (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, 'mcmi'),
+            (Link.IFLA_BR_MCAST_QUERIER_INTVL, 'mcqpi'),
+            (Link.IFLA_BR_MCAST_QUERY_INTVL, 'mcqi'),
+            (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, 'mcqri'),
+            (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, 'mcsqi'),
+            (Link.IFLA_BR_VLAN_STATS_ENABLED, 'vlan-stats'),
+            (Link.IFLA_BR_MCAST_STATS_ENABLED, 'mcstats'),
+            (Link.IFLA_BR_MCAST_IGMP_VERSION, 'igmp-version'),
+            (Link.IFLA_BR_MCAST_MLD_VERSION, 'mld-version')
+        )
+    )
+
+    _ifla_br_attributes_translate_user_config_to_netlink_map = dict(
+        (
+            # Link.IFLA_BR_UNSPEC,
+            (Link.IFLA_BR_FORWARD_DELAY, lambda x: int(x) * 100),
+            (Link.IFLA_BR_HELLO_TIME, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MAX_AGE, lambda x: int(x) * 100),
+            (Link.IFLA_BR_AGEING_TIME, lambda x: int(x) * 100),
+            # Link.IFLA_BR_STP_STATE, #  STP is treated outside the loop
+            (Link.IFLA_BR_PRIORITY, int),
+            (Link.IFLA_BR_VLAN_FILTERING, utils.get_boolean_from_string),
+            (Link.IFLA_BR_VLAN_PROTOCOL, str),
+            # Link.IFLA_BR_GROUP_FWD_MASK,
+            # Link.IFLA_BR_ROOT_ID,
+            # Link.IFLA_BR_BRIDGE_ID,
+            # Link.IFLA_BR_ROOT_PORT,
+            # Link.IFLA_BR_ROOT_PATH_COST,
+            # Link.IFLA_BR_TOPOLOGY_CHANGE,
+            # Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+            # Link.IFLA_BR_HELLO_TIMER,
+            # Link.IFLA_BR_TCN_TIMER,
+            # Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+            # Link.IFLA_BR_GC_TIMER,
+            # Link.IFLA_BR_GROUP_ADDR,
+            # Link.IFLA_BR_FDB_FLUSH,
+            (Link.IFLA_BR_MCAST_ROUTER, utils.get_int_from_boolean_and_string),
+            (Link.IFLA_BR_MCAST_SNOOPING, utils.get_boolean_from_string),
+            (Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, utils.get_boolean_from_string),
+            (Link.IFLA_BR_MCAST_QUERIER, utils.get_boolean_from_string),
+            (Link.IFLA_BR_MCAST_HASH_ELASTICITY, int),
+            (Link.IFLA_BR_MCAST_HASH_MAX, int),
+            (Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, int),
+            (Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, int),
+            (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MCAST_QUERIER_INTVL, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MCAST_QUERY_INTVL, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, lambda x: int(x) * 100),
+            (Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, lambda x: int(x) * 100),
+            # Link.IFLA_BR_NF_CALL_IPTABLES,
+            # Link.IFLA_BR_NF_CALL_IP6TABLES,
+            # Link.IFLA_BR_NF_CALL_ARPTABLES,
+            # Link.IFLA_BR_VLAN_DEFAULT_PVID,
+            # Link.IFLA_BR_PAD,
+            (Link.IFLA_BR_VLAN_STATS_ENABLED, utils.get_boolean_from_string),
+            (Link.IFLA_BR_MCAST_IGMP_VERSION, int),
+            (Link.IFLA_BR_MCAST_STATS_ENABLED, utils.get_boolean_from_string),
+            (Link.IFLA_BR_MCAST_MLD_VERSION, int)
+        )
+    )
+
+    _ifla_brport_attributes_map = (
+        # Link.IFLA_BRPORT_UNSPEC,
+        # Link.IFLA_BRPORT_STATE,
+        ('bridge-portprios', Link.IFLA_BRPORT_PRIORITY),
+        ('bridge-pathcosts', Link.IFLA_BRPORT_COST),
+        # Link.IFLA_BRPORT_MODE,
+        # Link.IFLA_BRPORT_GUARD,
+        # Link.IFLA_BRPORT_PROTECT,
+        ('bridge-portmcfl', Link.IFLA_BRPORT_FAST_LEAVE),
+        ('bridge-learning', Link.IFLA_BRPORT_LEARNING),
+        ('bridge-unicast-flood', Link.IFLA_BRPORT_UNICAST_FLOOD),
+        # Link.IFLA_BRPORT_PROXYARP,
+        # Link.IFLA_BRPORT_LEARNING_SYNC,
+        # Link.IFLA_BRPORT_PROXYARP_WIFI,
+        # Link.IFLA_BRPORT_ROOT_ID,
+        # Link.IFLA_BRPORT_BRIDGE_ID,
+        # Link.IFLA_BRPORT_DESIGNATED_PORT,
+        # Link.IFLA_BRPORT_DESIGNATED_COST,
+        # Link.IFLA_BRPORT_ID,
+        # Link.IFLA_BRPORT_NO,
+        # Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
+        # Link.IFLA_BRPORT_CONFIG_PENDING,
+        # Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
+        # Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
+        # Link.IFLA_BRPORT_HOLD_TIMER,
+        # Link.IFLA_BRPORT_FLUSH,
+        ('bridge-portmcrouter', Link.IFLA_BRPORT_MULTICAST_ROUTER),
+        # Link.IFLA_BRPORT_PAD,
+        ('bridge-multicast-flood', Link.IFLA_BRPORT_MCAST_FLOOD),
+        # Link.IFLA_BRPORT_MCAST_TO_UCAST,
+        # Link.IFLA_BRPORT_VLAN_TUNNEL,
+        # Link.IFLA_BRPORT_BCAST_FLOOD
+        ('bridge-l2protocol-tunnel', Link.IFLA_BRPORT_GROUP_FWD_MASK),
+        # Link.IFLA_BRPORT_PEER_LINK,
+        # Link.IFLA_BRPORT_DUAL_LINK,
+        ('bridge-arp-nd-suppress', Link.IFLA_BRPORT_ARP_SUPPRESS),
+    )
+
+    _ifla_brport_multicast_router_dict_to_int = {
+        'disabled': 0,
+        '0': 0,
+        'no': 0,
+        'automatic': 1,
+        '1': 1,
+        'yes': 1,
+        'enabled': 2,
+        '2': 2,
+    }
+
+    # callable to translate <interface-yes-no-0-1-list> to netlink value
+    _ifla_brport_attributes_translate_user_config_to_netlink_map = dict(
+        (
+            (Link.IFLA_BRPORT_PRIORITY, int),
+            (Link.IFLA_BRPORT_COST, int),
+            (Link.IFLA_BRPORT_MULTICAST_ROUTER, lambda x: bridge._ifla_brport_multicast_router_dict_to_int.get(x, 0)),
+            (Link.IFLA_BRPORT_FAST_LEAVE, utils.get_boolean_from_string),
+            (Link.IFLA_BRPORT_LEARNING, utils.get_boolean_from_string),
+            (Link.IFLA_BRPORT_UNICAST_FLOOD, utils.get_boolean_from_string),
+            (Link.IFLA_BRPORT_MCAST_FLOOD, utils.get_boolean_from_string),
+            (Link.IFLA_BRPORT_GROUP_FWD_MASK, lambda x: x),
+            (Link.IFLA_BRPORT_ARP_SUPPRESS, utils.get_boolean_from_string)
+        )
+    )
 
     def __init__(self, *args, **kargs):
         moduleBase.__init__(self, *args, **kargs)
         self.ipcmd = None
+        self.name = self.__class__.__name__
         self.brctlcmd = None
         self._running_vidinfo = {}
         self._running_vidinfo_valid = False
         self._resv_vlan_range =  self._get_reserved_vlan_range()
-        self.logger.debug('%s: using reserved vlan range %s'
-                  %(self.__class__.__name__, str(self._resv_vlan_range)))
+        self.logger.debug('%s: using reserved vlan range %s' % (self.__class__.__name__, str(self._resv_vlan_range)))
+
+        self.default_stp_on = utils.get_boolean_from_string(
+            policymanager.policymanager_api.get_attr_default(
+                module_name=self.__class__.__name__,
+                attr='bridge-stp'
+            )
+        )
+
+        self.default_vlan_stats = policymanager.policymanager_api.get_attr_default(
+            module_name=self.__class__.__name__,
+            attr='bridge-vlan-stats'
+        )
+
+        self.warn_on_untagged_bridge_absence = utils.get_boolean_from_string(
+            policymanager.policymanager_api.get_module_globals(
+                module_name=self.__class__.__name__,
+                attr='warn_on_untagged_bridge_absence'
+            )
+        )
+        self.logger.debug('bridge: init: warn_on_untagged_bridge_absence=%s'
+                         % self.warn_on_untagged_bridge_absence)
+
+        self._vxlan_bridge_default_igmp_snooping = policymanager.policymanager_api.get_module_globals(
+            self.__class__.__name__,
+            'vxlan_bridge_default_igmp_snooping'
+        )
+        self.logger.debug('bridge: init: vxlan_bridge_default_igmp_snooping=%s'
+                          % self._vxlan_bridge_default_igmp_snooping)
+
+        self.arp_nd_suppress_only_on_vxlan = utils.get_boolean_from_string(
+            policymanager.policymanager_api.get_module_globals(
+                module_name=self.__class__.__name__,
+                attr='allow_arp_nd_suppress_only_on_vxlan'
+            )
+        )
+        self.logger.debug('bridge: init: arp_nd_suppress_only_on_vxlan=%s' % self.arp_nd_suppress_only_on_vxlan)
+
+        try:
+            self.bridge_allow_multiple_vlans = utils.get_boolean_from_string(
+                self.sysctl_get('net.bridge.bridge-allow-multiple-vlans')
+            )
+        except:
+            # Cumulus Linux specific variable. Failure probably means that
+            # ifupdown2 is running a a different system.
+            self.bridge_allow_multiple_vlans = True
+        self.logger.debug('bridge: init: multiple vlans allowed %s' % self.bridge_allow_multiple_vlans)
+
+        self.bridge_mac_iface_list = policymanager.policymanager_api.get_module_globals(self.__class__.__name__, 'bridge_mac_iface') or []
+        self.bridge_mac_iface = None, None  # ifname, mac
+
+        self.bridge_set_static_mac_from_port = utils.get_boolean_from_string(
+            policymanager.policymanager_api.get_module_globals(
+                self.__class__.__name__, 'bridge_set_static_mac_from_port'
+            )
+        )
+
+        self.vxlan_bridge_igmp_snooping_enable_port_mcrouter = utils.get_boolean_from_string(
+            policymanager.policymanager_api.get_module_globals(
+                module_name=self.__class__.__name__,
+                attr="vxlan_bridge_igmp_snooping_enable_port_mcrouter"
+            ),
+            default=True
+        )
+
+        self.l2protocol_tunnel_callback = {
+            'all': self._l2protocol_tunnel_set_all,
+            'stp': self._l2protocol_tunnel_set_stp,
+            'cdp': self._l2protocol_tunnel_set_cdp,
+            'pvst': self._l2protocol_tunnel_set_pvst,
+            'lldp': self._l2protocol_tunnel_set_lldp,
+            'lacp': self._l2protocol_tunnel_set_lacp
+        }
+
+        self.query_check_l2protocol_tunnel_callback = {
+            'all': self._query_check_l2protocol_tunnel_all,
+            'stp': self._query_check_l2protocol_tunnel_stp,
+            'cdp': self._query_check_l2protocol_tunnel_cdp,
+            'pvst': self._query_check_l2protocol_tunnel_pvst,
+            'lldp': self._query_check_l2protocol_tunnel_lldp,
+            'lacp': self._query_check_l2protocol_tunnel_lacp
+        }
+
+    @staticmethod
+    def _l2protocol_tunnel_set_pvst(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        if not ifla_brport_group_maskhi:
+            ifla_brport_group_maskhi = 0x1
+        else:
+            ifla_brport_group_maskhi |= 0x1
+        return ifla_brport_group_mask, ifla_brport_group_maskhi
+
+    @staticmethod
+    def _l2protocol_tunnel_set_cdp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        if not ifla_brport_group_maskhi:
+            ifla_brport_group_maskhi = 0x2
+        else:
+            ifla_brport_group_maskhi |= 0x2
+        return ifla_brport_group_mask, ifla_brport_group_maskhi
+
+    @staticmethod
+    def _l2protocol_tunnel_set_stp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        if not ifla_brport_group_mask:
+            ifla_brport_group_mask = 0x1
+        else:
+            ifla_brport_group_mask |= 0x1
+        return ifla_brport_group_mask, ifla_brport_group_maskhi
+
+    @staticmethod
+    def _l2protocol_tunnel_set_lacp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        if not ifla_brport_group_mask:
+            ifla_brport_group_mask = 0x4
+        else:
+            ifla_brport_group_mask |= 0x4
+        return ifla_brport_group_mask, ifla_brport_group_maskhi
 
-    def _is_bridge(self, ifaceobj):
-        if ifaceobj.get_attr_value_first('bridge-ports'):
+    @staticmethod
+    def _l2protocol_tunnel_set_lldp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        if not ifla_brport_group_mask:
+            ifla_brport_group_mask = 0x4000
+        else:
+            ifla_brport_group_mask |= 0x4000
+        return ifla_brport_group_mask, ifla_brport_group_maskhi
+
+    @staticmethod
+    def _l2protocol_tunnel_set_all(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        # returns new values for ifla_brport_group_mask and ifla_brport_group_maskhi
+        return 0x1 | 0x4 | 0x4000, 0x1 | 0x2
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_stp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_mask and ifla_brport_group_mask & 0x1
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_cdp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_maskhi and ifla_brport_group_maskhi & 0x2
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_pvst(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_maskhi and ifla_brport_group_maskhi & 0x1
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_lldp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_mask and ifla_brport_group_mask & 0x4000
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_lacp(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_mask and ifla_brport_group_mask & 0x4
+
+    @staticmethod
+    def _query_check_l2protocol_tunnel_all(ifla_brport_group_mask, ifla_brport_group_maskhi):
+        return ifla_brport_group_mask == (0x1 | 0x4 | 0x4000) and ifla_brport_group_maskhi == (0x1 | 0x2)
+
+    def syntax_check(self, ifaceobj, ifaceobj_getfunc):
+        retval = self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc)
+        if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+            if not self.check_bridge_port_vid_attrs(ifaceobj):
+                retval = False
+        c1 = self.syntax_check_vxlan_in_vlan_aware_br(ifaceobj, ifaceobj_getfunc)
+        c2 = self.syntax_check_bridge_allow_multiple_vlans(ifaceobj, ifaceobj_getfunc)
+        return retval and c1 #and c2
+
+    def syntax_check_bridge_allow_multiple_vlans(self, ifaceobj, ifaceobj_getfunc):
+        result = True
+        if not self.bridge_allow_multiple_vlans and ifaceobj.link_kind & ifaceLinkKind.BRIDGE and ifaceobj.lowerifaces:
+            vlan_id = None
+            for brport_name in ifaceobj.lowerifaces:
+                for obj in ifaceobj_getfunc(brport_name) or []:
+                    if obj.link_kind & ifaceLinkKind.VLAN:
+                        sub_intf_vlan_id = self._get_vlan_id(obj)
+                        if vlan_id and vlan_id != sub_intf_vlan_id:
+                            self.logger.error('%s: ignore %s: multiple vlans not allowed under bridge '
+                                              '(sysctl net.bridge.bridge-allow-multiple-vlans not set)'
+                                              % (ifaceobj.name, brport_name))
+                            result = False
+                            continue
+                        vlan_id = sub_intf_vlan_id
+        return result
+
+    def check_bridge_port_vid_attrs(self, ifaceobj):
+        if (ifaceobj.get_attr_value('bridge-access') and
+            (self.get_ifaceobj_bridge_vids_value(ifaceobj) or
+             ifaceobj.get_attr_value('bridge-pvid'))):
+            self.logger.warn('%s: bridge-access given, bridge-vids and bridge-pvid '
+                             'will be ignored' % ifaceobj.name)
+            return False
+        return True
+
+    def check_bridge_vlan_aware_port(self, ifaceobj, ifaceobj_getfunc):
+        if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
+            ports = self._get_bridge_port_list(ifaceobj)
+            if not ports:
+                return True
+            result = True
+            for port_name in ports:
+                port_obj_l = ifaceobj_getfunc(port_name)
+                if port_obj_l and port_obj_l[0].link_kind & ifaceLinkKind.VLAN:
+                    self.logger.error('%s: %s: vlan sub-interface is not '
+                                      'supported in a vlan-aware bridge'
+                                      % (ifaceobj.name, port_name))
+                    result = False
+                if (port_obj_l and
+                    port_obj_l[0].get_attr_value('bridge-arp-nd-suppress') and
+                    self.arp_nd_suppress_only_on_vxlan and
+                    not port_obj_l[0].link_kind & ifaceLinkKind.VXLAN):
+                    self.log_error('\'bridge-arp-nd-suppress\' is not '
+                                   'supported on a non-vxlan port %s'
+                                   %port_obj_l[0].name)
+                    result = False
+            return result
+        return True
+
+    def _error_vxlan_in_vlan_aware_br(self, ifaceobj, bridgename):
+        self.log_error('`bridge-access` attribute is mandatory when vxlan '
+                       'device (%s) is part of vlan aware bridge (%s)'
+                       % (ifaceobj.name, bridgename), ifaceobj)
+
+    def syntax_check_vxlan_in_vlan_aware_br(self, ifaceobj, ifaceobj_getfunc):
+        if not ifaceobj_getfunc:
             return True
-        return False
+        if (ifaceobj.link_kind & ifaceLinkKind.VXLAN
+                and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
+            if ifaceobj.get_attr_value('bridge-access'):
+                return True
+            for iface in ifaceobj.upperifaces if ifaceobj.upperifaces else []:
+                ifaceobj_upper_list = ifaceobj_getfunc(iface)
+                if not ifaceobj_upper_list:
+                    continue
+                ifaceobj_upper = ifaceobj_upper_list[0]
+                bridge_vids = self._get_bridge_vids(iface, ifaceobj_getfunc)
+                if ifaceobj_upper.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
+                    vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
+                    pvid = ifaceobj.get_attr_value_first('bridge-pvid')
+                    if (not vids
+                        or not pvid
+                        or not self._compare_vids(bridge_vids,
+                                                  vids,
+                                                  pvid=pvid)):
+                        self._error_vxlan_in_vlan_aware_br(ifaceobj,
+                                                           ifaceobj_upper.name)
+                        return False
+        return True
+
+    @staticmethod
+    def _is_bridge(ifaceobj):
+        return (ifaceobj.link_kind & ifaceLinkKind.BRIDGE or
+                ifaceobj.get_attr_value_first('bridge-ports') or
+                ifaceobj.get_attr_value_first('bridge-vlan-aware'))
+
+    def _get_ifaceobj_bridge_ports(self, ifaceobj):
+        bridge_ports = []
+
+        for brport in ifaceobj.get_attr_value('bridge-ports') or []:
+            if brport != 'none':
+                bridge_ports.extend(brport.split())
+
+        return ' '.join(bridge_ports)
 
     def _is_bridge_port(self, ifaceobj):
         if self.brctlcmd.is_bridge_port(ifaceobj.name):
             return True
         return False
 
+    def check_valid_bridge(self, ifaceobj, ifname):
+        if LinkUtils.link_exists_nodryrun(ifname) and not LinkUtils.is_bridge(ifname):
+            self.log_error('misconfiguration of bridge attribute(s) on existing non-bridge interface (%s)' % ifname, ifaceobj=ifaceobj)
+            return False
+        return True
+
     def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
-        if not self._is_bridge(ifaceobj):
+        if not self._is_bridge(ifaceobj) or not self.check_valid_bridge(ifaceobj, ifaceobj.name):
             return None
         if ifaceobj.link_type != ifaceLinkType.LINK_NA:
            ifaceobj.link_type = ifaceLinkType.LINK_MASTER
-        ifaceobj.link_kind = ifaceLinkKind.BRIDGE
-        return self.parse_port_list(ifaceobj.get_attr_value_first(
-                                    'bridge-ports'), ifacenames_all)
+        ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
+        # for special vlan aware bridges, we need to add another bit
+        if utils.get_boolean_from_string(ifaceobj.get_attr_value_first('bridge-vlan-aware')):
+            ifaceobj.link_kind |= ifaceLinkKind.BRIDGE
+            ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE
+        ifaceobj.role |= ifaceRole.MASTER
+        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
+        return self.parse_port_list(ifaceobj.name,
+                                    self._get_ifaceobj_bridge_ports(ifaceobj),
+                                    ifacenames_all)
 
     def get_dependent_ifacenames_running(self, ifaceobj):
         self._init_command_handlers()
@@ -238,12 +884,19 @@ class bridge(moduleBase):
         port_list = ifaceobj.lowerifaces
         if port_list:
             return port_list
-        ports = ifaceobj.get_attr_value_first('bridge-ports')
+        ports = self._get_ifaceobj_bridge_ports(ifaceobj)
         if ports:
-            return self.parse_port_list(ports)
+            return self.parse_port_list(ifaceobj.name, ports)
         else:
             return None
 
+    def _get_bridge_port_list_user_ordered(self, ifaceobj):
+        # When enslaving bridge-ports we need to return the exact user
+        # configured bridge ports list (bridge will inherit the mac of the
+        # first device.
+        ports = self._get_ifaceobj_bridge_ports(ifaceobj)
+        return self.parse_port_list(ifaceobj.name, ports) if ports else None
+
     def _process_bridge_waitport(self, ifaceobj, portlist):
         waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
         if not waitport_value: return
@@ -254,11 +907,12 @@ class bridge(moduleBase):
                 waitporttime = int(waitportvals[0])
             except:
                 self.log_warn('%s: invalid waitport value \'%s\''
-                        %(ifaceobj.name, waitporttime))
+                        %(ifaceobj.name, waitportvals[0]))
                 return
             if waitporttime <= 0: return
             try:
-                waitportlist = self.parse_port_list(waitportvals[1])
+                waitportlist = self.parse_port_list(ifaceobj.name,
+                                                    waitportvals[1])
             except IndexError, e:
                 # ignore error and use all bridge ports
                 waitportlist = portlist
@@ -276,42 +930,85 @@ class bridge(moduleBase):
             self.log_warn('%s: unable to process waitport: %s'
                     %(ifaceobj.name, str(e)))
 
-    def _ports_enable_disable_ipv6(self, ports, enable='1'):
+    def _enable_disable_ipv6(self, port, enable='1'):
+        try:
+            self.write_file('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % port, enable)
+        except Exception, e:
+            self.logger.info(str(e))
+
+    def handle_ipv6(self, ports, state, ifaceobj=None):
+        if (ifaceobj and
+                (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN) and
+                not ifaceobj.get_attr_value('address')):
+            self._enable_disable_ipv6(ifaceobj.name, state)
         for p in ports:
-            try:
-                self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
-                                '/disable_ipv6', enable)
-            except Exception, e:
-                self.logger.info(str(e))
-                pass
+            self._enable_disable_ipv6(p, state)
 
-    def _add_ports(self, ifaceobj):
+    def _pretty_print_add_ports_error(self, errstr, bridgeifaceobj, bridgeports):
+        """ pretty print bridge port add errors.
+            since the commands are batched and the kernel only returns error
+            codes, this function tries to interpret some error codes
+            and prints clearer errors """
+
+        if re.search('RTNETLINK answers: Invalid argument', errstr):
+            # Cumulus Linux specific error checks
+            try:
+                if self.sysctl_get('net.bridge.bridge-allow-multiple-vlans') == '0':
+                    vlanid = None
+                    for bport in bridgeports:
+                        currvlanid = self._get_vlan_id_from_ifacename(bport)
+                        if vlanid:
+                            if currvlanid != vlanid:
+                                self.log_error('%s: ' %bridgeifaceobj.name +
+                                               'net.bridge.bridge-allow-multiple-vlans not set, multiple vlans not allowed', bridgeifaceobj)
+                                break
+                        if currvlanid:
+                            vlanid = currvlanid
+            except Exception as e:
+                errstr += '\n%s' % str(e)
+        self.log_error(bridgeifaceobj.name + ': ' + errstr, bridgeifaceobj)
+
+    def _add_ports(self, ifaceobj, ifaceobj_getfunc):
         bridgeports = self._get_bridge_port_list(ifaceobj)
         runningbridgeports = []
-        removedbridgeports = []
 
         self.ipcmd.batch_start()
         self._process_bridge_waitport(ifaceobj, bridgeports)
         self.ipcmd.batch_start()
         # Delete active ports not in the new port list
-        if not self.PERFMODE:
+        if not ifupdownflags.flags.PERFMODE:
             runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
             if runningbridgeports:
                 for bport in runningbridgeports:
                     if not bridgeports or bport not in bridgeports:
                         self.ipcmd.link_set(bport, 'nomaster')
-                        removedbridgeports.append(bport)
+                        # set admin DOWN on all removed ports
+                        # that don't have config outside bridge
+                        if not ifaceobj_getfunc(bport):
+                            netlink.link_set_updown(bport, "down")
+                        # enable ipv6 for ports that were removed
+                        self.handle_ipv6([bport], '0')
             else:
                 runningbridgeports = []
         if not bridgeports:
             self.ipcmd.batch_commit()
-            return
+            return []
         err = 0
-        for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
+        ports = 0
+        newbridgeports = Set(bridgeports).difference(Set(runningbridgeports))
+        newly_enslaved_ports = []
+
+        newbridgeports_ordered = []
+        for br_port in self._get_bridge_port_list_user_ordered(ifaceobj):
+            if br_port in newbridgeports:
+                newbridgeports_ordered.append(br_port)
+
+        for bridgeport in newbridgeports_ordered:
             try:
-                if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
-                    self.log_warn('%s: bridge port %s does not exist'
-                                   %(ifaceobj.name, bridgeport))
+                if (not ifupdownflags.flags.DRYRUN and
+                    not self.ipcmd.link_exists(bridgeport)):
+                    self.log_error('%s: bridge port %s does not exist'
+                                   %(ifaceobj.name, bridgeport), ifaceobj)
                     err += 1
                     continue
                 hwaddress = self.ipcmd.link_get_hwaddress(bridgeport)
@@ -321,21 +1018,28 @@ class bridge(moduleBase):
                                   %hwaddress)
                     continue
                 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
+                newly_enslaved_ports.append(bridgeport)
+                self.handle_ipv6([bridgeport], '1')
                 self.ipcmd.addr_flush(bridgeport)
+                ports += 1
+                if ports == 250:
+                    ports = 0
+                    self.ipcmd.batch_commit()
+                    self.ipcmd.batch_start()
             except Exception, e:
                 self.logger.error(str(e))
                 pass
         try:
             self.ipcmd.batch_commit()
         except Exception, e:
-            self.logger.error(str(e))
+            self._pretty_print_add_ports_error(str(e), ifaceobj,
+                                               bridgeports)
             pass
 
-        # enable ipv6 for ports that were removed
-        self._ports_enable_disable_ipv6(removedbridgeports, '0')
         if err:
             self.log_error('bridge configuration failed (missing ports)')
 
+        return newly_enslaved_ports
 
     def _process_bridge_maxwait(self, ifaceobj, portlist):
         maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
@@ -372,38 +1076,37 @@ class bridge(moduleBase):
         example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
         """
         result = []
-        for part in rangelist:
-            if '-' in part:
-                a, b = part.split('-')
-                a, b = int(a), int(b)
-                result.extend(range(a, b + 1))
-            else:
-                a = int(part)
-                result.append(a)
+        try:
+            for part in rangelist:
+                if '-' in part:
+                    a, b = part.split('-')
+                    a, b = int(a), int(b)
+                    result.extend(range(a, b + 1))
+                else:
+                    a = int(part)
+                    result.append(a)
+        except:
+            self.logger.warn('unable to parse vids \'%s\''
+                             %''.join(rangelist))
+            pass
         return result
 
-    def _diff_vids(self, vids1, vids2):
-        vids_to_add = None
-        vids_to_del = None
+    def _compress_into_ranges(self, vids_ints):
+        return ['%d' %start if start == end else '%d-%d' %(start, end)
+                       for start, end in self._ints_to_ranges(vids_ints)]
 
-        vids1_ints = self._ranges_to_ints(vids1)
-        vids2_ints = self._ranges_to_ints(vids2)
-        vids1_diff = Set(vids1_ints).difference(vids2_ints)
-        vids2_diff = Set(vids2_ints).difference(vids1_ints)
-        if vids1_diff:
-            vids_to_add = ['%d' %start if start == end else '%d-%d' %(start, end)
-                        for start, end in self._ints_to_ranges(vids1_diff)]
-        if vids2_diff:
-            vids_to_del = ['%d' %start if start == end else '%d-%d' %(start, end)
-                        for start, end in self._ints_to_ranges(vids2_diff)]
-        return (vids_to_del, vids_to_add)
-
-    def _compare_vids(self, vids1, vids2):
+    def _diff_vids(self, vids1_ints, vids2_ints):
+        return Set(vids2_ints).difference(vids1_ints), Set(vids1_ints).difference(vids2_ints)
+
+    def _compare_vids(self, vids1, vids2, pvid=None):
         """ Returns true if the vids are same else return false """
 
         vids1_ints = self._ranges_to_ints(vids1)
         vids2_ints = self._ranges_to_ints(vids2)
-        if Set(vids1_ints).symmetric_difference(vids2_ints):
+        set_diff = Set(vids1_ints).symmetric_difference(vids2_ints)
+        if pvid and int(pvid) in set_diff:
+            set_diff.remove(int(pvid))
+        if set_diff:
             return False
         else:
             return True
@@ -415,8 +1118,8 @@ class bridge(moduleBase):
         attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
         if attrval:
             running_mcqv4src = {}
-            if not self.PERFMODE:
-                running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name)
+            if not ifupdownflags.flags.PERFMODE:
+                running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobj.name)
             mcqs = {}
             srclist = attrval.split()
             for s in srclist:
@@ -425,44 +1128,50 @@ class bridge(moduleBase):
 
             k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
             for v in k_to_del:
-                self.brctlcmd.del_mcqv4src(ifaceobj.name, v)
+                self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
             for v in mcqs.keys():
-                self.brctlcmd.set_mcqv4src(ifaceobj.name, v, mcqs[v])
+                self.brctlcmd.bridge_set_mcqv4src(ifaceobj.name, v, mcqs[v])
+        elif not ifupdownflags.flags.PERFMODE:
+            running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobj.name)
+            if running_mcqv4src:
+                for v in running_mcqv4src.keys():
+                    self.brctlcmd.bridge_del_mcqv4src(ifaceobj.name, v)
 
     def _get_running_vidinfo(self):
         if self._running_vidinfo_valid:
             return self._running_vidinfo
         self._running_vidinfo = {}
-        if not self.PERFMODE:
-            self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
+
+        # Removed check for PERFMODE.  Need the get in all cases
+        # including reboot, so that we can configure the pvid correctly.
+        self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all_json()
         self._running_vidinfo_valid = True
         return self._running_vidinfo
 
-    def _flush_running_vidinfo(self):
-        self._running_vidinfo = {}
-        self._running_vidinfo_valid = False
-
     def _set_bridge_vidinfo_compat(self, ifaceobj):
         #
         # Supports old style vlan vid info format
         # for compatibility
         #
+        bridge_port_pvids = ifaceobj.get_attr_value_first('bridge-port-pvids')
+        bridge_port_vids = ifaceobj.get_attr_value_first('bridge-port-vids')
+        if not bridge_port_pvids and not bridge_port_vids:
+            return
 
         # Handle bridge vlan attrs
-        running_vidinfo = self._get_running_vidinfo()
-
         # Install pvids
-        attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
-        if attrval:
-            portlist = self.parse_port_list(attrval)
+        if bridge_port_pvids:
+            portlist = self.parse_port_list(ifaceobj.name, bridge_port_pvids)
             if not portlist:
                 self.log_warn('%s: could not parse \'%s %s\''
-                              %(ifaceobj.name, attrname, attrval))
+                              %(ifaceobj.name, 'bridge-port-pvids',
+                                bridge_port_pvids))
                 return
             for p in portlist:
                 try:
                     (port, pvid) = p.split('=')
-                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
+                    pvid = int(pvid)
+                    running_pvid = self._get_running_pvid(port)
                     if running_pvid:
                         if running_pvid == pvid:
                             continue
@@ -474,214 +1183,358 @@ class bridge(moduleBase):
                             %(ifaceobj.name, p, str(e)))
 
         # install port vids
-        attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
-        if attrval:
-            portlist = self.parse_port_list(attrval)
+        if bridge_port_vids:
+            portlist = self.parse_port_list(ifaceobj.name, bridge_port_vids)
             if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                          %(ifaceobj.name, attrname, attrval))
+                self.log_warn('%s: could not parse \'%s %s\'' %(ifaceobj.name,
+                              'bridge-port-vids', bridge_port_vids))
                 return
             for p in portlist:
                 try:
                     (port, val) = p.split('=')
                     vids = val.split(',')
-                    if running_vidinfo.get(port):
+                    vids_int =  self._ranges_to_ints(vids)
+                    running_vids = self.ipcmd.bridge_vlan_get_vids(port)
+                    if running_vids:
                         (vids_to_del, vids_to_add) = \
-                                self._diff_vids(vids,
-                                running_vidinfo.get(port).get('vlan'))
+                                self._diff_vids(vids_int, running_vids)
                         if vids_to_del:
-                            self.ipcmd.bridge_port_vids_del(port, vids_to_del)
+                            self.ipcmd.bridge_port_vids_del(port,
+                                    self._compress_into_ranges(vids_to_del))
                         if vids_to_add:
-                            self.ipcmd.bridge_port_vids_add(port, vids_to_add)
+                            self.ipcmd.bridge_port_vids_add(port,
+                                    self._compress_into_ranges(vids_to_add))
                     else:
-                        self.ipcmd.bridge_port_vids_add(port, vids)
+                        self.ipcmd.bridge_port_vids_add(port, vids_int)
                 except Exception, e:
                     self.log_warn('%s: failed to set vid `%s` (%s)'
                         %(ifaceobj.name, p, str(e)))
 
-        # install vids
-        # XXX: Commenting out this code for now because it was decided
-        # that this is not needed
-        #attrval = ifaceobj.get_attr_value_first('bridge-vids')
-        #if attrval:
-        #    vids = re.split(r'[\s\t]\s*', attrval)
-        #    if running_vidinfo.get(ifaceobj.name):
-        #        (vids_to_del, vids_to_add) = \
-        #                self._diff_vids(vids,
-        #                    running_vidinfo.get(ifaceobj.name).get('vlan'))
-        #        if vids_to_del:
-        #            self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
-        #        if vids_to_add:
-        #            self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
-        #    else:
-        #        self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
-        #else:
-        #    running_vids = running_vidinfo.get(ifaceobj.name)
-        #    if running_vids:
-        #        self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
-
-    def _apply_bridge_settings(self, ifaceobj):
+    def _is_running_stp_state_on(self, bridgename):
+        """ Returns True if running stp state is on, else False """
+
+        stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
+        try:
+            running_stp_state = self.read_file_oneline(stp_state_file)
+            return running_stp_state and running_stp_state != '0'
+        except:
+            return False
+
+    def _is_config_stp_state_on(self, ifaceobj):
+        """ Returns true if user specified stp state is on, else False """
+
+        stp_attr = ifaceobj.get_attr_value_first('bridge-stp')
+        if not stp_attr:
+            return self.default_stp_on
+        return utils.get_boolean_from_string(stp_attr)
+
+    def get_bridge_mcsnoop_value(self, ifaceobj):
+        mcsnoop = ifaceobj.get_attr_value_first('bridge-mcsnoop')
+        if not mcsnoop and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN:
+            return self._vxlan_bridge_default_igmp_snooping
+        return mcsnoop
+
+    def fill_ifla_info_data_with_ifla_br_attribute(self,
+                                                   ifla_info_data,
+                                                   link_just_created,
+                                                   ifname,
+                                                   nl_attr,
+                                                   attr_name,
+                                                   user_config):
+        try:
+            translate_func = self._ifla_br_attributes_translate_user_config_to_netlink_map.get(nl_attr)
+
+            if not callable(translate_func):
+                return
+
+            if not user_config:
+                user_config = policymanager.policymanager_api.get_iface_default(
+                    module_name=self.__class__.__name__,
+                    ifname=ifname,
+                    attr=attr_name
+                )
+
+            old_cache_key = self._ifla_br_attributes_old_cache_key_map.get(nl_attr)
+            if old_cache_key and not link_just_created:
+                cached_value = self.brctlcmd.link_cache_get([ifname, 'linkinfo', old_cache_key])
+                if not cached_value or cached_value == "None":
+                    # the link already exists but we don't have any value
+                    # cached for this attr, it probably means that the
+                    # capability is not available on this system (i.e old kernel)
+                    self.logger.debug('%s: ignoring %s %s: capability '
+                                      'probably not supported on this system'
+                                      % (ifname, attr_name, user_config))
+                    return
+                # we need to convert the cache value to "netlink" format
+                cached_value = translate_func(cached_value.lower())
+            else:
+                cached_value = None
+
+            if not user_config and not link_just_created and cached_value is not None:
+                # there is no user configuration for this attribute
+                # if the bridge existed before we need to check if
+                # this attribute needs to be reset to default value
+                default_value = self.get_attr_default_value(attr_name)
+
+                if default_value:
+                    # the attribute has a default value, we need to convert it to
+                    # netlink format to compare it with the cache value
+                    default_value_nl = translate_func(default_value)  # default_value.lower()
+
+                    if default_value_nl != cached_value:
+                        # the running value difers from the default value
+                        # but the user didn't specify any config
+                        # resetting attribute to default
+                        ifla_info_data[nl_attr] = default_value_nl
+                        self.logger.info('%s: reset %s to default: %s' % (ifname, attr_name, default_value))
+            elif user_config:
+                user_config_nl = translate_func(user_config)  # user_config.lower()
+
+                if user_config_nl != cached_value:
+                    ifla_info_data[nl_attr] = user_config_nl
+
+                    if cached_value is not None:
+                        self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value))
+                    else:
+                        self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config))
+        except Exception as e:
+            self.logger.warning('%s: %s: %s' % (ifname, attr_name, str(e)))
+
+    def up_apply_bridge_settings(self, ifaceobj, link_just_created, bridge_vlan_aware):
+        ifla_info_data = dict()
+        ifname = ifaceobj.name
+
+        self.logger.info('%s: apply bridge settings' % ifname)
+
+        for attr_name, nl_attr in self._ifla_br_attributes_map:
+            self.fill_ifla_info_data_with_ifla_br_attribute(
+                ifla_info_data=ifla_info_data,
+                link_just_created=link_just_created,
+                ifname=ifname,
+                nl_attr=nl_attr,
+                attr_name=attr_name,
+                user_config=ifaceobj.get_attr_value_first(attr_name)
+            )
+
+        # bridge-mcsnoop
+        self.fill_ifla_info_data_with_ifla_br_attribute(
+            ifla_info_data=ifla_info_data,
+            link_just_created=link_just_created,
+            ifname=ifname,
+            nl_attr=Link.IFLA_BR_MCAST_SNOOPING,
+            attr_name='bridge-mcsnoop',
+            user_config=self.get_bridge_mcsnoop_value(ifaceobj)
+        )
+
+        # bridge-vlan-stats
+        if bridge_vlan_aware:
+            self.fill_ifla_info_data_with_ifla_br_attribute(
+                ifla_info_data=ifla_info_data,
+                link_just_created=link_just_created,
+                ifname=ifname,
+                nl_attr=Link.IFLA_BR_VLAN_STATS_ENABLED,
+                attr_name='bridge-vlan-stats',
+                user_config=ifaceobj.get_attr_value_first('bridge-vlan-stats') or self.default_vlan_stats
+            )
+
         try:
-            stp = ifaceobj.get_attr_value_first('bridge-stp')
-            if stp:
-                self.brctlcmd.set_stp(ifaceobj.name, stp)
+            if self._is_config_stp_state_on(ifaceobj):
+                if not self._is_running_stp_state_on(ifname):
+                    ifla_info_data[Link.IFLA_BR_STP_STATE] = 1
+                    self.logger.info('%s: stp state reset, reapplying port settings' % ifname)
+                    ifaceobj.module_flags[ifaceobj.name] = \
+                        ifaceobj.module_flags.setdefault(self.name, 0) | \
+                        bridgeFlags.PORT_PROCESSED_OVERRIDE
             else:
                 # If stp not specified and running stp state on, set it to off
-                running_stp_state = self.read_file_oneline(
-                       '/sys/class/net/%s/bridge/stp_state' %ifaceobj.name)
-                if running_stp_state and running_stp_state != '0':
-                   self.brctlcmd.set_stp(ifaceobj.name, 'no')
-
-            if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes':
-               self.write_file('/sys/class/net/%s/bridge/vlan_filtering'
-                       %ifaceobj.name, '1')
-            # Use the brctlcmd bulk set method: first build a dictionary
-            # and then call set
-            bridgeattrs = { k:v for k,v in
-                             {'ageing' :
-                                ifaceobj.get_attr_value_first('bridge-ageing'),
-                              'bridgeprio' :
-                                ifaceobj.get_attr_value_first(
-                                                        'bridge-bridgeprio'),
-                              'fd' :
-                                ifaceobj.get_attr_value_first('bridge-fd'),
-                              'gcint' :
-                                ifaceobj.get_attr_value_first('bridge-gcint'),
-                              'hello' :
-                                ifaceobj.get_attr_value_first('bridge-hello'),
-                              'maxage' :
-                                ifaceobj.get_attr_value_first('bridge-maxage'),
-                              'mclmc' :
-                                ifaceobj.get_attr_value_first('bridge-mclmc'),
-                              'mcrouter' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcrouter'),
-                              'mcsnoop' :
-                                ifaceobj.get_attr_value_first('bridge-mcsnoop'),
-                              'mcsqc' :
-                                ifaceobj.get_attr_value_first('bridge-mcsqc'),
-                              'mcqifaddr' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcqifaddr'),
-                              'mcquerier' :
-                                ifaceobj.get_attr_value_first(
-                                                            'bridge-mcquerier'),
-                              'hashel' :
-                                ifaceobj.get_attr_value_first('bridge-hashel'),
-                              'hashmax' :
-                                ifaceobj.get_attr_value_first('bridge-hashmax'),
-                              'mclmi' :
-                                ifaceobj.get_attr_value_first('bridge-mclmi'),
-                              'mcmi' :
-                                ifaceobj.get_attr_value_first('bridge-mcmi'),
-                              'mcqpi' :
-                                ifaceobj.get_attr_value_first('bridge-mcqpi'),
-                              'mcqi' :
-                                ifaceobj.get_attr_value_first('bridge-mcqi'),
-                              'mcqri' :
-                                ifaceobj.get_attr_value_first('bridge-mcqri'),
-                              'mcsqi' :
-                                ifaceobj.get_attr_value_first('bridge-mcsqi')
-                               }.items()
-                            if v }
-            if bridgeattrs:
-                self.brctlcmd.set_bridge_attrs(ifaceobj.name, bridgeattrs)
-            portattrs = {}
-            for attrname, dstattrname in {'bridge-pathcosts' : 'pathcost',
-                                'bridge-portprios' : 'portprio',
-                                'bridge-portmcrouter' : 'portmcrouter',
-                                'bridge-portmcfl' : 'portmcfl'}.items():
-                attrval = ifaceobj.get_attr_value_first(attrname)
-                if not attrval:
-                    continue
-                portlist = self.parse_port_list(attrval)
-                if not portlist:
-                    self.log_warn('%s: could not parse \'%s %s\''
-                         %(ifaceobj.name, attrname, attrval))
-                    continue
-                for p in portlist:
-                    try:
-                        (port, val) = p.split('=')
-                        if not portattrs.get(port):
-                            portattrs[port] = {}
-                        portattrs[port].update({dstattrname : val})
-                    except Exception, e:
-                        self.log_warn('%s: could not parse %s (%s)'
-                                    %(ifaceobj.name, attrname, str(e)))
-            for port, attrdict in portattrs.iteritems():
-                try:
-                    self.brctlcmd.set_bridgeport_attrs(ifaceobj.name, port,
-                                                       attrdict)
-                except Exception, e:
-                    self.log_warn('%s: %s', str(e))
-                    pass
-            self._set_bridge_vidinfo_compat(ifaceobj)
-            self._set_bridge_mcqv4src_compat(ifaceobj)
-            self._process_bridge_maxwait(ifaceobj,
-                    self._get_bridge_port_list(ifaceobj))
-        except Exception, e:
-            self.log_warn(str(e))
+                if self._is_running_stp_state_on(ifname):
+                    self.logger.info('%s: bridge-stp not specified but running: turning stp off')
+                    ifla_info_data[Link.IFLA_BR_STP_STATE] = 0
+        except Exception as e:
+            self.logger.warning('%s: bridge stp: %s' % (ifname, str(e)))
+
+        if ifla_info_data:
+            netlink.link_add_set(ifname=ifname, kind='bridge', ifla_info_data=ifla_info_data, link_exists=True)
 
     def _check_vids(self, ifaceobj, vids):
         ret = True
         for v in vids:
-            if '-' in v:
-                va, vb = v.split('-')
-                va, vb = int(va), int(vb)
-                if (self._handle_reserved_vlan(va, ifaceobj.name) or
-                    self._handle_reserved_vlan(vb, ifaceobj.name)):
-                    ret = False
-            else:
-                va = int(v)
-                if self._handle_reserved_vlan(va, ifaceobj.name):
-                   ret = False
+            try:
+                if '-' in v:
+                    va, vb = v.split('-')
+                    va, vb = int(va), int(vb)
+                    self._handle_reserved_vlan(va, ifaceobj.name, end=vb)
+                else:
+                    va = int(v)
+                    self._handle_reserved_vlan(va, ifaceobj.name)
+            except exceptions.ReservedVlanException as e:
+                raise e
+            except Exception:
+                self.logger.warn('%s: unable to parse vid \'%s\''
+                                 %(ifaceobj.name, v))
         return ret
-         
-    def _apply_bridge_vids(self, bportifaceobj, vids, running_vids, isbridge):
+
+    def _get_running_pvid(self, ifacename):
+        pvid = 0
+
+        running_vidinfo = self._get_running_vidinfo()
+        for vinfo in running_vidinfo.get(ifacename, {}):
+            v = vinfo.get('vlan')
+            pvid = v if 'PVID' in vinfo.get('flags', []) else 0
+            if pvid:
+                return pvid
+        return pvid
+
+    def _get_running_vids_n_pvid_str(self, ifacename):
+        vids = []
+        pvid = None
+
+        (vids, pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(ifacename)
+
+        if vids:
+            ret_vids = self._compress_into_ranges(vids)
+        else:
+            ret_vids = None
+
+        if pvid:
+            ret_pvid = '%s' %pvid
+        else:
+            ret_pvid = None
+        return (ret_vids, ret_pvid)
+
+    def _apply_bridge_vids_and_pvid(self, bportifaceobj, vids, pvid,
+                                    isbridge):
+        """ This method is a combination of methods _apply_bridge_vids and
+            _apply_bridge_port_pvids above. A combined function is
+            found necessary to do the deletes first and the adds later
+            because kernel does honor vid info flags during deletes.
+
+        """
+        if not isbridge and bportifaceobj.link_kind & ifaceLinkKind.VXLAN:
+            if not vids or not pvid or len(vids) > 1 or vids[0] != pvid:
+                self._error_vxlan_in_vlan_aware_br(bportifaceobj,
+                                                   bportifaceobj.upperifaces[0])
+                return
+
+        vids_int =  self._ranges_to_ints(vids)
+        try:
+            pvid_int = int(pvid) if pvid else 0
+        except Exception:
+            self.logger.warn('%s: unable to parse pvid \'%s\''
+                             %(bportifaceobj.name, pvid))
+            pvid_int = 0
+            pass
+
+        vids_to_del = []
+        vids_to_add = vids_int
+        pvid_to_del = None
+        pvid_to_add = pvid_int
+
         try:
             if not self._check_vids(bportifaceobj, vids):
                return
+
+            (running_vids, running_pvid) = self.ipcmd.bridge_vlan_get_vids_n_pvid(
+                                                        bportifaceobj.name)
+
+            if not running_vids and not running_pvid:
+                # There cannot be a no running pvid.
+                # It might just not be in our cache:
+                # this can happen if at the time we were
+                # creating the bridge vlan cache, the port
+                # was not part of the bridge. And we need
+                # to make sure both vids and pvid is not in
+                # the cache, to declare that our cache may
+                # be stale.
+                running_pvid = 1
+                running_vids = [1]
+
             if running_vids:
                 (vids_to_del, vids_to_add) = \
-                    self._diff_vids(vids, running_vids)
-                if vids_to_del:
-                    self.ipcmd.bridge_vids_del(bportifaceobj.name,
-                                               vids_to_del, isbridge)
-                if vids_to_add:
-                    self.ipcmd.bridge_vids_add(bportifaceobj.name,
-                                               vids_to_add, isbridge)
-            else:
-                self.ipcmd.bridge_vids_add(bportifaceobj.name, vids, isbridge)
+                    self._diff_vids(vids_to_add, running_vids)
+
+            if running_pvid:
+                if running_pvid != pvid_int and running_pvid != 0:
+                    pvid_to_del = running_pvid
+
+            if (pvid_to_del and (pvid_to_del in vids_int) and
+                (pvid_to_del not in vids_to_add)):
+                # kernel deletes dont take into account
+                # bridge vid flags and its possible that
+                # the pvid deletes we do end up deleting
+                # the vids. Be proactive and add the pvid
+                # to the vid add list if it is in the vids
+                # and not already part of vids_to_add.
+                # This helps with a small corner case:
+                #   - running
+                #       pvid 100
+                #       vid 101 102
+                #   - new change is going to move the state to
+                #       pvid 101
+                #       vid 100 102
+                vids_to_add.add(pvid_to_del)
+        except exceptions.ReservedVlanException as e:
+            raise e
         except Exception, e:
-                self.log_warn('%s: failed to set vid `%s` (%s)'
-                        %(bportifaceobj.name, str(vids), str(e)))
+            self.log_error('%s: failed to process vids/pvids'
+                           %bportifaceobj.name + ' vids = %s' %str(vids) +
+                           'pvid = %s ' %pvid + '(%s)' %str(e),
+                           bportifaceobj, raise_error=False)
+        try:
+            if vids_to_del:
+               if pvid_to_add in vids_to_del:
+                   vids_to_del.remove(pvid_to_add)
+               self.ipcmd.bridge_vids_del(bportifaceobj.name,
+                                          self._compress_into_ranges(
+                                          vids_to_del), isbridge)
+        except Exception, e:
+                self.log_warn('%s: failed to del vid `%s` (%s)'
+                        %(bportifaceobj.name, str(vids_to_del), str(e)))
 
-    def _apply_bridge_port_pvids(self, bportifaceobj, pvid, running_pvid):
-        # Install pvids
         try:
-            if running_pvid:
-                if running_pvid != pvid:
-                    self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
-                                                    running_pvid)
-                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
-            else:
-                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
+            if pvid_to_del:
+               self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
+                                               pvid_to_del)
+        except Exception, e:
+                self.log_warn('%s: failed to del pvid `%s` (%s)'
+                        %(bportifaceobj.name, pvid_to_del, str(e)))
+
+        try:
+            if vids_to_add:
+               self.ipcmd.bridge_vids_add(bportifaceobj.name,
+                                          self._compress_into_ranges(
+                                          vids_to_add), isbridge)
+        except Exception, e:
+                self.log_error('%s: failed to set vid `%s` (%s)'
+                               %(bportifaceobj.name, str(vids_to_add),
+                                 str(e)), bportifaceobj, raise_error=False)
+
+        try:
+            if pvid_to_add and pvid_to_add != running_pvid:
+                self.ipcmd.bridge_port_pvid_add(bportifaceobj.name,
+                                                pvid_to_add)
         except Exception, e:
-            self.log_warn('%s: failed to set pvid `%s` (%s)'
-                          %(bportifaceobj.name, pvid, str(e)))
+                self.log_error('%s: failed to set pvid `%s` (%s)'
+                               %(bportifaceobj.name, pvid_to_add, str(e)),
+                               bportifaceobj)
 
     def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
                                                    bridge_vids=None,
                                                    bridge_pvid=None):
-        running_vidinfo = self._get_running_vidinfo()
         vids = None
         pvids = None
+        vids_final = []
+        pvid_final = None
         bport_access = bportifaceobj.get_attr_value_first('bridge-access')
         if bport_access:
             vids = re.split(r'[\s\t]\s*', bport_access)
             pvids = vids
+            allow_untagged = 'yes'
+            self.check_bridge_port_vid_attrs(bportifaceobj)
         else:
-            bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
+            allow_untagged = bportifaceobj.get_attr_value_first('bridge-allow-untagged') or 'yes'
+
+            bport_vids = self.get_ifaceobj_bridge_vids_value(bportifaceobj)
             if bport_vids:
                 vids = re.split(r'[\s\t,]\s*', bport_vids)
 
@@ -689,65 +1542,26 @@ class bridge(moduleBase):
             if bport_pvids:
                 pvids = re.split(r'[\s\t]\s*', bport_pvids)
 
-        if pvids:
-            self._apply_bridge_port_pvids(bportifaceobj, pvids[0],
-                    running_vidinfo.get(bportifaceobj.name, {}).get('pvid'))
-        elif bridge_pvid:
-            self._apply_bridge_port_pvids(bportifaceobj,
-                    bridge_pvid, running_vidinfo.get(bportifaceobj.name,
-                    {}).get('pvid'))
-        # XXX: default pvid is already one
-        #else:
-        #    self._apply_bridge_port_pvids(bportifaceobj,
-        #            '1', running_vidinfo.get(bportifaceobj.name,
-        #            {}).get('pvid'))
-
         if vids:
-            self._apply_bridge_vids(bportifaceobj, vids,
-                    running_vidinfo.get(bportifaceobj.name,
-                    {}).get('vlan'), False)
+            vids_final =  vids
         elif bridge_vids:
-            self._apply_bridge_vids(bportifaceobj,
-                                    bridge_vids, running_vidinfo.get(
-                                    bportifaceobj.name, {}).get('vlan'), False)
-
-
-    def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
-                                    bridgeifaceobj=None):
-        if not bridgename and bridgeifaceobj:
-            bridgename = bridgeifaceobj.name
-        # Set other stp and igmp attributes
-        portattrs = {}
-        for attrname, dstattrname in {
-            'bridge-pathcosts' : 'pathcost',
-            'bridge-portprios' : 'portprio',
-            'bridge-portmcrouter' : 'portmcrouter',
-            'bridge-portmcfl' : 'portmcfl'}.items():
-            attrval = bportifaceobj.get_attr_value_first(attrname)
-            if not attrval:
-                # Check if bridge has that attribute
-                #if bridgeifaceobj:
-                #    attrval = bridgeifaceobj.get_attr_value_first(attrname)
-                #    if not attrval:
-                #        continue
-                #else:
-                continue
-            portattrs[dstattrname] = attrval
-        try:
-            self.brctlcmd.set_bridgeport_attrs(bridgename,
-                            bportifaceobj.name, portattrs)
-        except Exception, e:
-            self.log_warn(str(e))
+            vids_final = bridge_vids
 
-    def _apply_bridge_port_settings_all(self, ifaceobj,
-                                        ifaceobj_getfunc=None):
-        err = False
-        bridge_vlan_aware = ifaceobj.get_attr_value_first(
-                                           'bridge-vlan-aware')
-        if bridge_vlan_aware and bridge_vlan_aware == 'yes':
-           bridge_vlan_aware = True
+        if allow_untagged == 'yes':
+            if pvids:
+                pvid_final = pvids[0]
+            elif bridge_pvid:
+                pvid_final = bridge_pvid
+            else:
+                pvid_final = '1'
         else:
-           bridge_vlan_aware = False
+            pvid_final = None
+
+        self._apply_bridge_vids_and_pvid(bportifaceobj, vids_final,
+                                         pvid_final, False)
+
+    def _apply_bridge_port_settings_all(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware):
+        err = False
 
         if (ifaceobj.get_attr_value_first('bridge-port-vids') and
                 ifaceobj.get_attr_value_first('bridge-port-pvids')):
@@ -757,7 +1571,7 @@ class bridge(moduleBase):
         self.logger.info('%s: applying bridge configuration '
                          %ifaceobj.name + 'specific to ports')
 
-        bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
+        bridge_vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
         if bridge_vids:
            bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
         else:
@@ -769,10 +1583,17 @@ class bridge(moduleBase):
         else:
            bridge_pvid = None
 
+        if (ifaceobj.module_flags.get(self.name, 0x0) &
+                bridgeFlags.PORT_PROCESSED_OVERRIDE):
+            port_processed_override = True
+        else:
+            port_processed_override = False
+
         bridgeports = self._get_bridge_port_list(ifaceobj)
         if not bridgeports:
            self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
            return
+        self.ipcmd.batch_start()
         for bport in bridgeports:
             # Use the brctlcmd bulk set method: first build a dictionary
             # and then call set
@@ -787,113 +1608,631 @@ class bridge(moduleBase):
                continue
             for bportifaceobj in bportifaceobjlist:
                 # Dont process bridge port if it already has been processed
-                if bportifaceobj.priv_flags & self._BRIDGE_PORT_PROCESSED:
+                # and there is no override on port_processed
+                if (not port_processed_override and
+                    (bportifaceobj.module_flags.get(self.name,0x0) &
+                     bridgeFlags.PORT_PROCESSED)):
                     continue
                 try:
                     # Add attributes specific to the vlan aware bridge
                     if bridge_vlan_aware:
                         self._apply_bridge_vlan_aware_port_settings_all(
                                 bportifaceobj, bridge_vids, bridge_pvid)
-                        self._apply_bridge_port_settings(bportifaceobj,
-                                                 bridgeifaceobj=ifaceobj)
+                    elif self.warn_on_untagged_bridge_absence:
+                        self._check_untagged_bridge(ifaceobj.name, bportifaceobj, ifaceobj_getfunc)
+                except exceptions.ReservedVlanException as e:
+                    raise e
                 except Exception, e:
                     err = True
                     self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
                     pass
+        self.ipcmd.bridge_batch_commit()
         if err:
            raise Exception('%s: errors applying port settings' %ifaceobj.name)
 
-    def _up(self, ifaceobj, ifaceobj_getfunc=None):
-        # Check if bridge port
+    def _check_untagged_bridge(self, bridgename, bridgeportifaceobj, ifaceobj_getfunc):
+        if bridgeportifaceobj.link_kind & ifaceLinkKind.VLAN:
+            lower_ifaceobj_list = ifaceobj_getfunc(bridgeportifaceobj.lowerifaces[0])
+            if lower_ifaceobj_list and lower_ifaceobj_list[0] and \
+                    not lower_ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+                self.logger.warn('%s: untagged bridge not found. Please configure a bridge with untagged bridge ports to avoid Spanning Tree Interoperability issue.' % bridgename)
+                self.warn_on_untagged_bridge_absence = False
+
+    def bridge_port_get_bridge_name(self, ifaceobj):
         bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
-        if bridgename:
-           if self.ipcmd.bridge_is_vlan_aware(bridgename):
-              bridge_vids = self._get_bridge_vids(bridgename,
-                                                  ifaceobj_getfunc)
-              bridge_pvid = self._get_bridge_pvid(bridgename,
-                                                   ifaceobj_getfunc)
-              self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
-                                                              bridge_vids,
-                                                              bridge_pvid)
-           self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
-           ifaceobj.priv_flags |= self._BRIDGE_PORT_PROCESSED
-           return
-        if not self._is_bridge(ifaceobj):
-            return
-        err = False
-        errstr = ''
-        running_ports = ''
+        if not bridgename:
+            # bridge port is not enslaved to a bridge we need to find
+            # the bridge in it's upper ifaces then enslave it
+            for u in ifaceobj.upperifaces:
+                if self.ipcmd.is_bridge(u):
+                    return True, u
+            return False, None
+        # return should_enslave port, bridgename
+        return False, bridgename
+
+    def up_bridge_port_vlan_aware_bridge(self, ifaceobj, ifaceobj_getfunc, bridge_name, should_enslave_port):
+        if should_enslave_port:
+            netlink.link_set_master(ifaceobj.name, bridge_name)
+            self.handle_ipv6([ifaceobj.name], '1')
+
+        bridge_vids = self._get_bridge_vids(bridge_name, ifaceobj_getfunc)
+        bridge_pvid = self._get_bridge_pvid(bridge_name, ifaceobj_getfunc)
         try:
-            if not self.PERFMODE:
-                if not self.ipcmd.link_exists(ifaceobj.name):
-                   self.ipcmd.link_create(ifaceobj.name, 'bridge')
-            else:
-                self.ipcmd.link_create(ifaceobj.name, 'bridge')
-        except Exception, e:
-            raise Exception(str(e))
+            self._apply_bridge_vlan_aware_port_settings_all(ifaceobj, bridge_vids, bridge_pvid)
+        except Exception as e:
+            self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
+            return
+
+    def up_bridge_port(self, ifaceobj, ifaceobj_getfunc):
+        should_enslave_port, bridge_name = self.bridge_port_get_bridge_name(ifaceobj)
+
+        if not bridge_name:
+            # bridge doesn't exist
+            return
+
+        vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridge_name)
+        if vlan_aware_bridge:
+            self.up_bridge_port_vlan_aware_bridge(ifaceobj,
+                                                  ifaceobj_getfunc,
+                                                  bridge_name,
+                                                  should_enslave_port)
+
+        bridge_ifaceobj = ifaceobj_getfunc(bridge_name)[0]
+
+        self.up_apply_brports_attributes(target_ports=[ifaceobj.name],
+                                         ifaceobj=bridge_ifaceobj,
+                                         ifaceobj_getfunc=ifaceobj_getfunc,
+                                         bridge_vlan_aware=vlan_aware_bridge)
+
+        ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED
+
+    def up_check_bridge_vlan_aware(self, ifaceobj, ifaceobj_getfunc, link_exists):
+        if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE:
+            if not self.check_bridge_vlan_aware_port(ifaceobj, ifaceobj_getfunc):
+                return False
+            if link_exists:
+                ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name, 0) | bridgeFlags.PORT_PROCESSED_OVERRIDE
+            return True
+        return False
+
+    @staticmethod
+    def parse_interface_list_value(user_config):
+        config = dict()
+        for entry in user_config.split():
+            ifname, value = entry.split('=')
+            config[ifname] = value
+        return config
+
+    def sync_bridge_learning_to_vxlan_brport(self, bridge_name, bridge_vlan_aware, brport_ifaceobj,
+                                             brport_name, brport_ifla_info_slave_data, brport_learning):
+        """
+            brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
+            and
+            brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
+
+            Checks are not performed in this function and must be verified
+             before. This is done this way to avoid calling this method on
+             non vlan & bridge port interfaces thus wasting a bit less time
+        """
+
+        kind = None
+        ifla_info_data = {}
+
+        brport_vxlan_learning_config = brport_ifaceobj.get_attr_value_first('vxlan-learning')
+        # if the user explicitly defined vxlan-learning we need to honor his config
+        # and not sync vxlan-learning with bridge-learning
+
+        brport_vxlan_learning = self.ipcmd.get_vxlandev_learning(brport_name)
+
+        # if BRIDGE_LEARNING is in the desired configuration
+        # and differs from the running vxlan configuration
+        if brport_learning is not None and brport_learning != brport_vxlan_learning and not brport_vxlan_learning_config:
+            kind = 'vxlan'
+            ifla_info_data = {Link.IFLA_VXLAN_LEARNING: brport_learning}
+            self.logger.info('%s: %s: vxlan learning and bridge learning out of sync: set %s'
+                             % (bridge_name, brport_name, brport_learning))
+
+        elif brport_learning is None and bridge_vlan_aware:
+            # is bridge-learning is not configured but the bridge is vlan-aware
+
+            running_value = self.ipcmd.get_brport_learning_bool(brport_name)
+            default_value = utils.get_boolean_from_string(self.get_mod_subattr('bridge-learning', 'default'))
+
+            if default_value != running_value:
+                brport_ifla_info_slave_data[Link.IFLA_BRPORT_LEARNING] = default_value
+
+                if not brport_vxlan_learning_config:
+                    kind = 'vxlan'
+                    ifla_info_data = {Link.IFLA_VXLAN_LEARNING: default_value}
+                    self.logger.info('%s: %s: reset brport learning to %s and sync vxlan learning'
+                                     % (bridge_name, brport_name, default_value))
+
+        # if kind and ifla_info_data are set they will be added to the
+        # netlink request on the VXLAN brport, to sync IFLA_VXLAN_LEARNING
+        return kind, ifla_info_data
+
+    def check_vxlan_brport_arp_suppress(self, ifaceobj, bridge_vlan_aware, brport_ifaceobj, brport_name, user_config):
+        if user_config:
+            if self.arp_nd_suppress_only_on_vxlan and not brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
+                self.logger.warning('%s: %s: \'bridge-arp-nd-suppress\' '
+                                    'is not supported on a non-vxlan port'
+                                    % (ifaceobj.name, brport_name))
+                raise Exception()
+        elif (bridge_vlan_aware and
+                  (not self.arp_nd_suppress_only_on_vxlan or
+                       (self.arp_nd_suppress_only_on_vxlan and
+                                brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN))):
+            return self.get_mod_subattr('bridge-arp-nd-suppress', 'default')
+        return None
+
+    def up_apply_brports_attributes(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware, target_ports=[], newly_enslaved_ports=[]):
+        ifname = ifaceobj.name
+
         try:
-            self._add_ports(ifaceobj)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
+            brports_ifla_info_slave_data    = dict()
+            brport_ifaceobj_dict            = dict()
+
+            running_brports = self.brctlcmd.get_bridge_ports(ifname)
+
+            if target_ports:
+                new_targets = []
+                for brport_name in target_ports:
+                    if brport_name not in running_brports:
+                        self.logger.info('%s: not enslaved to bridge %s: ignored for now' % (brport_name, ifname))
+                    else:
+                        new_targets.append(brport_name)
+                running_brports = new_targets
+
+            self.logger.info('%s: applying bridge port configuration: %s' % (ifname, running_brports))
+
+            # If target_ports is specified we want to configure only this
+            # sub-list of port we need to check if these ports are already
+            # enslaved, if not they will be ignored.
+            # If target_ports is not populated we will apply the brport
+            # attributes on all running brport.
+
+            for port in running_brports:
+                brport_list = ifaceobj_getfunc(port)
+                if brport_list:
+                    brport_ifaceobj_dict[port] = brport_list[0]
+                    brports_ifla_info_slave_data[port] = dict()
+
+            bridge_ports_learning = {}
+
+            # we iterate through all IFLA_BRPORT supported attributes
+            for attr_name, nl_attr in self._ifla_brport_attributes_map:
+                br_config = ifaceobj.get_attr_value_first(attr_name)
+                translate_func = self._ifla_brport_attributes_translate_user_config_to_netlink_map.get(nl_attr)
+
+                if not translate_func:
+                    # if no translation function is found,
+                    # we ignore this attribute and continue
+                    continue
+
+                if not br_config:
+                    # user didn't specify any value for this attribute
+                    # looking at policy overrides
+                    br_config = policymanager.policymanager_api.get_iface_default(
+                        module_name=self.__class__.__name__,
+                        ifname=ifname,
+                        attr=attr_name
+                    )
+
+                if br_config:
+                    #if bridge_vlan_aware:
+                    #    self.logger.info('%s: is a vlan-aware bridge, "%s %s" '
+                    #                     'should be configured under the ports'
+                    #                     % (ifname, attr_name, br_config))
+
+                    # convert the <interface-yes-no-0-1-list> and <interface-range-list> value to subdict
+                    # brport_name: { attr: value }
+                    # example:
+                    #   bridge-portprios swp1=5 swp2=32
+                    # swp1: { bridge-portprios: 5 } swp2: { bridge-portprios: 32}
+                    if '=' in br_config:
+                        try:
+                            br_config = self.parse_interface_list_value(br_config)
+                        except:
+                            self.log_error('error while parsing \'%s %s\'' % (attr_name, br_config))
+                            continue
+
+                for brport_ifaceobj in brport_ifaceobj_dict.values():
+                    brport_config = brport_ifaceobj.get_attr_value_first(attr_name)
+                    brport_name = brport_ifaceobj.name
+
+                    if not ifupdownflags.flags.PERFMODE and brport_name not in newly_enslaved_ports:
+                        # if the port has just been enslaved, info_slave_data is not cached yet
+                        cached_value = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', nl_attr])
+                    else:
+                        cached_value = None
+
+                    if not brport_config:
+                        # if a brport attribute was specified under the bridge and not under the port
+                        # we assign the bridge value to the port. If an attribute is both defined under
+                        # the bridge and the brport we keep the value of the port and ignore the br val.
+                        if type(br_config) == dict:
+                            # if the attribute value was in the format interface-list-value swp1=XX swp2=YY
+                            # br_config is a dictionary, example:
+                            # bridge-portprios swp1=5 swp2=32 = {swp1: 5, swp2: 32}
+                            brport_config = br_config.get(brport_name)
+                        else:
+                            brport_config = br_config
+
+                    if not brport_config:
+                        brport_config = policymanager.policymanager_api.get_iface_default(
+                            module_name=self.__class__.__name__,
+                            ifname=brport_name,
+                            attr=attr_name
+                        )
+
+                    user_config = brport_config
+
+                    # attribute specific work
+                    # This shouldn't be here but we don't really have a choice otherwise this
+                    # will require too much code duplication and will make the code very complex
+                    if nl_attr == Link.IFLA_BRPORT_ARP_SUPPRESS:
+                        try:
+                            arp_suppress = self.check_vxlan_brport_arp_suppress(ifaceobj,
+                                                                                bridge_vlan_aware,
+                                                                                brport_ifaceobj,
+                                                                                brport_name,
+                                                                                user_config)
+                            if arp_suppress:
+                                user_config = arp_suppress
+                        except:
+                            continue
+                    elif nl_attr == Link.IFLA_BRPORT_GROUP_FWD_MASK:
+                        # special handking for group_fwd_mask because Cisco proprietary
+                        # protocol needs to be set via a private netlink attribute
+                        self.ifla_brport_group_fwd_mask(ifname, brport_name,
+                                                        brports_ifla_info_slave_data,
+                                                        user_config, cached_value)
+                        continue
+
+                    #if brport_config:
+                    #    if not bridge_vlan_aware:
+                    #        self.logger.info('%s: %s: is not a vlan-aware bridge, "%s %s" '
+                    #                         'should be configured under the bridge'
+                    #                         % (ifname, brport_name,
+                    #                            attr_name, brport_config))
+
+                    if user_config:
+                        user_config_nl = translate_func(user_config)
+                        # check config value against running value
+                        if user_config_nl != cached_value:
+                            brports_ifla_info_slave_data[brport_name][nl_attr] = user_config_nl
+                            self.logger.info('%s: %s: set %s %s' % (ifname, brport_name, attr_name, user_config))
+                            self.logger.debug('(cache %s)' % cached_value)
+
+                        if nl_attr == Link.IFLA_BRPORT_LEARNING:
+                            # for vxlan-learning sync purposes we need to save the user config for each brports.
+                            # The dictionary 'brports_ifla_info_slave_data' might not contain any value for
+                            # IFLA_BRPORT_LEARNING if the user value is already configured and running
+                            # nevertheless we still need to check if the vxlan-learning is rightly synced with
+                            # the brport since it might go out of sync for X and Y reasons.
+                            bridge_ports_learning[brport_name] = user_config_nl
+
+                    elif cached_value is not None:
+                        # no config found, do we need to reset to default?
+                        default = self.get_attr_default_value(attr_name)
+                        if default:
+                            default_netlink = translate_func(default)
+
+                            if (nl_attr == Link.IFLA_BRPORT_LEARNING
+                                and not ifupdownflags.flags.PERFMODE
+                                    and brport_name not in newly_enslaved_ports):
+                                try:
+                                    if self.ipcmd.get_brport_peer_link(brport_name):
+                                        if default_netlink != cached_value:
+                                            self.logger.debug('%s: %s: bridge port peerlink: ignoring bridge-learning'
+                                                              % (ifname, brport_name))
+                                        continue
+                                    bridge_ports_learning[brport_name] = default_netlink
+                                except Exception as e:
+                                    self.logger.debug('%s: %s: peerlink check: %s' % (ifname, brport_name, str(e)))
+
+                            if default_netlink != cached_value:
+                                self.logger.info('%s: %s: %s: no configuration detected, resetting to default %s'
+                                                 % (ifname, brport_name, attr_name, default))
+                                self.logger.debug('(cache %s)' % cached_value)
+                                brports_ifla_info_slave_data[brport_name][nl_attr] = default_netlink
+
+            # applying bridge port configuration via netlink
+            for brport_name, brport_ifla_info_slave_data in brports_ifla_info_slave_data.items():
+
+                brport_ifaceobj = brport_ifaceobj_dict.get(brport_name)
+                if (brport_ifaceobj
+                    and brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN
+                    and brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
+                    # if the brport is a VXLAN, we might need to sync the VXLAN learning with the brport_learning val
+                    # we use the same netlink request, by specfying kind=vxlan and ifla_info_data={vxlan_learning=0/1}
+                    kind, ifla_info_data = self.sync_bridge_learning_to_vxlan_brport(ifaceobj.name,
+                                                                                     bridge_vlan_aware,
+                                                                                     brport_ifaceobj,
+                                                                                     brport_name,
+                                                                                     brport_ifla_info_slave_data,
+                                                                                     bridge_ports_learning.get(brport_name))
+
+                    cached_bridge_mcsnoop = self.brctlcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BR_MCAST_SNOOPING])
+
+                    if (self.vxlan_bridge_igmp_snooping_enable_port_mcrouter and utils.get_boolean_from_string(
+                            self.get_bridge_mcsnoop_value(ifaceobj)
+                    )) or cached_bridge_mcsnoop:
+                        # if policy "vxlan_bridge_igmp_snooping_enable_port_mcrouter"
+                        # is on and mcsnoop is on (or mcsnoop is already enabled on the
+                        # bridge, set 'bridge-portmcrouter 2' on vxlan ports (if not set by the user)
+                        if not brport_ifla_info_slave_data.get(Link.IFLA_BRPORT_MULTICAST_ROUTER):
+                            brport_ifla_info_slave_data[Link.IFLA_BRPORT_MULTICAST_ROUTER] = 2
+                            self.logger.info("%s: %s: vxlan bridge igmp snooping: enable port multicast router" % (ifname, brport_name))
+                else:
+                    kind = None
+                    ifla_info_data = {}
+
+                if brport_ifla_info_slave_data or ifla_info_data:
+                    try:
+                        netlink.link_add_set(ifname=brport_name,
+                                             kind=kind,
+                                             ifla_info_data=ifla_info_data,
+                                             slave_kind='bridge',
+                                             ifla_info_slave_data=brport_ifla_info_slave_data)
+                    except Exception as e:
+                        self.logger.warning('%s: %s: %s' % (ifname, brport_name, str(e)))
+
+            self._set_bridge_vidinfo_compat(ifaceobj)
+            self._set_bridge_mcqv4src_compat(ifaceobj)
+            self._process_bridge_maxwait(ifaceobj, self._get_bridge_port_list(ifaceobj))
+
+        except Exception as e:
+            self.log_error(str(e), ifaceobj)
+
+    def ifla_brport_group_fwd_mask(self, ifname, brport_name, brports_ifla_info_slave_data, user_config, cached_ifla_brport_group_fwd_mask):
+        """
+            Support for IFLA_BRPORT_GROUP_FWD_MASK and IFLA_BRPORT_GROUP_FWD_MASKHI
+            Since this is the only ifupdown2 attribute dealing with more than 1 netlink
+            field we need to have special handling for that.
+        """
+        ifla_brport_group_fwd_mask = 0
+        ifla_brport_group_fwd_maskhi = 0
+        if user_config:
+            for group in re.split(',|\s*', user_config):
+                if not group:
+                    continue
+
+                callback = self.l2protocol_tunnel_callback.get(group)
+
+                if not callable(callback):
+                    self.logger.warning('%s: %s: bridge-l2protocol-tunnel ignoring invalid parameter \'%s\'' % (ifname, brport_name, group))
+                else:
+                    ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi = callback(ifla_brport_group_fwd_mask, ifla_brport_group_fwd_maskhi)
+
+        # cached_ifla_brport_group_fwd_mask is given as parameter because it was already pulled out from the cache in the functio above
+        cached_ifla_brport_group_fwd_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
+
+        log_mask_change = True
+        # if user specify bridge-l2protocol-tunnel stp cdp
+        # we need to set both MASK and MASKHI but we only want to log once
+
+        if cached_ifla_brport_group_fwd_mask is None:
+            cached_ifla_brport_group_fwd_mask = 0
+        if cached_ifla_brport_group_fwd_maskhi is None:
+            cached_ifla_brport_group_fwd_maskhi = 0
+
+        # if the cache value is None it means that the kernel doesn't support this attribute
+        # or that the cache is stale, we dumped this intf before it was enslaved in the bridge
+
+        if ifla_brport_group_fwd_mask != cached_ifla_brport_group_fwd_mask:
+            if log_mask_change:
+                self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
+                self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_mask)
+                log_mask_change = False
+            brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASK] = ifla_brport_group_fwd_mask
+
+        if ifla_brport_group_fwd_maskhi != cached_ifla_brport_group_fwd_maskhi:
+            if log_mask_change:
+                self.logger.info('%s: %s: set bridge-l2protocol-tunnel %s' % (ifname, brport_name, user_config))
+                self.logger.debug('(cache %s)' % cached_ifla_brport_group_fwd_maskhi)
+            brports_ifla_info_slave_data[brport_name][Link.IFLA_BRPORT_GROUP_FWD_MASKHI] = ifla_brport_group_fwd_maskhi
+
+    def up_bridge(self, ifaceobj, ifaceobj_getfunc):
+        ifname = ifaceobj.name
+
+        if ifupdownflags.flags.PERFMODE:
+            link_just_created = True
+            link_exists = False
+        else:
+            link_exists = self.ipcmd.link_exists(ifaceobj.name)
+            link_just_created = not link_exists
+
+        if not link_exists:
+            netlink.link_add_bridge(ifname)
+        else:
+            self.logger.info('%s: bridge already exists' % ifname)
+
+        bridge_vlan_aware = self.up_check_bridge_vlan_aware(ifaceobj, ifaceobj_getfunc, not link_just_created)
+
+        self.up_apply_bridge_settings(ifaceobj, link_just_created, bridge_vlan_aware)
 
         try:
-            self._apply_bridge_settings(ifaceobj)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
+            newly_enslaved_ports = self._add_ports(ifaceobj, ifaceobj_getfunc)
+            self.up_apply_brports_attributes(ifaceobj, ifaceobj_getfunc, bridge_vlan_aware,
+                                             newly_enslaved_ports=newly_enslaved_ports)
+        except Exception as e:
+            self.logger.warning('%s: apply bridge ports settings: %s' % (ifname, str(e)))
 
+        running_ports = ''
         try:
             running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
             if not running_ports:
-               return
-            # disable ipv6 for ports that were added to bridge
-            self._ports_enable_disable_ipv6(running_ports, '1')
+                return
+            self.handle_ipv6([], '1', ifaceobj=ifaceobj)
             self._apply_bridge_port_settings_all(ifaceobj,
-                            ifaceobj_getfunc=ifaceobj_getfunc)
-        except Exception, e:
-            err = True
-            errstr = str(e)
-            pass
-            #self._flush_running_vidinfo()
+                                                 ifaceobj_getfunc=ifaceobj_getfunc,
+                                                 bridge_vlan_aware=bridge_vlan_aware)
+        except exceptions.ReservedVlanException as e:
+            raise e
+        except Exception as e:
+            self.logger.warning('%s: apply bridge settings: %s' % (ifname, str(e)))
         finally:
             if ifaceobj.link_type != ifaceLinkType.LINK_NA:
                 for p in running_ports:
+                    ifaceobj_list = ifaceobj_getfunc(p)
+                    if (ifaceobj_list and ifaceobj_list[0].link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN):
+                        netlink.link_set_updown(p, "down")
+                        continue
                     try:
-                        rtnetlink_api.rtnl_api.link_set(p, "up")
+                        netlink.link_set_updown(p, "up")
                     except Exception, e:
                         self.logger.debug('%s: %s: link set up (%s)'
-                                          %(ifaceobj.name, p, str(e)))
+                                          % (ifaceobj.name, p, str(e)))
                         pass
 
-            if ifaceobj.addr_method == 'manual':
-               rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
-        if err:
-            raise Exception(errstr)
+        try:
+            self._up_bridge_mac(ifaceobj, ifaceobj_getfunc)
+        except Exception as e:
+            self.logger.warning('%s: setting bridge mac address: %s' % (ifaceobj.name, str(e)))
+
+    def _get_bridge_mac(self, ifaceobj, ifname, ifaceobj_getfunc):
+        if self.bridge_mac_iface and self.bridge_mac_iface[0] and self.bridge_mac_iface[1]:
+            return self.bridge_mac_iface
+
+        if self.bridge_mac_iface_list:
+            self.logger.debug('bridge mac iface list: %s' % self.bridge_mac_iface_list)
+
+            for bridge_mac_intf in self.bridge_mac_iface_list:
+                ifaceobj_list = ifaceobj_getfunc(bridge_mac_intf)
+                iface_mac = None
+
+                if ifaceobj_list:
+                    for obj in ifaceobj_list:
+                        iface_user_configured_hwaddress = utils.strip_hwaddress(obj.get_attr_value_first('hwaddress'))
+                        # if user did configured 'hwaddress' we need to use this value instead of the cached value.
+                        if iface_user_configured_hwaddress:
+                            iface_mac = iface_user_configured_hwaddress
+
+                if not iface_mac and not self.ipcmd.link_exists(bridge_mac_intf):
+                    continue
+
+                if not iface_mac:
+                    iface_mac = self.ipcmd.cache_get('link', [bridge_mac_intf, 'hwaddress'])
+                    # if hwaddress attribute is not configured we use the running mac addr
+
+                self.bridge_mac_iface = (bridge_mac_intf, iface_mac)
+                return self.bridge_mac_iface
+        elif self.bridge_set_static_mac_from_port:
+            # no policy was provided, we need to get the first physdev or bond ports
+            # and use its hwaddress to set the bridge mac
+            for port in self._get_bridge_port_list_user_ordered(ifaceobj) or []:
+                # iterate through the bridge-port list
+                for port_obj in ifaceobj_getfunc(port) or []:
+                    # check if the port is a physdev (link_kind is null) or a bon
+                    if port_obj.link_kind != ifaceLinkKind.VXLAN:
+                        iface_user_configured_hwaddress = utils.strip_hwaddress(port_obj.get_attr_value_first('hwaddress'))
+                        # if user did configured 'hwaddress' we need to use this value instead of the cached value.
+                        if iface_user_configured_hwaddress:
+                            iface_mac = iface_user_configured_hwaddress.lower()
+                            # we need to "normalize" the user provided MAC so it can match with
+                            # what we have in the cache (data retrieved via a netlink dump by
+                            # nlmanager). nlmanager return all macs in lower-case
+                        else:
+                            iface_mac = self.ipcmd.link_get_hwaddress(port)
+
+                        if iface_mac:
+                            self.bridge_mac_iface = (port, iface_mac)
+                            return self.bridge_mac_iface
+
+        return None, None
+
+    def _add_bridge_mac_to_fdb(self, ifaceobj, bridge_mac):
+        if not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE and bridge_mac and ifaceobj.get_attr_value('address'):
+            self.ipcmd.bridge_fdb_add(ifaceobj.name, bridge_mac, vlan=None, bridge=True, remote=None)
+
+    def _up_bridge_mac(self, ifaceobj, ifaceobj_getfunc):
+        """
+        We have a day one bridge mac changing problem with changing ports
+        (basically bridge mac changes when the port it inherited the mac from
+        gets de-enslaved).
+
+        We have discussed this problem many times before and tabled it.
+        The issue has aggravated with vxlan bridge ports having auto-generated
+        random macs...which change on every reboot.
+
+        ifupdown2 extract from policy files an iface to select a mac from and
+        configure it automatically.
+        """
+        if ifaceobj.get_attr_value('hwaddress'):
+            # if the user configured a static hwaddress
+            # there is no need to assign one
+            return
+
+        ifname = ifaceobj.name
+        mac_intf, bridge_mac = self._get_bridge_mac(ifaceobj, ifname, ifaceobj_getfunc)
+        self.logger.debug("%s: _get_bridge_mac returned (%s, %s)"
+                          %(ifname, mac_intf, bridge_mac))
+
+        if bridge_mac:
+            # if an interface is configured with the following attribute:
+            # hwaddress 08:00:27:42:42:4
+            # the cache_check won't match because nlmanager return "08:00:27:42:42:04"
+            # from the kernel. The only way to counter that is to convert all mac to int
+            # and compare the ints, it will increase perfs and be safer.
+            cached_value = self.ipcmd.cache_get('link', [ifname, 'hwaddress'])
+            self.logger.debug('%s: cached hwaddress value: %s' % (ifname, cached_value))
+            if cached_value and cached_value == bridge_mac:
+                # the bridge mac is already set to the bridge_mac_intf's mac
+                return
+
+            self.logger.info('%s: setting bridge mac to port %s mac' % (ifname, mac_intf))
+            try:
+                self.ipcmd.link_set(ifname, 'address', value=bridge_mac, force=True)
+            except Exception as e:
+                self.logger.info('%s: %s' % (ifname, str(e)))
+                # log info this error because the user didn't explicitly configured this
+        else:
+            self._add_bridge_mac_to_fdb(ifaceobj, self.ipcmd.link_get_hwaddress(ifname))
+
+    def _up(self, ifaceobj, ifaceobj_getfunc=None):
+        if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
+            self.up_bridge_port(ifaceobj, ifaceobj_getfunc)
+
+        elif ifaceobj.link_kind & ifaceLinkKind.BRIDGE:
+            self.up_bridge(ifaceobj, ifaceobj_getfunc)
+
+        else:
+            bridge_attributes = self._modinfo.get('attrs', {}).keys()
+
+            for ifaceobj_config_attr in ifaceobj.config.keys():
+                if ifaceobj_config_attr in bridge_attributes:
+                    self.logger.warning('%s: invalid use of bridge attribute (%s) on non-bridge stanza'
+                                        % (ifaceobj.name, ifaceobj_config_attr))
 
     def _down(self, ifaceobj, ifaceobj_getfunc=None):
+        if not self._is_bridge(ifaceobj):
+            return
+        ifname = ifaceobj.name
+        if not self.ipcmd.link_exists(ifname):
+            return
         try:
-            if ifaceobj.get_attr_value_first('bridge-ports'):
-                ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
-                self.brctlcmd.delete_bridge(ifaceobj.name)
-                if ports:
-                    self._ports_enable_disable_ipv6(ports, '0')
-                    if ifaceobj.link_type != ifaceLinkType.LINK_NA:
-                        map(lambda p: rtnetlink_api.rtnl_api.link_set(p,
-                                    "down"), ports)
-        except Exception, e:
-            self.log_error(str(e))
+            running_ports = self.brctlcmd.get_bridge_ports(ifname)
+            if running_ports:
+                self.handle_ipv6(running_ports, '0')
+                if ifaceobj.link_type != ifaceLinkType.LINK_NA:
+                    map(lambda p: netlink.link_set_updown(p, 'down'), running_ports)
+        except Exception as e:
+            self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
+        try:
+            netlink.link_del(ifname)
+        except Exception as e:
+            ifaceobj.set_status(ifaceStatus.ERROR)
+            self.logger.error(str(e))
+            # netlink exception already contains the ifname
 
     def _query_running_vidinfo_compat(self, ifaceobjrunning, ports):
         running_attrs = {}
-        running_vidinfo = self._get_running_vidinfo()
         if ports:
             running_bridge_port_vids = ''
             for p in ports:
                 try:
-                    running_vids = running_vidinfo.get(p, {}).get('vlan')
+                    running_vids = self._get_runing_vids(p)
                     if running_vids:
                         running_bridge_port_vids += ' %s=%s' %(p,
                                                       ','.join(running_vids))
@@ -901,44 +2240,39 @@ class bridge(moduleBase):
                     pass
             running_attrs['bridge-port-vids'] = running_bridge_port_vids
 
-            running_bridge_port_pvids = ''
+            running_bridge_port_pvid = ''
             for p in ports:
                 try:
-                    running_pvids = running_vidinfo.get(p, {}).get('pvid')
-                    if running_pvids:
-                        running_bridge_port_pvids += ' %s=%s' %(p,
-                                                        running_pvids)
+                    running_pvid = self._get_runing_pvid(p)
+                    if running_pvid:
+                        running_bridge_port_pvid += ' %s=%s' %(p,
+                                                        running_pvid)
                 except Exception:
                     pass
-            running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
+            running_attrs['bridge-port-pvids'] = running_bridge_port_pvid
 
-        running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name,
-                                                  {}).get('vlan')
+        running_bridge_vids = self.ipcmd.bridge_vlan_get_vids(ifaceobjrunning.name)
         if running_bridge_vids:
-            running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
+            running_attrs['bridge-vids'] = ','.join(self._compress_into_ranges(running_bridge_vids))
         return running_attrs
 
     def _query_running_vidinfo(self, ifaceobjrunning, ifaceobj_getfunc,
                                bridgeports=None):
         running_attrs = {}
-        running_vidinfo = self._get_running_vidinfo()
-        if not running_vidinfo:
-           return running_attrs
 
         # 'bridge-vids' under the bridge is all about 'vids' on the port.
         # so query the ports
         running_bridgeport_vids = []
         running_bridgeport_pvids = []
         for bport in bridgeports:
-            vids = running_vidinfo.get(bport, {}).get('vlan')
+            (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
             if vids:
                 running_bridgeport_vids.append(' '.join(vids))
-            pvids = running_vidinfo.get(bport, {}).get('pvid')
-            if pvids:
-                running_bridgeport_pvids.append(pvids[0])
+            if pvid:
+                running_bridgeport_pvids.append(pvid)
 
         bridge_vids = None
-        if running_bridgeport_vids: 
+        if running_bridgeport_vids:
            (vidval, freq) = Counter(running_bridgeport_vids).most_common()[0]
            if freq == len(bridgeports):
               running_attrs['bridge-vids'] = vidval
@@ -949,26 +2283,29 @@ class bridge(moduleBase):
            (vidval, freq) = Counter(running_bridgeport_pvids).most_common()[0]
            if freq == len(bridgeports) and vidval != '1':
               running_attrs['bridge-pvid'] = vidval
-              bridge_pvid = vidval.split()
+              bridge_pvid = vidval.split()[0]
 
         # Go through all bridge ports and find their vids
         for bport in bridgeports:
             bportifaceobj = ifaceobj_getfunc(bport)
             if not bportifaceobj:
                continue
-            bport_vids = None
-            bport_pvids = None
-            vids = running_vidinfo.get(bport, {}).get('vlan')
+            bport_vids = []
+            bport_pvid = None
+            (vids, pvid) = self._get_running_vids_n_pvid_str(bport)
             if vids and vids != bridge_vids:
                bport_vids = vids
-            pvids = running_vidinfo.get(bport, {}).get('pvid')
-            if pvids and pvids[0] != bridge_pvid:
-               bport_pvids = pvids
-            if not bport_vids and bport_pvids and bport_pvids[0] != '1':
-               bportifaceobj[0].replace_config('bridge-access', bport_pvids[0])
+            if pvid and pvid != bridge_pvid:
+               bport_pvid = pvid
+            if bport_vids and bport_pvid in bport_vids:
+                bport_vids.remove(bport_pvid)
+            if (not bport_vids and bport_pvid and bport_pvid != '1'):
+               bportifaceobj[0].replace_config('bridge-access', bport_pvid)
+               bportifaceobj[0].delete_config('bridge-pvid')
+               bportifaceobj[0].delete_config('bridge-vids')
             else:
-               if bport_pvids and bport_pvids[0] != '1':
-                  bportifaceobj[0].replace_config('bridge-pvid', bport_pvids[0])
+               if bport_pvid and bport_pvid != '1':
+                  bportifaceobj[0].replace_config('bridge-pvid', bport_pvid)
                else:
                   # delete any stale bridge-vids under ports
                   bportifaceobj[0].delete_config('bridge-pvid')
@@ -981,7 +2318,7 @@ class bridge(moduleBase):
         return running_attrs
 
     def _query_running_mcqv4src(self, ifaceobjrunning):
-        running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
+        running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src_sysfs(ifaceobjrunning.name)
         mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
         mcqs.sort()
         mcq = ' '.join(mcqs)
@@ -994,8 +2331,11 @@ class bridge(moduleBase):
         ports = None
         skip_kernel_stp_attrs = 0
 
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
-            userspace_stp = 1
+        try:
+            if self.systcl_get_net_bridge_stp_user_space() == '1':
+                userspace_stp = 1
+        except Exception as e:
+            self.logger.info('%s: %s' % (ifaceobjrunning.name, str(e)))
 
         tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
         if not tmpbridgeattrdict:
@@ -1014,6 +2354,13 @@ class bridge(moduleBase):
         if  stp == 'yes' and userspace_stp:
             skip_kernel_stp_attrs = 1
 
+        vlan_stats = utils.get_onff_from_onezero(
+                            tmpbridgeattrdict.get('vlan-stats', None))
+        if (vlan_stats and
+            vlan_stats != self.get_mod_subattr('bridge-vlan-stats', 'default')):
+            bridgeattrdict['bridge-vlan-stats'] = [vlan_stats]
+
+        bool2str = {'0': 'no', '1': 'yes'}
         # pick all other attributes
         for k,v in tmpbridgeattrdict.items():
             if not v:
@@ -1025,10 +2372,16 @@ class bridge(moduleBase):
                 # only include igmp attributes if kernel stp is off
                 continue
             attrname = 'bridge-' + k
-            if v != self.get_mod_subattr(attrname, 'default'):
+            mod_default = self.get_mod_subattr(attrname, 'default')
+            if v != mod_default:
+                # convert '0|1' running values to 'no|yes'
+                if v in bool2str.keys() and bool2str[v] == mod_default:
+                    continue
                 bridgeattrdict[attrname] = [v]
 
         if bridge_vlan_aware:
+            if not ports:
+                ports = {}
             bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning,
                                                         ifaceobj_getfunc,
                                                         ports.keys())
@@ -1046,20 +2399,57 @@ class bridge(moduleBase):
         if skip_kernel_stp_attrs:
             return bridgeattrdict
 
-        if ports:
+        # Do this only for vlan-UNAWARE-bridge
+        if ports and not bridge_vlan_aware:
             portconfig = {'bridge-pathcosts' : '',
-                          'bridge-portprios' : ''}
+                          'bridge-portprios' : '',
+                          'bridge-learning' : '',
+                          'bridge-unicast-flood' : '',
+                          'bridge-multicast-flood' : '',
+                          'bridge-arp-nd-suppress' : '',
+                         }
             for p, v in ports.items():
-                v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
+                v = self.brctlcmd.bridge_get_pathcost(ifaceobjrunning.name, p)
                 if v and v != self.get_mod_subattr('bridge-pathcosts',
                                                    'default'):
                     portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
 
-                v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
+                v = self.brctlcmd.bridge_get_portprio(ifaceobjrunning.name, p)
                 if v and v != self.get_mod_subattr('bridge-portprios',
                                                    'default'):
                     portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
 
+                v = utils.get_onff_from_onezero(
+                        self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                                                          p, 'learning'))
+                if (v and
+                    v != self.get_mod_subattr('bridge-learning', 'default')):
+                    portconfig['bridge-learning'] += ' %s=%s' %(p, v)
+
+                v = utils.get_onff_from_onezero(
+                        self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                                                          p, 'unicast-flood'))
+                if (v and
+                    v != self.get_mod_subattr('bridge-unicast-flood',
+                                              'default')):
+                    portconfig['bridge-unicast-flood'] += ' %s=%s' %(p, v)
+
+                v = utils.get_onff_from_onezero(
+                        self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                                                          p, 'multicast-flood'))
+                if (v and
+                    v != self.get_mod_subattr('bridge-multicast-flood',
+                                              'default')):
+                    portconfig['bridge-multicast-flood'] += ' %s=%s' %(p, v)
+
+                v = utils.get_onff_from_onezero(
+                        self.brctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
+                                                          p, 'arp-nd-suppress'))
+                if (v and
+                    v != self.get_mod_subattr('bridge-arp-nd-suppress',
+                                              'default')):
+                    portconfig['bridge-arp-nd-suppress'] += ' %s=%s' %(p, v)
+
             bridgeattrdict.update({k : [v] for k, v in portconfig.items()
                                     if v})
 
@@ -1077,21 +2467,20 @@ class bridge(moduleBase):
 
     def _query_check_bridge_vidinfo(self, ifaceobj, ifaceobjcurr):
         err = 0
-        running_vidinfo = self._get_running_vidinfo()
         attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
         if attrval:
             running_bridge_port_vids = ''
-            portlist = self.parse_port_list(attrval)
+            portlist = self.parse_port_list(ifaceobj.name, attrval)
             if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                          %(ifaceobj.name, attrname, attrval))
+                self.log_warn('%s: could not parse \'bridge-port-vids %s\''
+                          %(ifaceobj.name, attrval))
                 return
             err = 0
             for p in portlist:
                 try:
                     (port, val) = p.split('=')
                     vids = val.split(',')
-                    running_vids = running_vidinfo.get(port, {}).get('vlan')
+                    running_vids = self.ipcmd.bridge_vlan_get_vids(port)
                     if running_vids:
                         if not self._compare_vids(vids, running_vids):
                             err += 1
@@ -1113,17 +2502,17 @@ class bridge(moduleBase):
 
         attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
         if attrval:
-            portlist = self.parse_port_list(attrval)
+            portlist = self.parse_port_list(ifaceobj.name, attrval)
             if not portlist:
-                self.log_warn('%s: could not parse \'%s %s\''
-                              %(ifaceobj.name, attrname, attrval))
+                self.log_warn('%s: could not parse \'bridge-port-pvids %s\''
+                              %(ifaceobj.name, attrval))
                 return
             running_bridge_port_pvids = ''
             err = 0
             for p in portlist:
                 try:
                     (port, pvid) = p.split('=')
-                    running_pvid = running_vidinfo.get(port, {}).get('pvid')
+                    running_pvid = self.ipcmd.bridge_vlan_get_vids(port)
                     if running_pvid and running_pvid == pvid:
                         running_bridge_port_pvids += ' %s' %p
                     else:
@@ -1140,26 +2529,15 @@ class bridge(moduleBase):
                 ifaceobjcurr.update_config_with_status('bridge-port-pvids',
                                                  running_bridge_port_pvids, 0)
 
-        # XXX: No need to check for bridge-vids on the bridge
-        # This is used by the ports. The vids on the bridge
-        # come from the vlan interfaces on the bridge.
-        #
-        attrval = ifaceobj.get_attr_value_first('bridge-vids')
-        #if attrval:
-        #    vids = re.split(r'[\s\t]\s*', attrval)
-        #    running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
-        #    if running_vids:
-        #        if self._compare_vids(vids, running_vids):
-        #            ifaceobjcurr.update_config_with_status('bridge-vids',
-        #                                                   attrval, 0)
-        #        else:
-        #            ifaceobjcurr.update_config_with_status('bridge-vids',
-        #                                        ','.join(running_vids), 1)
-        #    else:
-        #        ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
-        #                                               1)
-        if attrval:
-            ifaceobjcurr.update_config_with_status('bridge-vids', attrval, -1)
+        vids = self.get_ifaceobj_bridge_vids(ifaceobj)
+        if vids[1]:
+            ifaceobjcurr.update_config_with_status(vids[0], vids[1], -1)
+
+    def _query_check_snooping_wdefault(self, ifaceobj):
+        if (ifupdownflags.flags.WITHDEFAULTS
+            and not self._vxlan_bridge_default_igmp_snooping
+                and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN):
+            ifaceobj.replace_config('bridge-mcsnoop', 'no')
 
     def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
                             ifaceobj_getfunc=None):
@@ -1169,8 +2547,13 @@ class bridge(moduleBase):
             self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
             return
 
+        self._query_check_snooping_wdefault(ifaceobj)
+
         ifaceattrs = self.dict_key_subset(ifaceobj.config,
                                           self.get_mod_attrs())
+        #Add default attributes if --with-defaults is set
+        if ifupdownflags.flags.WITHDEFAULTS and 'bridge-stp' not in ifaceattrs:
+            ifaceattrs.append('bridge-stp')
         if not ifaceattrs:
             return
         try:
@@ -1182,18 +2565,39 @@ class bridge(moduleBase):
         except Exception, e:
             self.logger.warn(str(e))
             runningattrs = {}
-        filterattrs = ['bridge-vids', 'bridge-port-vids',
+
+        self._query_check_support_yesno_attrs(runningattrs, ifaceobj)
+
+        filterattrs = ['bridge-vids', 'bridge-trunk', 'bridge-port-vids',
                        'bridge-port-pvids']
-        for k in Set(ifaceattrs).difference(filterattrs):
+
+        diff = Set(ifaceattrs).difference(filterattrs)
+
+        if 'bridge-l2protocol-tunnel' in diff:
+            diff.remove('bridge-l2protocol-tunnel')
+            # bridge-l2protocol-tunnel requires separate handling
+
+        if 'bridge-ports' in diff:
+            self.query_check_bridge_ports(ifaceobj, ifaceobjcurr, runningattrs.get('ports', {}).keys(), ifaceobj_getfunc)
+            diff.remove('bridge-ports')
+
+        for k in diff:
             # get the corresponding ifaceobj attr
             v = ifaceobj.get_attr_value_first(k)
             if not v:
-               continue
+                if ifupdownflags.flags.WITHDEFAULTS and k == 'bridge-stp':
+                    v = 'on' if self.default_stp_on else 'off'
+                else:
+                    continue
             rv = runningattrs.get(k[7:])
             if k == 'bridge-mcqv4src':
                continue
-            if k == 'bridge-vlan-aware' and v == 'yes':
-                if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
+            if k == 'bridge-maxwait' or k == 'bridge-waitport':
+                ifaceobjcurr.update_config_with_status(k, v, 0)
+                continue
+            if k == 'bridge-vlan-aware':
+                rv = self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)
+                if (rv and v == 'yes') or (not rv and v == 'no'):
                     ifaceobjcurr.update_config_with_status('bridge-vlan-aware',
                                v, 0)
                 else:
@@ -1203,60 +2607,86 @@ class bridge(moduleBase):
                # special case stp compare because it may
                # contain more than one valid values
                stp_on_vals = ['on', 'yes']
-               stp_off_vals = ['off']
+               stp_off_vals = ['off', 'no']
                if ((v in stp_on_vals and rv in stp_on_vals) or
                    (v in stp_off_vals and rv in stp_off_vals)):
                     ifaceobjcurr.update_config_with_status('bridge-stp',
-                               v, 0)
+                               rv, 0)
                else:
                     ifaceobjcurr.update_config_with_status('bridge-stp',
-                                v, 1)
-            elif k == 'bridge-ports':
-               # special case ports because it can contain regex or glob
-               running_port_list = rv.keys() if rv else []
-               bridge_port_list = self._get_bridge_port_list(ifaceobj)
-               if not running_port_list and not bridge_port_list:
-                  continue
-               portliststatus = 1
-               if running_port_list and bridge_port_list:
-                  difference = set(running_port_list
-                                 ).symmetric_difference(bridge_port_list)
-                  if not difference:
-                     portliststatus = 0
-                  ifaceobjcurr.update_config_with_status('bridge-ports',
-                              ' '.join(running_port_list)
-                              if running_port_list else '', portliststatus)
-            elif (k == 'bridge-pathcosts' or
-                  k == 'bridge-portprios' or k == 'bridge-portmcrouter'
-                  or k == 'bridge-portmcfl'):
-               brctlcmdattrname = k[11:].rstrip('s')
+                               rv, 1)
+            elif k in ['bridge-pathcosts',
+                       'bridge-portprios',
+                       'bridge-portmcrouter',
+                       'bridge-portmcfl',
+                       'bridge-learning',
+                       'bridge-unicast-flood',
+                       'bridge-multicast-flood',
+                       'bridge-arp-nd-suppress',
+                      ]:
+               if k == 'bridge-arp-nd-suppress':
+                  brctlcmdattrname = k[7:]
+               else:
+                  brctlcmdattrname = k[7:].rstrip('s')
                # for port attributes, the attributes are in a list
                # <portname>=<portattrvalue>
                status = 0
                currstr = ''
-               vlist = self.parse_port_list(v)
+               vlist = self.parse_port_list(ifaceobj.name, v)
                if not vlist:
                   continue
                for vlistitem in vlist:
                    try:
                       (p, v) = vlistitem.split('=')
-                      currv = self.brctlcmd.get_bridgeport_attr(
+                      if k in ['bridge-learning',
+                               'bridge-unicast-flood',
+                               'bridge-multicast-flood',
+                               'bridge-arp-nd-suppress',
+                              ]:
+                         currv = utils.get_onoff_bool(
+                                    self.brctlcmd.get_bridgeport_attr(
+                                         ifaceobj.name, p,
+                                         brctlcmdattrname))
+                      else:
+                         currv = self.brctlcmd.get_bridgeport_attr(
                                          ifaceobj.name, p,
                                          brctlcmdattrname)
                       if currv:
                           currstr += ' %s=%s' %(p, currv)
                       else:
                           currstr += ' %s=%s' %(p, 'None')
-                      if currv != v:
+
+                      if k == 'bridge-portmcrouter':
+                          if self._ifla_brport_multicast_router_dict_to_int.get(v) != int(currv):
+                              status = 1
+                      elif currv != v:
                           status = 1
                    except Exception, e:
                       self.log_warn(str(e))
                    pass
                ifaceobjcurr.update_config_with_status(k, currstr, status)
+            elif k == 'bridge-vlan-stats' or k == 'bridge-mcstats':
+                rv = utils.get_onff_from_onezero(rv)
+                if v != rv:
+                    ifaceobjcurr.update_config_with_status(k, rv, 1)
+                else:
+                    ifaceobjcurr.update_config_with_status(k, rv, 0)
             elif not rv:
-               ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
+               if k == 'bridge-pvid' or k == 'bridge-vids' or k == 'bridge-trunk' or k == 'bridge-allow-untagged':
+                   # bridge-pvid and bridge-vids on a bridge does
+                   # not correspond directly to a running config
+                   # on the bridge. They correspond to default
+                   # values for the bridge ports. And they are
+                   # already checked against running config of the
+                   # bridge port and reported against a bridge port.
+                   # So, ignore these attributes under the bridge.
+                   # Use '2' for ignore today. XXX: '2' will be
+                   # mapped to a defined value in subsequent patches.
+                   ifaceobjcurr.update_config_with_status(k, v, 2)
+               else:
+                   ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
                continue
-            elif v != rv:
+            elif v.upper() != rv.upper():
                ifaceobjcurr.update_config_with_status(k, rv, 1)
             else:
                ifaceobjcurr.update_config_with_status(k, rv, 0)
@@ -1264,11 +2694,48 @@ class bridge(moduleBase):
         self._query_check_bridge_vidinfo(ifaceobj, ifaceobjcurr)
 
         self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
+        self._query_check_l2protocol_tunnel_on_bridge(ifaceobj, ifaceobjcurr, runningattrs)
+
+    def query_check_bridge_ports(self, ifaceobj, ifaceobjcurr, running_port_list, ifaceobj_getfunc):
+        bridge_all_ports = []
+        for obj in ifaceobj_getfunc(ifaceobj.name) or []:
+            bridge_all_ports.extend(self._get_bridge_port_list(obj) or [])
+
+        if not running_port_list and not bridge_all_ports:
+            return
+
+        ports_list_status = 0 if not set(running_port_list).symmetric_difference(bridge_all_ports) else 1
+
+        try:
+            port_list = self._get_ifaceobj_bridge_ports(ifaceobj).split()
+            # we want to display the same bridge-ports list as provided
+            # in the interfaces file but if this list contains regexes or
+            # globs, for now, we won't try to change it.
+            if 'regex' in port_list or 'glob' in port_list:
+                port_list = running_port_list
+            else:
+                ordered = []
+                for i in range(0, len(port_list)):
+                    if port_list[i] in running_port_list:
+                        ordered.append(port_list[i])
+                port_list = ordered
+        except:
+            port_list = running_port_list
+        ifaceobjcurr.update_config_with_status('bridge-ports', (' '.join(port_list) if port_list else ''), ports_list_status)
+
+    def get_ifaceobj_bridge_vids(self, ifaceobj):
+        vids = ('bridge-vids', ifaceobj.get_attr_value_first('bridge-vids'))
+        if not vids[1]:
+            vids = ('bridge-trunk', ifaceobj.get_attr_value_first('bridge-trunk'))
+        return vids
+
+    def get_ifaceobj_bridge_vids_value(self, ifaceobj):
+        return self.get_ifaceobj_bridge_vids(ifaceobj)[1]
 
     def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
         ifaceobjs = ifaceobj_getfunc(bridgename)
         for ifaceobj in ifaceobjs:
-            vids = ifaceobj.get_attr_value_first('bridge-vids')
+            vids = self.get_ifaceobj_bridge_vids_value(ifaceobj)
             if vids: return re.split(r'[\s\t,]\s*', vids)
         return None
 
@@ -1277,6 +2744,8 @@ class bridge(moduleBase):
         pvid = None
         for ifaceobj in ifaceobjs:
             pvid = ifaceobj.get_attr_value_first('bridge-pvid')
+            if pvid:
+                break
         return pvid
 
     def _get_bridge_name(self, ifaceobj):
@@ -1284,69 +2753,82 @@ class bridge(moduleBase):
 
     def _query_check_bridge_port_vidinfo(self, ifaceobj, ifaceobjcurr,
                                          ifaceobj_getfunc, bridgename):
-        running_vidinfo = self._get_running_vidinfo()
-
         attr_name = 'bridge-access'
-        vids = ifaceobj.get_attr_value_first(attr_name)
-        if vids:
-           running_pvids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('pvid')
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
-           if (not running_pvids or running_pvids != vids or
-                   running_vids):
+        vid = ifaceobj.get_attr_value_first(attr_name)
+        if vid:
+            (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
+                                                        ifaceobj.name)
+            if (not running_pvid or running_pvid != vid or
+                (running_vids and running_vids[0] != vid)):
                ifaceobjcurr.update_config_with_status(attr_name,
-                                running_pvids, 1)
-           else:
-               ifaceobjcurr.update_config_with_status(attr_name, vids, 0)
-           return
+                                running_pvid, 1)
+            else:
+               ifaceobjcurr.update_config_with_status(attr_name, vid, 0)
+            return
 
-        attr_name = 'bridge-vids'
-        vids = ifaceobj.get_attr_value_first(attr_name)
+        (running_vids, running_pvid) = self._get_running_vids_n_pvid_str(
+                                                        ifaceobj.name)
+        attr_name = 'bridge-pvid'
+        pvid = ifaceobj.get_attr_value_first('bridge-pvid')
+        if pvid:
+            if running_pvid and running_pvid == pvid:
+                ifaceobjcurr.update_config_with_status(attr_name,
+                                                       running_pvid, 0)
+            else:
+                ifaceobjcurr.update_config_with_status(attr_name,
+                                                       running_pvid, 1)
+        elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
+              ((ifaceobj.flags & iface.HAS_SIBLINGS) and
+               (ifaceobj.flags & iface.OLDEST_SIBLING))):
+            # if the interface has multiple iface sections,
+            # we check the below only for the oldest sibling
+            # or the last iface section
+            pvid = self._get_bridge_pvid(bridgename, ifaceobj_getfunc)
+            if pvid:
+                if not running_pvid or running_pvid != pvid:
+                    ifaceobjcurr.status = ifaceStatus.ERROR
+                    ifaceobjcurr.status_str = 'bridge pvid error'
+            elif not running_pvid or running_pvid != '1':
+                ifaceobjcurr.status = ifaceStatus.ERROR
+                ifaceobjcurr.status_str = 'bridge pvid error'
+
+        attr_name, vids = self.get_ifaceobj_bridge_vids(ifaceobj)
         if vids:
            vids = re.split(r'[\s\t]\s*', vids)
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
-           if not running_vids or not self._compare_vids(vids, running_vids):
+           if not running_vids or not self._compare_vids(vids, running_vids,
+                                                         running_pvid):
                ifaceobjcurr.update_config_with_status(attr_name,
-                                ' '.join(running_vids), 1)
+                                            ' '.join(running_vids), 1)
            else:
                ifaceobjcurr.update_config_with_status(attr_name,
-                                ' '.join(running_vids), 0)
-        else:
+                                            ' '.join(vids), 0)
+        elif (not (ifaceobj.flags & iface.HAS_SIBLINGS) or
+              ((ifaceobj.flags & iface.HAS_SIBLINGS) and
+               (ifaceobj.flags & iface.OLDEST_SIBLING))):
+           # if the interface has multiple iface sections,
+           # we check the below only for the oldest sibling
+           # or the last iface section
+
            # check if it matches the bridge vids
            bridge_vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
-           running_vids = running_vidinfo.get(ifaceobj.name,
-                                              {}).get('vlan')
            if (bridge_vids and (not running_vids  or
-                   not self._compare_vids(bridge_vids, running_vids))):
+                   not self._compare_vids(bridge_vids, running_vids, running_pvid))):
               ifaceobjcurr.status = ifaceStatus.ERROR
               ifaceobjcurr.status_str = 'bridge vid error'
 
-        running_pvid = running_vidinfo.get(ifaceobj.name,
-                                           {}).get('pvid')
-        attr_name = 'bridge-pvid'
-        pvid = ifaceobj.get_attr_value_first(attr_name)
-        if pvid:
-           if running_pvid and running_pvid == pvid:
-              ifaceobjcurr.update_config_with_status(attr_name,
-                                                     running_pvid, 0)
-           else:
-              ifaceobjcurr.update_config_with_status(attr_name,
-                                                     running_pvid, 1)
-        elif not running_pvid or running_pvid != '1':
-           ifaceobjcurr.status = ifaceStatus.ERROR
-           ifaceobjcurr.status_str = 'bridge pvid error'
-
     def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr,
                                  ifaceobj_getfunc):
         if not self._is_bridge_port(ifaceobj):
             # Mark all bridge attributes as failed
             ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
-                    ['bridge-vids', 'bridge-pvid', 'bridge-access',
+                    ['bridge-vids', 'bridge-trunk', 'bridge-pvid', 'bridge-access',
                      'bridge-pathcosts', 'bridge-portprios',
                      'bridge-portmcrouter',
-                     'bridge-portmcfl'], 1)
+                     'bridge-learning',
+                     'bridge-portmcfl', 'bridge-unicast-flood',
+                     'bridge-multicast-flood',
+                     'bridge-arp-nd-suppress', 'bridge-l2protocol-tunnel'
+                    ], 1)
             return
         bridgename = self._get_bridge_name(ifaceobj)
         if not bridgename:
@@ -1359,9 +2841,14 @@ class bridge(moduleBase):
                                                   ifaceobj_getfunc,
                                                   bridgename)
         for attr, dstattr in {'bridge-pathcosts' : 'pathcost',
-                              'bridge-portprios' : 'priority',
-                              'bridge-portmcrouter' : 'mcrouter',
-                              'bridge-portmcfl' : 'mcfl' }.items():
+                              'bridge-portprios' : 'portprio',
+                              'bridge-portmcrouter' : 'portmcrouter',
+                              'bridge-portmcfl' : 'portmcfl',
+                              'bridge-learning' : 'learning',
+                              'bridge-unicast-flood' : 'unicast-flood',
+                              'bridge-multicast-flood' : 'multicast-flood',
+                              'bridge-arp-nd-suppress' : 'arp-nd-suppress',
+                             }.items():
             attrval = ifaceobj.get_attr_value_first(attr)
             if not attrval:
                 continue
@@ -1369,6 +2856,26 @@ class bridge(moduleBase):
             try:
                 running_attrval = self.brctlcmd.get_bridgeport_attr(
                                        bridgename, ifaceobj.name, dstattr)
+
+                if dstattr == 'portmcfl':
+                    if not utils.is_binary_bool(attrval) and running_attrval:
+                        running_attrval = utils.get_yesno_boolean(
+                            utils.get_boolean_from_string(running_attrval))
+                elif dstattr == 'portmcrouter':
+                    if self._ifla_brport_multicast_router_dict_to_int.get(attrval) == int(running_attrval):
+                        ifaceobjcurr.update_config_with_status(attr, attrval, 0)
+                    else:
+                        ifaceobjcurr.update_config_with_status(attr, attrval, 1)
+                    continue
+                elif dstattr in ['learning',
+                                 'unicast-flood',
+                                 'multicast-flood',
+                                 'arp-nd-suppress',
+                                ]:
+                    if not utils.is_binary_bool(attrval) and running_attrval:
+                        running_attrval = utils.get_onff_from_onezero(
+                                                running_attrval)
+
                 if running_attrval != attrval:
                     ifaceobjcurr.update_config_with_status(attr,
                                             running_attrval, 1)
@@ -1378,9 +2885,88 @@ class bridge(moduleBase):
             except Exception, e:
                 self.log_warn('%s: %s' %(ifaceobj.name, str(e)))
 
+        self._query_check_l2protocol_tunnel_on_port(ifaceobj, ifaceobjcurr)
+
+    def _query_check_l2protocol_tunnel_on_port(self, ifaceobj, ifaceobjcurr):
+        user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
+
+        if user_config_l2protocol_tunnel:
+            result = 0
+            try:
+                self._query_check_l2protocol_tunnel(ifaceobj.name, user_config_l2protocol_tunnel)
+            except Exception as e:
+                self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
+                result = 1
+            ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
+
+    def _query_check_l2protocol_tunnel_on_bridge(self, ifaceobj, ifaceobjcurr, bridge_running_attrs):
+        """
+            In case the bridge-l2protocol-tunnel is specified under the bridge and not the brport
+            We need to make sure that all ports comply with the mask given under the bridge
+        """
+        user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
+
+        if user_config_l2protocol_tunnel:
+            if '=' in user_config_l2protocol_tunnel:
+                try:
+                    config_per_port_dict = self.parse_interface_list_value(user_config_l2protocol_tunnel)
+                    brport_list = config_per_port_dict.keys()
+                except:
+                    ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, 1)
+                    return
+            else:
+                config_per_port_dict = {}
+                brport_list = bridge_running_attrs.get('ports', {}).keys()
+            result = 1
+            try:
+                for brport_name in brport_list:
+                    self._query_check_l2protocol_tunnel(
+                        brport_name,
+                        config_per_port_dict.get(brport_name) if config_per_port_dict else user_config_l2protocol_tunnel
+                    )
+                result = 0
+            except Exception as e:
+                self.logger.debug('query: %s: %s' % (ifaceobj.name, str(e)))
+                result = 1
+            ifaceobjcurr.update_config_with_status('bridge-l2protocol-tunnel', user_config_l2protocol_tunnel, result)
+
+    def _query_check_l2protocol_tunnel(self, brport_name, user_config_l2protocol_tunnel):
+        cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
+        cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
+
+        for protocol in re.split(',|\s*', user_config_l2protocol_tunnel):
+            callback = self.query_check_l2protocol_tunnel_callback.get(protocol)
+
+            if callable(callback):
+                if not callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
+                    raise Exception('%s: bridge-l2protocol-tunnel: protocol \'%s\' not present (cached value: %d | %d)'
+                                    % (brport_name, protocol, cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi))
+
+    def _query_running_bridge_l2protocol_tunnel(self, brport_name, brport_ifaceobj=None, bridge_ifaceobj=None):
+        cached_ifla_brport_group_maskhi = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASKHI])
+        cached_ifla_brport_group_mask = self.ipcmd.cache_get_info_slave([brport_name, 'info_slave_data', Link.IFLA_BRPORT_GROUP_FWD_MASK])
+        running_protocols = []
+        for protocol_name, callback in self.query_check_l2protocol_tunnel_callback.items():
+            if protocol_name == 'all' and callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
+                running_protocols = self.query_check_l2protocol_tunnel_callback.keys()
+                running_protocols.remove('all')
+                break
+            elif callback(cached_ifla_brport_group_mask, cached_ifla_brport_group_maskhi):
+                running_protocols.append(protocol_name)
+        if running_protocols:
+            if brport_ifaceobj:
+                brport_ifaceobj.update_config('bridge-l2protocol-tunnel', ' '.join(running_protocols))
+            elif bridge_ifaceobj:
+                current_config = bridge_ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
+
+                if current_config:
+                    bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s %s=%s' % (current_config, brport_name, ','.join(running_protocols)))
+                else:
+                    bridge_ifaceobj.replace_config('bridge-l2protocol-tunnel', '%s=%s' % (brport_name, ','.join(running_protocols)))
+
     def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
         if self._is_bridge(ifaceobj):
-            self._query_check_bridge(ifaceobj, ifaceobjcurr)
+            self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
         else:
             self._query_check_bridge_port(ifaceobj, ifaceobjcurr,
                                           ifaceobj_getfunc)
@@ -1392,24 +2978,25 @@ class bridge(moduleBase):
                                                ifaceobjrunning,
                                                ifaceobj_getfunc,
                                                bridge_vlan_aware=True))
-        else: 
+        else:
             ifaceobjrunning.update_config_dict(self._query_running_attrs(
                                                ifaceobjrunning, None))
 
     def _query_running_bridge_port_attrs(self, ifaceobjrunning, bridgename):
-        if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
+        if self.systcl_get_net_bridge_stp_user_space() == '1':
             return
 
-        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
+        v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
         if v and v != self.get_mod_subattr('bridge-pathcosts', 'default'):
             ifaceobjrunning.update_config('bridge-pathcosts', v)
 
-        v = self.brctlcmd.get_pathcost(bridgename, ifaceobjrunning.name)
+        v = self.brctlcmd.bridge_get_pathcost(bridgename, ifaceobjrunning.name)
         if v and v != self.get_mod_subattr('bridge-portprios', 'default'):
             ifaceobjrunning.update_config('bridge-portprios', v)
 
     def _query_running_bridge_port(self, ifaceobjrunning,
                                    ifaceobj_getfunc=None):
+
         bridgename = self.ipcmd.bridge_port_get_bridge_name(
                                                 ifaceobjrunning.name)
         bridge_vids = None
@@ -1418,14 +3005,20 @@ class bridge(moduleBase):
             self.logger.warn('%s: unable to find bridgename'
                              %ifaceobjrunning.name)
             return
+
         if not self.ipcmd.bridge_is_vlan_aware(bridgename):
+            try:
+                self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, bridge_ifaceobj=ifaceobj_getfunc(bridgename)[0])
+            except Exception as e:
+                self.logger.debug('%s: q_query_running_bridge_l2protocol_tunnel: %s' % (ifaceobjrunning.name, str(e)))
             return
 
-        running_vidinfo = self._get_running_vidinfo()
-        bridge_port_vids = running_vidinfo.get(ifaceobjrunning.name,
-                                               {}).get('vlan')
-        bridge_port_pvid = running_vidinfo.get(ifaceobjrunning.name,
-                                               {}).get('pvid')
+        self._query_running_bridge_l2protocol_tunnel(ifaceobjrunning.name, brport_ifaceobj=ifaceobjrunning)
+
+        (bridge_port_vids, bridge_port_pvid) = self._get_running_vids_n_pvid_str(
+                                                           ifaceobjrunning.name)
+        if bridge_port_vids and bridge_port_pvid in bridge_port_vids:
+                bridge_port_vids.remove(bridge_port_pvid)
 
         bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
         if bridgeifaceobjlist:
@@ -1446,32 +3039,122 @@ class bridge(moduleBase):
                 if (not bridge_pvid or (bridge_port_pvid != bridge_pvid)):
                     ifaceobjrunning.update_config('bridge-pvid',
                                         bridge_port_pvid)
+
+        v = utils.get_onff_from_onezero(
+                self.brctlcmd.get_bridgeport_attr(bridgename,
+                                                  ifaceobjrunning.name,
+                                                  'learning'))
+        if v and v != self.get_mod_subattr('bridge-learning', 'default'):
+            ifaceobjrunning.update_config('bridge-learning', v)
+
+        v = utils.get_onff_from_onezero(
+                self.brctlcmd.get_bridgeport_attr(bridgename,
+                                                  ifaceobjrunning.name,
+                                                  'unicast-flood'))
+        if v and v != self.get_mod_subattr('bridge-unicast-flood', 'default'):
+            ifaceobjrunning.update_config('bridge-unicast-flood', v)
+
+        v = utils.get_onff_from_onezero(
+                self.brctlcmd.get_bridgeport_attr(bridgename,
+                                                  ifaceobjrunning.name,
+                                                  'multicast-flood'))
+        if v and v != self.get_mod_subattr('bridge-multicast-flood', 'default'):
+            ifaceobjrunning.update_config('bridge-multicast-flood', v)
+
+        v = utils.get_onff_from_onezero(
+                self.brctlcmd.get_bridgeport_attr(bridgename,
+                                                  ifaceobjrunning.name,
+                                                  'arp-nd-suppress'))
+        # Display running 'arp-nd-suppress' only on vxlan ports
+        # if 'allow_arp_nd_suppress_only_on_vxlan' is set to 'yes'
+        # otherwise, display on all bridge-ports
+
+        bportifaceobj = ifaceobj_getfunc(ifaceobjrunning.name)[0]
+        if (v and
+            v != self.get_mod_subattr('bridge-arp-nd-suppress', 'default') and
+            (not self.arp_nd_suppress_only_on_vxlan or
+             (self.arp_nd_suppress_only_on_vxlan and
+              bportifaceobj.link_kind & ifaceLinkKind.VXLAN))):
+            ifaceobjrunning.update_config('bridge-arp-nd-suppress', v)
+
         self._query_running_bridge_port_attrs(ifaceobjrunning, bridgename)
 
     def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
-        if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
-            self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
-        elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
-            self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
+        try:
+            if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
+                self._query_running_bridge(ifaceobjrunning, ifaceobj_getfunc)
+            elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
+                self._query_running_bridge_port(ifaceobjrunning, ifaceobj_getfunc)
+        except Exception as e:
+            raise Exception('%s: %s' % (ifaceobjrunning.name, str(e)))
+
+    def _query(self, ifaceobj, **kwargs):
+        """ add default policy attributes supported by the module """
+        if (not (ifaceobj.link_kind & ifaceLinkKind.BRIDGE) or
+            ifaceobj.get_attr_value_first('bridge-stp')):
+            return
+        if self.default_stp_on:
+            ifaceobj.update_config('bridge-stp', 'yes')
+
+    def _query_check_support_yesno_attrs(self, runningattrs, ifaceobj):
+        for attrl in [['mcqifaddr', 'bridge-mcqifaddr'],
+                     ['mcquerier', 'bridge-mcquerier'],
+                     ['mcsnoop', 'bridge-mcsnoop']]:
+            value = ifaceobj.get_attr_value_first(attrl[1])
+            if value and not utils.is_binary_bool(value):
+                if attrl[0] in runningattrs:
+                    bool = utils.get_boolean_from_string(runningattrs[attrl[0]])
+                    runningattrs[attrl[0]] = utils.get_yesno_boolean(bool)
+
+        self._query_check_mcrouter(ifaceobj, runningattrs)
+        self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'portmcfl', ifaceobj.get_attr_value_first('bridge-portmcfl'))
+        self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'learning', ifaceobj.get_attr_value_first('bridge-learning'))
+        self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'unicast-flood', ifaceobj.get_attr_value_first('bridge-unicast-flood'))
+        self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'multicast-flood', ifaceobj.get_attr_value_first('bridge-multicast-flood'))
+        self._query_check_support_yesno_attr_port(runningattrs, ifaceobj, 'arp-nd-suppress', ifaceobj.get_attr_value_first('bridge-arp-nd-suppress'))
+
+    def _query_check_mcrouter(self, ifaceobj, running_attrs):
+        """
+        bridge-mcrouter and bridge-portmcrouter supports: yes-no-0-1-2
+        """
+        if 'mcrouter' in running_attrs:
+            value = ifaceobj.get_attr_value_first('bridge-mcrouter')
+            if value:
+                try:
+                    int(value)
+                except:
+                    running_attrs['mcrouter'] = 'yes' if utils.get_boolean_from_string(running_attrs['mcrouter']) else 'no'
 
-    _run_ops = {'pre-up' : _up,
-               'post-down' : _down,
-               'query-checkcurr' : _query_check,
-               'query-running' : _query_running}
+    def _query_check_support_yesno_attr_port(self, runningattrs, ifaceobj, attr, attrval):
+        if attrval:
+            portlist = self.parse_port_list(ifaceobj.name, attrval)
+            if portlist:
+                to_convert = []
+                for p in portlist:
+                    (port, val) = p.split('=')
+                    if not utils.is_binary_bool(val):
+                        to_convert.append(port)
+                for port in to_convert:
+                    runningattrs['ports'][port][attr] = utils.get_yesno_boolean(
+                        utils.get_boolean_from_string(runningattrs['ports'][port][attr]))
+
+    _run_ops = {
+        'pre-up': _up,
+        'post-down': _down,
+        'query-checkcurr': _query_check,
+        'query-running': _query_running,
+        'query': _query
+    }
 
     def get_ops(self):
         """ returns list of ops supported by this module """
         return self._run_ops.keys()
 
     def _init_command_handlers(self):
-        flags = self.get_flags()
         if not self.ipcmd:
-            self.ipcmd = iproute2(**flags)
-        if not self.brctlcmd:
-            self.brctlcmd = brctl(**flags)
+            self.ipcmd = self.brctlcmd = LinkUtils()
 
-    def run(self, ifaceobj, operation, query_ifaceobj=None,
-            ifaceobj_getfunc=None):
+    def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
         """ run bridge configuration on the interface object passed as
             argument. Can create bridge interfaces if they dont exist already
 
@@ -1493,7 +3176,14 @@ class bridge(moduleBase):
         if not op_handler:
            return
         self._init_command_handlers()
-        self._flush_running_vidinfo()
+
+        if (not LinkUtils.bridge_utils_is_installed
+                and (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
+                    and LinkUtils.bridge_utils_missing_warning):
+            self.logger.warning('%s: missing - bridge operation may not work as expected. '
+                                'Please check if \'bridge-utils\' package is installed' % utils.brctl_cmd)
+            LinkUtils.bridge_utils_missing_warning = False
+
         if operation == 'query-checkcurr':
             op_handler(self, ifaceobj, query_ifaceobj,
                        ifaceobj_getfunc=ifaceobj_getfunc)