]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - ifupdown/ifupdownmain.py
mstp: performances: now globaly caching "mstpctl showportdetail <bridgename> json...
[mirror_ifupdown2.git] / ifupdown / ifupdownmain.py
index 5125352f2f0806722a864069a16348ad0ab551cf..36252c81c095fd4253a57bf57765da462f3d9098 100644 (file)
@@ -15,7 +15,9 @@ import logging
 import sys, traceback
 import copy
 import json
-from statemanager import *
+import ifupdown.statemanager as statemanager
+import ifupdown.ifupdownconfig as ifupdownConfig
+import ifupdown.ifupdownflags as ifupdownflags
 from networkinterfaces import *
 from iface import *
 from scheduler import *
@@ -34,13 +36,10 @@ from sets import Set
 
 _tickmark = u'\u2713'
 _crossmark = u'\u2717'
-_success_sym = _tickmark
-_error_sym = _crossmark
+_success_sym = '(%s)' %_tickmark
+_error_sym = '(%s)' %_crossmark
 
-class ifupdownMain(ifupdownBase):
-    """ ifupdown2 main class """
-
-    # Flags
+class ifupdownMainFlags():
     WITH_DEPENDS = False
     ALL = False
     IFACE_CLASS = False
@@ -48,14 +47,25 @@ class ifupdownMain(ifupdownBase):
     STATEMANAGER_ENABLE = True
     STATEMANAGER_UPDATE = True
     ADDONS_ENABLE = False
+    DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
+    SCHED_SKIP_CHECK_UPPERIFACES = False
+    CHECK_SHARED_DEPENDENTS = True
 
+class ifacePrivFlags():
     # priv flags to mark iface objects
-    BUILTIN = 0x1
-    NOCONFIG = 0x2
+    BUILTIN = False
+    NOCONFIG = False
+
+    def __init__(self, builtin=False, noconfig=False):
+        self.BUILTIN = builtin
+        self.NOCONFIG = noconfig
+    
+class ifupdownMain(ifupdownBase):
+    """ ifupdown2 main class """
 
     scripts_dir='/etc/network'
-    addon_modules_dir='/usr/share/ifupdownaddons'
-    addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
+    addon_modules_dir='/usr/share/ifupdown2/addons'
+    addon_modules_configfile='/etc/network/ifupdown2/addons.conf'
 
     # iface dictionary in the below format:
     # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
@@ -98,24 +108,60 @@ class ifupdownMain(ifupdownBase):
 
     # Handlers for ops that ifupdown2 owns
     def run_up(self, ifaceobj):
-        ifacename = ifaceobj.name
-        if self.link_exists(ifacename):
-            self.link_up(ifacename)
+        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
+        # there is no real interface behind it
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        if ifaceobj.link_kind & ifaceLinkKind.VRF:
+            return
+        if (ifaceobj.addr_method and
+            ifaceobj.addr_method == 'manual'):
+            return
+        if self._delay_admin_state:
+            self._delay_admin_state_iface_queue.append(ifaceobj.name)
+            return
+        # If this object is a link slave, ie its link is controlled
+        # by its link master interface, then dont set the link state.
+        # But do allow user to change state of the link if the interface
+        # is already with its link master (hence the master check).
+        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
+            return
+        if not self.link_exists(ifaceobj.name):
+           return
+        self.link_up(ifaceobj.name)
 
     def run_down(self, ifaceobj):
-        ifacename = ifaceobj.name
-        if self.link_exists(ifacename):
-            self.link_down(ifacename)
+        if ifaceobj.link_kind & ifaceLinkKind.VRF:
+            return
+        # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
+        # there is no real interface behind it
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return
+        if (ifaceobj.addr_method and
+            ifaceobj.addr_method == 'manual'):
+            return
+        if self._delay_admin_state:
+            self._delay_admin_state_iface_queue.append(ifaceobj.name)
+            return
+        # If this object is a link slave, ie its link is controlled
+        # by its link master interface, then dont set the link state.
+        # But do allow user to change state of the link if the interface
+        # is already with its link master (hence the master check).
+        if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
+           return
+        if not self.link_exists(ifaceobj.name):
+           return
+        self.link_down(ifaceobj.name)
 
     # ifupdown object interface operation handlers
     ops_handlers = OrderedDict([('up', run_up),
                                 ('down', run_down)])
 
     def run_sched_ifaceobj_posthook(self, ifaceobj, op):
-        if ((ifaceobj.priv_flags & self.BUILTIN) or
-            (ifaceobj.priv_flags & self.NOCONFIG)):
+        if (ifaceobj.priv_flags and (ifaceobj.priv_flags.BUILTIN or
+            ifaceobj.priv_flags.NOCONFIG)):
             return
-        if self.STATEMANAGER_UPDATE:
+        if self.flags.STATEMANAGER_UPDATE:
             self.statemanager.ifaceobj_sync(ifaceobj, op)
 
     # ifupdown object interface scheduler pre and posthooks
@@ -127,7 +173,8 @@ class ifupdownMain(ifupdownBase):
                  cache=False, addons_enable=True, statemanager_enable=True,
                  interfacesfile='/etc/network/interfaces',
                  interfacesfileiobuf=None,
-                 interfacesfileformat='native'):
+                 interfacesfileformat='native',
+                 withdefaults=False):
         """This member function initializes the ifupdownmain object.
 
         Kwargs:
@@ -142,23 +189,31 @@ class ifupdownMain(ifupdownBase):
             AttributeError, KeyError """
 
         self.logger = logging.getLogger('ifupdown')
-        self.FORCE = force
-        self.DRYRUN = dryrun
-        self.NOWAIT = nowait
-        self.PERFMODE = perfmode
-        self.WITH_DEPENDS = withdepends
-        self.STATEMANAGER_ENABLE = statemanager_enable
-        self.CACHE = cache
+        ifupdownflags.flags.FORCE = force
+        ifupdownflags.flags.DRYRUN = dryrun
+        ifupdownflags.flags.WITHDEFAULTS = withdefaults
+        ifupdownflags.flags.NOWAIT = nowait
+        ifupdownflags.flags.PERFMODE = perfmode
+        ifupdownflags.flags.CACHE = cache
+
+        # Can be used to provide hints for caching
+        ifupdownflags.flags.CACHE_FLAGS = 0x0
+
+        self.flags = ifupdownMainFlags()
+
+        self.flags.WITH_DEPENDS = withdepends
+        self.flags.STATEMANAGER_ENABLE = statemanager_enable
         self.interfacesfile = interfacesfile
         self.interfacesfileiobuf = interfacesfileiobuf
         self.interfacesfileformat = interfacesfileformat
         self.config = config
         self.logger.debug(self.config)
+        self.blacklisted_ifaces_present = False
 
-        # Can be used to provide hints for caching
-        self.CACHE_FLAGS = 0x0
-        self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
-        self.ADDONS_ENABLE = addons_enable
+        self.type = ifaceType.UNKNOWN
+
+        self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
+        self.flags.ADDONS_ENABLE = addons_enable
 
         self.ifaces = OrderedDict()
         self.njobs = njobs
@@ -167,24 +222,77 @@ class ifupdownMain(ifupdownBase):
         self.module_attrs = {}
         
         self.load_addon_modules(self.addon_modules_dir)
-        if self.COMPAT_EXEC_SCRIPTS:
+        if self.flags.COMPAT_EXEC_SCRIPTS:
             self.load_scripts(self.scripts_dir)
         self.dependency_graph = OrderedDict({})
 
-        if self.STATEMANAGER_ENABLE:
+        self._cache_no_repeats = {}
+
+        if self.flags.STATEMANAGER_ENABLE:
             try:
-                self.statemanager = stateManager()
+                self.statemanager = statemanager.statemanager_api
                 self.statemanager.read_saved_state()
             except Exception, e:
                 # XXX Maybe we should continue by ignoring old state
                 self.logger.warning('error reading state (%s)' %str(e))
                 raise
         else:
-            self.STATEMANAGER_UPDATE = False
+            self.flags.STATEMANAGER_UPDATE = False
+        self._delay_admin_state = True if self.config.get(
+                            'delay_admin_state_change', '0') == '1' else False
+        self._delay_admin_state_iface_queue = []
+        if self._delay_admin_state:
+            self.logger.info('\'delay_admin_state_change\' is set. admin ' +
+                             'state changes will be delayed till the end.')
+
+        self._link_master_slave = True if self.config.get(
+                      'link_master_slave', '0') == '1' else False
+        if self._link_master_slave:
+            self.logger.info('\'link_master_slave\' is set. slave admin ' +
+                             'state changes will be delayed till the ' +
+                             'masters admin state change.')
+
+        # squash iface objects for same interface both internal and
+        # external representation. It is off by default.
+        self._ifaceobj_squash = True if self.config.get(
+                            'ifaceobj_squash', '0') == '1' else False
+
+        # squash iface objects for same interface internal
+        # representation only. External representation as seen by ifquery
+        # will continue to see multiple iface stanzas if it was specified
+        # that way by the user. It is on by default.
+        self._ifaceobj_squash_internal = True if self.config.get(
+                            'ifaceobj_squash_internal', '1') == '1' else False
+
+        # initialize global config object with config passed by the user
+        # This makes config available to addon modules
+        ifupdownConfig.config = self.config
+
+    def link_master_slave_ignore_error(self, errorstr):
+        # If link master slave flag is set, 
+        # there may be cases where the lowerdev may not be
+        # up resulting in 'Network is down' error
+        # This can happen if the lowerdev is a LINK_SLAVE
+        # of another interface which is not up yet
+        # example of such a case:
+        #   bringing up a vlan on a bond interface and the bond
+        #   is a LINK_SLAVE of a bridge (in other words the bond is
+        #   part of a bridge) which is not up yet
+        if self._link_master_slave:
+           if 'Network is down':
+              return True
+        return False
 
     def get_ifaceobjs(self, ifacename):
         return self.ifaceobjdict.get(ifacename)
 
+    def get_ifaceobjs_saved(self, ifacename):
+        """ Return ifaceobjects from statemanager """
+        if self.flags.STATEMANAGER_ENABLE:
+           return self.statemanager.get_ifaceobjs(ifacename)
+        else:
+           None
+
     def get_ifaceobj_first(self, ifacename):
         ifaceobjs = self.get_ifaceobjs(ifacename)
         if ifaceobjs:
@@ -197,6 +305,20 @@ class ifupdownMain(ifupdownBase):
     def get_iface_obj_last(self, ifacename):
         return self.ifaceobjdict.get(ifacename)[-1]
 
+
+    def must_follow_upperifaces(self, ifacename):
+        #
+        # XXX: This bleeds the knowledge of iface
+        # types in the infrastructure module.
+        # Cant think of a better fix at the moment.
+        # In future maybe the module can set a flag
+        # to indicate if we should follow upperifaces
+        #
+        ifaceobj = self.get_ifaceobj_first(ifacename)
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            return False
+        return True
+
     def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
                                increfcnt=False):
         """ creates a iface object and adds it to the iface dictionary """
@@ -204,6 +326,8 @@ class ifupdownMain(ifupdownBase):
         ifaceobj.name = ifacename
         ifaceobj.priv_flags = priv_flags
         ifaceobj.auto = True
+        if not self._link_master_slave:
+            ifaceobj.link_type = ifaceLinkType.LINK_NA
         if increfcnt:
             ifaceobj.inc_refcnt()
         self.ifaceobjdict[ifacename] = [ifaceobj]
@@ -215,8 +339,9 @@ class ifupdownMain(ifupdownBase):
         """
         ifaceobjcurr = iface()
         ifaceobjcurr.name = ifaceobj.name
+        ifaceobjcurr.type = ifaceobj.type
         ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
-        ifaceobjcurr.priv_flags = ifaceobj.priv_flags
+        ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
         ifaceobjcurr.auto = ifaceobj.auto
         self.ifaceobjcurrdict.setdefault(ifaceobj.name,
                                      []).append(ifaceobjcurr)
@@ -261,7 +386,8 @@ class ifupdownMain(ifupdownBase):
         The following are currently considered builtin ifaces:
             - vlan interfaces in the format <ifacename>.<vlanid>
         """
-        return (ifaceobj.priv_flags & self.BUILTIN)
+
+        return (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN)
 
     def is_ifaceobj_noconfig(self, ifaceobj):
         """ Returns true if iface object did not have a user defined config.
@@ -269,7 +395,7 @@ class ifupdownMain(ifupdownBase):
         These interfaces appear only when they are dependents of interfaces
         which have user defined config
         """
-        return (ifaceobj.priv_flags & self.NOCONFIG)
+        return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
 
     def is_iface_noconfig(self, ifacename):
         """ Returns true if iface has no config """
@@ -278,18 +404,91 @@ class ifupdownMain(ifupdownBase):
         if not ifaceobj: return True
         return self.is_ifaceobj_noconfig(ifaceobj)
 
-    def preprocess_dependency_list(self, upperifacename, dlist, ops):
+    def check_shared_dependents(self, ifaceobj, dlist):
+        """ ABSOLETE: Check if dlist intersects with any other
+            interface with slave dependents.
+            example: bond and bridges.
+            This function logs such errors """
+        setdlist = Set(dlist)
+        for ifacename, ifacedlist in self.dependency_graph.items():
+            if not ifacedlist:
+                continue
+            check_depends = False
+            iobjs = self.get_ifaceobjs(ifacename)
+            if not iobjs:
+                continue
+            for i in iobjs:
+                if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
+                    check_depends = True
+            if check_depends:
+                common = Set(ifacedlist).intersection(setdlist)
+                if common:
+                    self.logger.error('misconfig..?. iface %s and %s '
+                            %(ifaceobj.name, ifacename) +
+                            'seem to share dependents/ports %s' %str(list(common)))
+
+    def _set_iface_role(self, ifaceobj, role, upperifaceobj):
+        if (self.flags.CHECK_SHARED_DEPENDENTS and
+            (ifaceobj.role & ifaceRole.SLAVE) and
+            (role == ifaceRole.SLAVE) and (upperifaceobj.role == ifaceRole.MASTER)):
+               self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
+                                  %(ifaceobj.name,
+                                    ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
+                ifaceobj.set_status(ifaceStatus.ERROR)
+                return
+        ifaceobj.role = role
+
+    def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
+
+        if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
+            self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
+            ifaceobj.link_privflags |= ifaceLinkPrivFlags.BOND_SLAVE
+
+        if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
+            self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
+            ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT
+
+        if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
+                and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
+            upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
+
+        # vrf masters get processed after slaves, which means
+        # check both link_kind vrf and vrf slave
+        if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or
+            (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
+            self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
+            ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
+        if self._link_master_slave:
+            if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
+                ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
+        else:
+            upperifaceobj.link_type = ifaceLinkType.LINK_NA
+            ifaceobj.link_type = ifaceLinkType.LINK_NA
+
+    def dump_iface_dependency_info(self):
+        """ debug funtion to print raw dependency 
+        info - lower and upper devices"""
+
+        for ifacename, ifaceobjs in self.ifaceobjdict.iteritems():
+            iobj = ifaceobjs[0]
+            self.logger.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename,
+                             self.get_iface_refcnt(ifacename),
+                             str(iobj.lowerifaces) if iobj.lowerifaces else [],
+                             str(iobj.upperifaces) if iobj.upperifaces else []))
+
+
+    def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
         """ We go through the dependency list and
             delete or add interfaces from the interfaces dict by
             applying the following rules:
-                if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
+                if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
                     we only consider devices whose configuration was
                     specified in the network interfaces file. We delete
                     any interface whose config was not specified except
                     for vlan devices. vlan devices get special treatment.
                     Even if they are not present they are created and added
                     to the ifacesdict
-                elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
+                elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
                     we create objects for all dependent devices that are not
                     present in the ifacesdict
         """
@@ -298,23 +497,40 @@ class ifupdownMain(ifupdownBase):
         for d in dlist:
             dilist = self.get_ifaceobjs(d)
             if not dilist:
+                ni = None
                 if self.is_iface_builtin_byname(d):
-                    self.create_n_save_ifaceobj(d, self.BUILTIN | self.NOCONFIG,
-                            True).add_to_upperifaces(upperifacename)
-                elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
-                    self.create_n_save_ifaceobj(d, self.NOCONFIG,
-                            True).add_to_upperifaces(upperifacename)
+                    ni = self.create_n_save_ifaceobj(d,
+                            ifacePrivFlags(True, True), True)
+                elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
+                    ni = self.create_n_save_ifaceobj(d,
+                                    ifacePrivFlags(False, True), True)
                 else:
                     del_list.append(d)
+                if ni:
+                    ni.add_to_upperifaces(upperifaceobj.name)
+                    self._set_iface_role_n_kind(ni, upperifaceobj)
             else:
                 for di in dilist:
                     di.inc_refcnt()
-                    di.add_to_upperifaces(upperifacename)
-
+                    di.add_to_upperifaces(upperifaceobj.name)
+                    self._set_iface_role_n_kind(di, upperifaceobj)
         for d in del_list:
             dlist.remove(d)
 
-    def query_dependents(self, ifaceobj, ops, ifacenames):
+    def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
+        for u in ulist:
+            if (lowerifaceobj.upperifaces and
+                u in lowerifaceobj.upperifaces):
+                continue
+            lowerifaceobj.add_to_upperifaces(u)
+            uifacelist = self.get_ifaceobjs(u)
+            if uifacelist:
+                for ui in uifacelist:
+                    lowerifaceobj.inc_refcnt()
+                    self._set_iface_role_n_kind(lowerifaceobj, ui)
+                    ui.add_to_lowerifaces(lowerifaceobj.name)
+
+    def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
         """ Gets iface dependents by calling into respective modules """
         ret_dlist = []
 
@@ -337,7 +553,31 @@ class ifupdownMain(ifupdownBase):
                 dlist = None
                 pass
             if dlist: ret_dlist.extend(dlist)
-        return ret_dlist
+        return list(set(ret_dlist))
+
+    def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
+        """ Gets iface upperifaces by calling into respective modules """
+        ret_ulist = []
+
+        # Get upperifaces for interface by querying respective modules
+        for module in self.modules.values():
+            try:
+                if ops[0] == 'query-running':
+                    if (not hasattr(module,
+                        'get_upper_ifacenames_running')):
+                        continue
+                    ulist = module.get_upper_ifacenames_running(ifaceobj)
+                else:
+                    if (not hasattr(module, 'get_upper_ifacenames')):
+                        continue
+                    ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
+            except Exception, e:
+                self.logger.warn('%s: error getting upper interfaces (%s)'
+                                 %(ifaceobj.name, str(e)))
+                ulist = None
+                pass
+            if ulist: ret_ulist.extend(ulist)
+        return list(set(ret_ulist))
 
     def populate_dependency_info(self, ops, ifacenames=None):
         """ recursive function to generate iface dependency info """
@@ -350,55 +590,134 @@ class ifupdownMain(ifupdownBase):
             i = iqueue.popleft()
             # Go through all modules and find dependent ifaces
             dlist = None
-            ifaceobj = self.get_ifaceobj_first(i)
-            if not ifaceobj: 
+            ulist = None
+            ifaceobjs = self.get_ifaceobjs(i)
+            if not ifaceobjs:
+                continue
+            dependents_processed = False
+
+            # Store all dependency info in the first ifaceobj
+            # but get dependency info from all ifaceobjs
+            ifaceobj = ifaceobjs[0]
+            for iobj in ifaceobjs:
+                ulist = self.query_upperifaces(iobj, ops, ifacenames)
+                if iobj.lowerifaces:
+                    dependents_processed = True
+                    break
+                dlist = self.query_lowerifaces(iobj, ops, ifacenames)
+                if dlist:
+                   break
+            if ulist:
+                self.preprocess_upperiface(ifaceobj, ulist, ops)
+            if dependents_processed:
                 continue
-            dlist = self.query_dependents(ifaceobj, ops, ifacenames)
-            if dlist and dlist != ifaceobj.lowerifaces:
-                self.preprocess_dependency_list(ifaceobj.name,
+            if dlist:
+                self.preprocess_dependency_list(ifaceobj,
                                                 dlist, ops)
+                ifaceobj.lowerifaces = dlist
                 [iqueue.append(d) for d in dlist]
-                self.dependency_graph.setdefault(i, []).extend(dlist)
-                ifaceobj.lowerifaces = self.dependency_graph.get(i)
+            #if not self.dependency_graph.get(i):
+            #    self.dependency_graph[i] = dlist
+
+        for i in self.ifaceobjdict.keys():
+            iobj = self.get_ifaceobj_first(i)
+            if iobj.lowerifaces:
+                self.dependency_graph[i] = iobj.lowerifaces
             else:
-                self.dependency_graph[i] = dlist
+                self.dependency_graph[i] = []
+
+        if not self.blacklisted_ifaces_present:
+            return
 
-    def _add_ifaceobj(self, ifaceobj):
+        # Walk through the dependency graph and remove blacklisted
+        # interfaces that were picked up as dependents
+        for i in self.dependency_graph.keys():
+            ifaceobj = self.get_ifaceobj_first(i)
+            if not ifaceobj:
+                continue
+
+            if ifaceobj.blacklisted and not ifaceobj.upperifaces:
+                # if blacklisted and was not picked up as a
+                # dependent of a upper interface, delete the
+                # interface from the dependency graph
+                dlist = ifaceobj.lowerifaces
+                if dlist:
+                    for d in dlist:
+                        difaceobjs = self.get_ifaceobjs(d)
+                        if not difaceobjs:
+                            continue
+                        try:
+                            for d in difaceobjs:
+                                d.dec_refcnt()
+                                d.upperifaces.remove(i)
+                        except:
+                            self.logger.debug('error removing %s from %s upperifaces' %(i, d))
+                            pass
+                self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
+                del self.dependency_graph[i]
+                continue
+
+    def _check_config_no_repeats(self, ifaceobj):
+        """ check if object has an attribute that is
+        restricted to a single object in the system.
+        if yes, warn and return """
+        for k,v in self._cache_no_repeats.items():
+            iv = ifaceobj.config.get(k)
+            if iv and iv[0] == v:
+                self.logger.error('ignoring interface %s. ' %ifaceobj.name +
+                        'Only one object with attribute ' +
+                        '\'%s %s\' allowed.' %(k, v))
+                return True
+        for k, v in self.config.get('no_repeats', {}).items():
+            iv = ifaceobj.config.get(k)
+            if iv and iv[0] == v:
+                self._cache_no_repeats[k] = v
+        return False
+
+    def _save_iface_squash(self, ifaceobj):
+        """ squash ifaceobjects belonging to same iface
+        into a single object """
+        if self._check_config_no_repeats(ifaceobj):
+           return
+        ifaceobj.priv_flags = ifacePrivFlags()
+        if not self._link_master_slave:
+           ifaceobj.link_type = ifaceLinkType.LINK_NA
         currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
         if not currentifaceobjlist:
-           self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
-           return
+            self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
+            return
         if ifaceobj.compare(currentifaceobjlist[0]):
             self.logger.warn('duplicate interface %s found' %ifaceobj.name)
             return
-        currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
-        ifaceobj.flags |= iface.HAS_SIBLINGS
-        self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
+        if ifaceobj.type == ifaceType.BRIDGE_VLAN:
+            self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
+        else:
+            currentifaceobjlist[0].squash(ifaceobj)
 
     def _save_iface(self, ifaceobj):
-        #
-        # Special 'iface vlan-' interface handling.
-        # If `iface vlan-` and belongs to a bridge
-        # mark interface type.
-        #
-        if ifaceobj.get_attr_value_first('bridge'):
-            vlan_match = re.match("^vlan-([\d]+)-([\d]+)|^vlan-([\d]+)",
-                                   ifaceobj.name)
-            if vlan_match:
-                vlan_groups = vlan_match.groups()
-                if vlan_groups[0] and vlan_groups[1]:
-                    for v in range(int(vlan_groups[0]), int(vlan_groups[1])+1):
-                        ifaceobj_vlan = copy.deepcopy(ifaceobj)
-                        ifaceobj_vlan.real_name = ifaceobj.name
-                        ifaceobj_vlan.name = "vlan-%d" %v
-                        ifaceobj_vlan.priv_data = v
-                        ifaceobj_vlan.type = ifaceType.BRIDGE_VLAN
-                        self._add_ifaceobj(ifaceobj_vlan)
-                    return
-                elif vlan_groups[2]:
-                    ifaceobj.priv_data = int(vlan_groups[2])
-                    ifaceobj.type = ifaceType.BRIDGE_VLAN
-        self._add_ifaceobj(ifaceobj)
+        if self._check_config_no_repeats(ifaceobj):
+           return
+        ifaceobj.priv_flags = ifacePrivFlags()
+        if not self._link_master_slave:
+           ifaceobj.link_type = ifaceLinkType.LINK_NA
+        currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
+        if not currentifaceobjlist:
+            self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
+            if not self._ifaceobj_squash:
+                ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
+            return
+        if ifaceobj.compare(currentifaceobjlist[0]):
+            self.logger.warn('duplicate interface %s found' %ifaceobj.name)
+            return
+        if currentifaceobjlist[0].type == ifaceobj.type:
+            currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
+            ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
+        # clear the OLDEST_SIBLING from all the siblings
+        for iface in self.ifaceobjdict[ifaceobj.name]:
+            iface.flags &= ~ifaceobj.OLDEST_SIBLING
+        # current sibling is the oldest
+        ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
+        self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
 
     def _iface_configattr_syntax_checker(self, attrname, attrval):
         for m, mdict in self.module_attrs.items():
@@ -406,38 +725,54 @@ class ifupdownMain(ifupdownBase):
                 continue
             attrsdict = mdict.get('attrs')
             try:
-                if attrsdict.get(attrname):
+                a = attrsdict.get(attrname)
+                if a:
+                    if a.get('deprecated'):
+                        newa = a.get('new-attribute')
+                        if newa:
+                            self.logger.warn('attribute %s is deprecated. Use %s instead' %(attrname, newa))
+                        else:
+                            self.logger.warn('attribute %s is deprecated'
+                                             %attrname)
                     return True
             except AttributeError:
                 pass
         return False
 
     def _ifaceobj_syntax_checker(self, ifaceobj):
-        err = False
-        for attrname in ifaceobj.config:
+        ret = True
+        for attrname, attrvalue in ifaceobj.config.items():
             found = False
             for k, v in self.module_attrs.items():
                 if v and v.get('attrs', {}).get(attrname):
                     found = True
                     break
             if not found:
-                err = True
-                self.logger.warn('%s: unsupported attribute \'%s\'' %attrname) 
+                ret = False
+                self.logger.warn('%s: unsupported attribute \'%s\'' \
+                                 % (ifaceobj.name, attrname))
                 continue
-        return err
+        return ret
 
     def read_iface_config(self):
         """ Reads default network interface config /etc/network/interfaces. """
+        ret = True
         nifaces = networkInterfaces(self.interfacesfile,
                         self.interfacesfileiobuf,
                         self.interfacesfileformat,
                         template_engine=self.config.get('template_engine'),
                 template_lookuppath=self.config.get('template_lookuppath'))
-        nifaces.subscribe('iface_found', self._save_iface)
+        if self._ifaceobj_squash or self._ifaceobj_squash_internal:
+            nifaces.subscribe('iface_found', self._save_iface_squash)
+        else:
+            nifaces.subscribe('iface_found', self._save_iface)
         nifaces.subscribe('validateifaceattr',
                           self._iface_configattr_syntax_checker)
         nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
         nifaces.load()
+        if nifaces.errors or nifaces.warns:
+            ret = False
+        return ret
 
     def read_old_iface_config(self):
         """ Reads the saved iface config instead of default iface config.
@@ -450,10 +785,16 @@ class ifupdownMain(ifupdownBase):
         with open(self.addon_modules_configfile, 'r') as f:
             lines = f.readlines()
             for l in lines:
-                litems = l.rstrip(' \n\t\r').split(',')
-                operation = litems[0]
-                mname = litems[1]
-                self.module_ops[operation].append(mname)
+                try:
+                    litems = l.strip(' \n\t\r').split(',')
+                    if not litems or len(litems) < 2:
+                        continue
+                    operation = litems[0]
+                    mname = litems[1]
+                    self.module_ops[operation].append(mname)
+                except Exception, e:
+                    self.logger.warn('error reading line \'%s\'' %(l, str(e)))
+                    continue
 
     def load_addon_modules(self, modules_dir):
         """ load python modules from modules_dir
@@ -477,12 +818,7 @@ class ifupdownMain(ifupdownBase):
                             mclass = getattr(m, mname)
                         except:
                             raise
-                        minstance = mclass(force=self.FORCE,
-                                        dryrun=self.DRYRUN,
-                                        nowait=self.NOWAIT,
-                                        perfmode=self.PERFMODE,
-                                        cache=self.CACHE,
-                                        cacheflags=self.CACHE_FLAGS)
+                        minstance = mclass()
                         self.modules[mname] = minstance
                         try:
                             self.module_attrs[mname] = minstance.get_modinfo()
@@ -567,26 +903,29 @@ class ifupdownMain(ifupdownBase):
                 # continue reading
                 pass
 
-    def _sched_ifaces(self, ifacenames, ops):
+    def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
+                      followdependents=True, sort=False):
         self.logger.debug('scheduling \'%s\' for %s'
                           %(str(ops), str(ifacenames)))
-
         self._pretty_print_ordered_dict('dependency graph',
                     self.dependency_graph)
-        return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
+        ifaceScheduler.sched_ifaces(self, ifacenames, ops,
                         dependency_graph=self.dependency_graph,
                         order=ifaceSchedulerFlags.INORDER
                             if 'down' in ops[0]
                                 else ifaceSchedulerFlags.POSTORDER,
-                        followdependents=True if self.WITH_DEPENDS else False)
+                        followdependents=followdependents,
+                        skipupperifaces=skipupperifaces,
+                        sort=True if (sort or self.flags.IFACE_CLASS) else False)
+        return ifaceScheduler.get_sched_status()
 
     def _render_ifacename(self, ifacename):
         new_ifacenames = []
-        vlan_match = re.match("^vlan-([\d]+)-([\d]+)", ifacename)
+        vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
         if vlan_match:
             vlan_groups = vlan_match.groups()
             if vlan_groups[0] and vlan_groups[1]:
-                [new_ifacenames.append('vlan-%d' %v)
+                [new_ifacenames.append('%d' %v)
                     for v in range(int(vlan_groups[0]),
                             int(vlan_groups[1])+1)]
         return new_ifacenames
@@ -603,7 +942,7 @@ class ifupdownMain(ifupdownBase):
             ifaceobjs = self.get_ifaceobjs(i)
             if not ifaceobjs:
                 # if name not available, render interface name and check again
-                rendered_ifacenames = self._render_ifacename(i)
+                rendered_ifacenames = utils.expand_iface_range(i)
                 if rendered_ifacenames:
                     for ri in rendered_ifacenames:
                         ifaceobjs = self.get_ifaceobjs(ri)
@@ -626,29 +965,55 @@ class ifupdownMain(ifupdownBase):
 
         """
 
+        ret = True
+
+           # Check if interface matches the exclude patter
         if excludepats:
             for e in excludepats:
                 if re.search(e, ifacename):
-                    return False
+                    ret = False
         ifaceobjs = self.get_ifaceobjs(ifacename)
         if not ifaceobjs:
-            self.logger.debug('iface %s' %ifacename + ' not found')
-            return False
-        # We check classes first
+            if ret:
+                self.logger.debug('iface %s' %ifacename + ' not found')
+            return ret
+        # If matched exclude pattern, return false
+        if not ret:
+            for i in ifaceobjs:
+                i.blacklisted = True
+                self.blacklisted_ifaces_present = True
+            return ret
+        # Check if interface belongs to the class
+        # the user is interested in, if not return false
         if allow_classes:
+            ret = False
             for i in ifaceobjs:
                 if i.classes:
                     common = Set([allow_classes]).intersection(
                                 Set(i.classes))
                     if common:
-                        return True
-            return False
+                        ret = True
+            if not ret:
+                # If a class was requested and interface does not belong
+                # to the class, only then mark the ifaceobjs as blacklisted
+                self.blacklisted_ifaces_present = True
+                for i in ifaceobjs:
+                    i.blacklisted = True
+            return ret
+        # If the user has requested auto class, check if the interface
+        # is marked auto
         if auto:
+            ret = False
             for i in ifaceobjs:
                 if i.auto:
-                    return True
-            return False
-        return True
+                    ret = True
+            if not ret:
+                # If auto was requested and interface was not marked auto,
+                # only then mark all of them as blacklisted
+                self.blacklisted_ifaces_present = True
+                for i in ifaceobjs:
+                    i.blacklisted = True
+        return ret
 
     def _compat_conv_op_to_mode(self, op):
         """ Returns old op name to work with existing scripts """
@@ -676,7 +1041,8 @@ class ifupdownMain(ifupdownBase):
         return cenv
 
     def _save_state(self):
-        if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
+        if (not self.flags.STATEMANAGER_ENABLE or
+            not self.flags.STATEMANAGER_UPDATE):
             return
         try:
             # Update persistant iface states
@@ -687,8 +1053,34 @@ class ifupdownMain(ifupdownBase):
                 traceback.print_tb(t)
                 self.logger.warning('error saving state (%s)' %str(e))
 
+    def set_type(self, type):
+        if type == 'iface':
+            self.type = ifaceType.IFACE
+        elif type == 'vlan':
+            self.type = ifaceType.BRIDGE_VLAN
+        else:
+            self.type = ifaceType.UNKNOWN
+
+    def _process_delay_admin_state_queue(self, op):
+        if not self._delay_admin_state_iface_queue:
+           return
+        if op == 'up':
+           func = self.link_up
+        elif op == 'down':
+           func = self.link_down
+        else:
+           return
+        for i in self._delay_admin_state_iface_queue:
+            try:
+                if self.link_exists(i):
+                   func(i)
+            except Exception, e:
+                self.logger.warn(str(e))
+                pass
+
     def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
-           excludepats=None, printdependency=None, syntaxcheck=False):
+           excludepats=None, printdependency=None, syntaxcheck=False,
+           type=None, skipupperifaces=False):
         """This brings the interface(s) up
         
         Args:
@@ -703,21 +1095,20 @@ class ifupdownMain(ifupdownBase):
             syntaxcheck (bool): only perform syntax check
         """
 
+        self.set_type(type)
+
         if allow_classes:
-            self.IFACE_CLASS = True
-        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
+            self.flags.IFACE_CLASS = True
+        if not self.flags.ADDONS_ENABLE:
+            self.flags.STATEMANAGER_UPDATE = False
         if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
+            self.flags.ALL = True
+            self.flags.WITH_DEPENDS = True
         try:
-            self.read_iface_config()
+            iface_read_ret = self.read_iface_config()
         except Exception:
             raise
 
-        # If only syntax check was requested, return here
-        if syntaxcheck:
-            return
-
         if ifacenames:
             ifacenames = self._preprocess_ifacenames(ifacenames)
 
@@ -738,25 +1129,44 @@ class ifupdownMain(ifupdownBase):
         else:
             self.populate_dependency_info(ops)
 
+        # If only syntax check was requested, return here.
+        # return here because we want to make sure most
+        # errors above are caught and reported.
+        if syntaxcheck:
+            if not iface_read_ret:
+                raise Exception()
+            return
+
         try:
-            self._sched_ifaces(filtered_ifacenames, ops)
+            ret = self._sched_ifaces(filtered_ifacenames, ops,
+                                     skipupperifaces=skipupperifaces,
+                                     followdependents=True
+                                     if self.flags.WITH_DEPENDS else False)
         finally:
-            if not self.DRYRUN and self.ADDONS_ENABLE:
+            self._process_delay_admin_state_queue('up')
+            if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
                 self._save_state()
 
+        if not iface_read_ret or not ret:
+            raise Exception()
+
     def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
-             excludepats=None, printdependency=None, usecurrentconfig=False):
+             excludepats=None, printdependency=None, usecurrentconfig=False,
+             type=None):
         """ down an interface """
 
+        self.set_type(type)
+
         if allow_classes:
-            self.IFACE_CLASS = True
-        if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
+            self.flags.IFACE_CLASS = True
+        if not self.flags.ADDONS_ENABLE:
+            self.flags.STATEMANAGER_UPDATE = False
         if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
+            self.flags.ALL = True
+            self.flags.WITH_DEPENDS = True
         # For down we need to look at old state, unless usecurrentconfig
         # is set
-        if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
+        if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
                     self.statemanager.ifaceobjdict):
             # Since we are using state manager objects,
             # skip the updating of state manager objects
@@ -796,33 +1206,44 @@ class ifupdownMain(ifupdownBase):
             self.populate_dependency_info(ops)
 
         try:
-            self._sched_ifaces(filtered_ifacenames, ops)
+            self._sched_ifaces(filtered_ifacenames, ops,
+                               followdependents=True
+                               if self.flags.WITH_DEPENDS else False)
         finally:
-            if not self.DRYRUN and self.ADDONS_ENABLE:
+            self._process_delay_admin_state_queue('down')
+            if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
                 self._save_state()
 
-    def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
+    def query(self, ops, auto=False, format_list=False, allow_classes=None,
+              ifacenames=None,
               excludepats=None, printdependency=None,
-              format='native'):
+              format='native', type=None):
         """ query an interface """
 
+        self.set_type(type)
+
+        # Let us forget internal squashing when it comes to 
+        # ifquery. It can surprise people relying of ifquery
+        # output
+        self._ifaceobj_squash_internal = False
+
         if allow_classes:
-            self.IFACE_CLASS = True
-        if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
+            self.flags.IFACE_CLASS = True
+        if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
             return self.statemanager.dump_pretty(ifacenames)
-        self.STATEMANAGER_UPDATE = False
+        self.flags.STATEMANAGER_UPDATE = False
         if auto:
             self.logger.debug('setting flag ALL')
-            self.ALL = True
-            self.WITH_DEPENDS = True
+            self.flags.ALL = True
+            self.flags.WITH_DEPENDS = True
 
         if ops[0] == 'query-syntax':
             self._modules_help()
             return
         elif ops[0] == 'query-running':
             # create fake devices to all dependents that dont have config
-            map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
-                    ifacenames)
+            map(lambda i: self.create_n_save_ifaceobj(i,
+                                ifacePrivFlags(False, True)), ifacenames)
         else:
             try:
                 self.read_iface_config()
@@ -847,19 +1268,26 @@ class ifupdownMain(ifupdownBase):
                 raise Exception('no ifaces found matching ' +
                         'given allow lists')
 
-        self.populate_dependency_info(ops, filtered_ifacenames)
+        self.populate_dependency_info(ops)
         if ops[0] == 'query-dependency' and printdependency:
             self.print_dependency(filtered_ifacenames, printdependency)
             return
 
-        if ops[0] == 'query':
+        if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'):
+            return self.print_ifaceobjs_list(filtered_ifacenames)
+
+        if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS:
             return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
         elif ops[0] == 'query-raw':
             return self.print_ifaceobjs_raw(filtered_ifacenames)
 
-        self._sched_ifaces(filtered_ifacenames, ops)
+        ret = self._sched_ifaces(filtered_ifacenames, ops,
+                           followdependents=True
+                           if self.flags.WITH_DEPENDS else False)
 
-        if ops[0] == 'query-checkcurr':
+        if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
+            return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
+        elif ops[0] == 'query-checkcurr':
             ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
             if ret != 0:
                 # if any of the object has an error, signal that silently
@@ -868,19 +1296,108 @@ class ifupdownMain(ifupdownBase):
             self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
             return
 
-    def reload(self, upops, downops, auto=False, allow=None,
-            ifacenames=None, excludepats=None, usecurrentconfig=False):
-        """ reload interface config """
-        allow_classes = []
+    def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
+            ifacenames=None, excludepats=None, usecurrentconfig=False,
+            syntaxcheck=False, **extra_args):
+        """ reload currently up interfaces """
         new_ifaceobjdict = {}
 
-        self.logger.debug('reloading interface config ..')
+        # Override auto to true
+        auto = True
+        try:
+            iface_read_ret = self.read_iface_config()
+        except:
+            raise
+        if not self.ifaceobjdict:
+            self.logger.warn("nothing to reload ..exiting.")
+            return
+        already_up_ifacenames = []
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+        filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow,
+                               excludepats, i)]
+
+        # generate dependency graph of interfaces
+        self.populate_dependency_info(upops)
+
+        # If only syntax check was requested, return here.
+        # return here because we want to make sure most
+        # errors above are caught and reported.
+        if syntaxcheck:
+            if not iface_read_ret:
+                raise Exception()
+            return
+
+        if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
+                and self.statemanager.ifaceobjdict):
+            already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
+
+        # Get already up interfaces that still exist in the interfaces file
+        already_up_ifacenames_not_present = Set(
+                        already_up_ifacenames).difference(ifacenames)
+        already_up_ifacenames_still_present = Set(
+                        already_up_ifacenames).difference(
+                        already_up_ifacenames_not_present)
+        interfaces_to_up = Set(already_up_ifacenames_still_present).union(
+                                            filtered_ifacenames)
+
+        if (already_up_ifacenames_not_present and
+                self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
+           self.logger.info('reload: schedule down on interfaces: %s'
+                            %str(already_up_ifacenames_not_present))
+
+           # Save a copy of new iface objects and dependency_graph
+           new_ifaceobjdict = dict(self.ifaceobjdict)
+           new_dependency_graph = dict(self.dependency_graph)
+
+           # old interface config is read into self.ifaceobjdict
+           self.read_old_iface_config()
+
+           # reinitialize dependency graph 
+           self.dependency_graph = OrderedDict({})
+           falready_up_ifacenames_not_present = [i for i in
+                                    already_up_ifacenames_not_present
+                                    if self._iface_whitelisted(auto, allow,
+                                    excludepats, i)]
+           self.populate_dependency_info(downops,
+                                         falready_up_ifacenames_not_present)
+           self._sched_ifaces(falready_up_ifacenames_not_present, downops,
+                              followdependents=False, sort=True)
+        else:
+           self.logger.debug('no interfaces to down ..')
+
+        # Now, run 'up' with new config dict
+        # reset statemanager update flag to default
         if auto:
-            self.ALL = True
-            self.WITH_DEPENDS = True
+            self.flags.ALL = True
+            self.flags.WITH_DEPENDS = True
+        if new_ifaceobjdict:
+            # and now, ifaceobjdict is back to current config
+            self.ifaceobjdict = new_ifaceobjdict
+            self.dependency_graph = new_dependency_graph
+
+        if not self.ifaceobjdict:
+           return
+        self.logger.info('reload: scheduling up on interfaces: %s'
+                         %str(interfaces_to_up))
+        ret = self._sched_ifaces(interfaces_to_up, upops,
+                                 followdependents=True
+                                 if self.flags.WITH_DEPENDS else False)
+        if ifupdownflags.flags.DRYRUN:
+            return
+        self._save_state()
+
+        if not iface_read_ret or not ret:
+            raise Exception()
+
+    def _reload_default(self, upops, downops, auto=False, allow=None,
+            ifacenames=None, excludepats=None, usecurrentconfig=False,
+            syntaxcheck=False, **extra_args):
+        """ reload interface config """
+        new_ifaceobjdict = {}
 
         try:
-            self.read_iface_config()
+            iface_read_ret = self.read_iface_config()
         except:
             raise
 
@@ -888,14 +1405,30 @@ class ifupdownMain(ifupdownBase):
             self.logger.warn("nothing to reload ..exiting.")
             return
 
+        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+        new_filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow,
+                               excludepats, i)]
         # generate dependency graph of interfaces
         self.populate_dependency_info(upops)
-        if (not usecurrentconfig and self.STATEMANAGER_ENABLE
+
+        # If only syntax check was requested, return here.
+        # return here because we want to make sure most
+        # errors above are caught and reported.
+        if syntaxcheck:
+            if not iface_read_ret:
+                raise Exception()
+            return
+
+        if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
                 and self.statemanager.ifaceobjdict):
             # Save a copy of new iface objects and dependency_graph
             new_ifaceobjdict = dict(self.ifaceobjdict)
             new_dependency_graph = dict(self.dependency_graph)
 
+            self.ifaceobjdict = OrderedDict({})
+            self.dependency_graph = OrderedDict({})
+
             # if old state is present, read old state and mark op for 'down'
             # followed by 'up' aka: reload
             # old interface config is read into self.ifaceobjdict
@@ -904,21 +1437,48 @@ class ifupdownMain(ifupdownBase):
         else:
             # oldconfig not available, continue with 'up' with new config
             op = 'up'
+            new_ifaceobjdict = self.ifaceobjdict
+            new_dependency_graph = self.dependency_graph
 
-        if not ifacenames: ifacenames = self.ifaceobjdict.keys()
         if op == 'reload' and ifacenames:
-            filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
+            ifacenames = self.ifaceobjdict.keys()
+            old_filtered_ifacenames = [i for i in ifacenames
+                               if self._iface_whitelisted(auto, allow,
                                excludepats, i)]
+
+            # generate dependency graph of old interfaces,
+            # This should make sure built in interfaces are
+            # populated. disable check shared dependents as an optimization.
+            # these are saved interfaces and dependency for these
+            # have been checked before they became part of saved state.
+            try:
+                self.flags.CHECK_SHARED_DEPENDENTS = False 
+                self.populate_dependency_info(upops)
+                self.flags.CHECK_SHARED_DEPENDENTS = True
+            except Exception, e:
+                self.logger.info("error generating dependency graph for "
+                                 "saved interfaces (%s)" %str(e))
+                pass
+            
+            # make sure we pick up built-in interfaces
+            # if config file had 'ifreload_down_changed' variable
+            # set, also look for interfaces that changed to down them
+            down_changed = int(self.config.get('ifreload_down_changed', '1'))
+
             # Generate the interface down list
             # Interfaces that go into the down list:
             #   - interfaces that were present in last config and are not
             #     present in the new config
             #   - interfaces that were changed between the last and current
             #     config
-            #
             ifacedownlist = []
-            for ifname, lastifaceobjlist in self.ifaceobjdict.items():
+            for ifname in self.ifaceobjdict.keys():
+                lastifaceobjlist = self.ifaceobjdict.get(ifname)
+                if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
+                    # if interface is not built-in and is not in
+                    # old filtered ifacenames
+                    if ifname not in old_filtered_ifacenames:
+                        continue
                 objidx = 0
                 # If interface is not present in the new file
                 # append it to the down list
@@ -926,11 +1486,28 @@ class ifupdownMain(ifupdownBase):
                 if not newifaceobjlist:
                     ifacedownlist.append(ifname)
                     continue
-                # If interface has changed between the current file
-                # and the last installed append it to the down list
+                # If ifaceobj was present in the old interfaces file,
+                # and does not have a config in the new interfaces file
+                # but has been picked up as a dependent of another
+                # interface, catch it here. This catches a common error
+                # for example: remove a bond section from the interfaces
+                # file, but leave it around as a bridge port
+                # XXX: Ideally its better to just add it to the
+                # ifacedownlist. But we will be cautious here 
+                # and just print a warning
+                if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
+                    not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
+                    lastifaceobjlist[0].is_config_present()):
+                    self.logger.warn('%s: misconfig ? removed but still exists as a dependency of %s' %(newifaceobjlist[objidx].name,
+                         str(newifaceobjlist[objidx].upperifaces)))
+                if not down_changed:
+                    continue
                 if len(newifaceobjlist) != len(lastifaceobjlist):
                     ifacedownlist.append(ifname)
                     continue
+
+                # If interface has changed between the current file
+                # and the last installed append it to the down list
                 # compare object list
                 for objidx in range(0, len(lastifaceobjlist)):
                     oldobj = lastifaceobjlist[objidx]
@@ -940,34 +1517,77 @@ class ifupdownMain(ifupdownBase):
                         continue
 
             if ifacedownlist:
-                self.logger.info('Executing down on interfaces: %s'
+                self.logger.info('reload: scheduling down on interfaces: %s'
                                   %str(ifacedownlist))
                 # reinitialize dependency graph 
                 self.dependency_graph = OrderedDict({})
+
                 # Generate dependency info for old config
+                self.flags.CHECK_SHARED_DEPENDENTS = False
                 self.populate_dependency_info(downops, ifacedownlist)
-                self._sched_ifaces(ifacedownlist, downops)
+                self.flags.CHECK_SHARED_DEPENDENTS = True
+
+                try:
+                    # XXX: Hack to skip checking upperifaces during down.
+                    # the dependency list is not complete here
+                    # and we dont want to down the upperiface.
+                    # Hence during reload, set  this to true.
+                    # This is being added to avoid a failure in
+                    # scheduler._check_upperifaces when we are dowing
+                    # a builtin bridge port 
+                    self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
+                    self._sched_ifaces(ifacedownlist, downops,
+                                       followdependents=False,
+                                       sort=True)
+                except Exception, e:
+                    self.logger.error(str(e))
+                    pass
+                finally:
+                    self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
+                    self._process_delay_admin_state_queue('down')
             else:
                 self.logger.debug('no interfaces to down ..')
 
         # Now, run 'up' with new config dict
         # reset statemanager update flag to default
         if not new_ifaceobjdict:
+            self.logger.debug('no interfaces to up')
             return
+
+        if auto:
+            self.flags.ALL = True
+            self.flags.WITH_DEPENDS = True
+        # and now, we are back to the current config in ifaceobjdict
         self.ifaceobjdict = new_ifaceobjdict
         self.dependency_graph = new_dependency_graph
-        ifacenames = self.ifaceobjdict.keys()
-        filtered_ifacenames = [i for i in ifacenames
-                               if self._iface_whitelisted(auto, allow_classes,
-                               excludepats, i)]
 
-        self.logger.info('Scheduling up on interfaces: %s'
-                                  %str(filtered_ifacenames))
-        self._sched_ifaces(filtered_ifacenames, upops)
-        if self.DRYRUN:
+        self.logger.info('reload: scheduling up on interfaces: %s'
+                         %str(new_filtered_ifacenames))
+        ifupdownflags.flags.CACHE = True
+        try:
+            ret = self._sched_ifaces(new_filtered_ifacenames, upops,
+                                     followdependents=True
+                                     if self.flags.WITH_DEPENDS else False)
+        except Exception, e:
+            self.logger.error(str(e))
+            pass
+        finally:
+            self._process_delay_admin_state_queue('up')
+        if ifupdownflags.flags.DRYRUN:
             return
         self._save_state()
 
+        if not iface_read_ret or not ret:
+            raise Exception()
+
+    def reload(self, *args, **kargs):
+        """ reload interface config """
+        self.logger.debug('reloading interface config ..')
+        if kargs.get('currentlyup', False):
+            self._reload_currentlyup(*args, **kargs)
+        else:
+            self._reload_default(*args, **kargs)
+
     def _pretty_print_ordered_dict(self, prefix, argdict):
         outbuf = prefix + ' {\n'
         for k, vlist in argdict.items():
@@ -989,6 +1609,10 @@ class ifupdownMain(ifupdownBase):
                 self.dependency_graph.keys())
             graph.generate_dots(self.dependency_graph, indegrees)
 
+    def print_ifaceobjs_list(self, ifacenames):
+        for i in ifacenames:
+            print i
+
     def print_ifaceobjs_raw(self, ifacenames):
         """ prints raw lines for ifaces from config file """
 
@@ -999,7 +1623,7 @@ class ifupdownMain(ifupdownBase):
                     continue
                 ifaceobj.dump_raw(self.logger)
                 print '\n'
-                if self.WITH_DEPENDS and not self.ALL:
+                if self.flags.WITH_DEPENDS and not self.flags.ALL:
                     dlist = ifaceobj.lowerifaces
                     if not dlist: continue
                     self.print_ifaceobjs_raw(dlist)
@@ -1013,7 +1637,7 @@ class ifupdownMain(ifupdownBase):
                     (running and not ifaceobj.is_config_present())):
                     continue
                 ifaceobjs.append(ifaceobj)
-                if self.WITH_DEPENDS and not self.ALL:
+                if self.flags.WITH_DEPENDS and not self.flags.ALL:
                     dlist = ifaceobj.lowerifaces
                     if not dlist: continue
                     self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
@@ -1028,7 +1652,14 @@ class ifupdownMain(ifupdownBase):
             print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
                              indent=4, separators=(',', ': '))
         else:
-            map(lambda i: i.dump_pretty(), ifaceobjs)
+            expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
+            for i in ifaceobjs:
+                if not expand and (i.flags & iface.IFACERANGE_ENTRY):
+                    # print only the first one
+                    if i.flags & iface.IFACERANGE_START:
+                       i.dump_pretty(use_realname=True)
+                else:
+                    i.dump_pretty()
 
     def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
         ret = 0
@@ -1042,7 +1673,7 @@ class ifupdownMain(ifupdownBase):
                 if self.is_ifaceobj_noconfig(ifaceobj):
                     continue
                 ifaceobjs.append(ifaceobj)
-                if self.WITH_DEPENDS and not self.ALL:
+                if self.flags.WITH_DEPENDS and not self.flags.ALL:
                     dlist = ifaceobj.lowerifaces
                     if not dlist: continue
                     dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
@@ -1059,16 +1690,16 @@ class ifupdownMain(ifupdownBase):
         ifaceobjs = []
         ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
         if not ifaceobjs: return
-        self.logger.debug(ifaceobjs)
+
+        # override ifaceStatusUserStrs
+        ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
+        ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
+        ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
         if format == 'json':
-            print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
-                       separators=(',', ': '))
+            print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
+                             indent=2, separators=(',', ': '))
         else:
-            map(lambda i: i.dump_pretty(with_status=True,
-                    successstr=self.config.get('check_success_str',
-                                               _success_sym),
-                    errorstr=self.config.get('check_error_str', _error_sym)),
-                                ifaceobjs)
+            map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
         return ret
 
     def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):