]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - pkg/scheduler.py
Bump kernel ethtool get/set wait to 20 + ifupdown2 convert ethtool
[mirror_ifupdown2.git] / pkg / scheduler.py
index 7c23edf225910a50227a91e52a572a24480d58b4..a98ee7e650638bd85fc95786def029114a757ded 100644 (file)
@@ -21,89 +21,167 @@ from threading import *
 from ifupdownbase import *
 
 class ifaceSchedulerFlags():
-    INORDER = 1
-    POSTORDER = 2
+    INORDER = 0x1
+    POSTORDER = 0x2
 
 class ifaceScheduler():
     """ scheduler functions to schedule configuration of interfaces.
 
-
     supports scheduling of interfaces serially in plain interface list
     or dependency graph format.
+
+    Algo:
+        - run topological sort on the iface objects
+        - In the sorted iface object list, pick up interfaces with no parents
+        and run ops on them and their children. 
+        - If operation is up and user gave interface list (ie not all)
+        option, also see if there were upper-devices and run ops on them. 
+        - if operation is down, dont down the interface if it still
+        has upperifaces present. The down operation is executed when the
+        last upperiface goes away. If force option is set, this rule does not
+        apply.
+        - run ops calls addon modules run operation passing the iface
+        object and op to each module.
+        - ops are [pre-up, up, post-up, pre-down, down,
+                   post-down, query-running, query-check]
     """
 
-    token_pool = None
+    _STATE_CHECK = True
+
+    _SCHED_RETVAL = True
 
     @classmethod
-    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv):
+    def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
         """ Runs sub operation on an interface """
-        ifacename = ifaceobj.get_name()
+        ifacename = ifaceobj.name
 
-        if (ifaceobj.get_state() >= ifaceState.from_str(op) and
-           ifaceobj.get_status() == ifaceStatus.SUCCESS):
+        if (cls._STATE_CHECK and
+            (ifaceobj.state >= ifaceState.from_str(op))):
             ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
             return
-
-        # first run ifupdownobj handlers
-        handler = ifupdownobj.ops_handlers.get(op)
-        if handler:
-            addr_method = ifaceobj.get_addr_method()
-            if not addr_method or (addr_method and addr_method != 'manual'):
-                handler(ifupdownobj, ifaceobj)
-
+        if not ifupdownobj.ADDONS_ENABLE: return
+        if op == 'query-checkcurr':
+            query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
         for mname in ifupdownobj.module_ops.get(op):
             m = ifupdownobj.modules.get(mname)
             err = 0
             try:
                 if hasattr(m, 'run'):
-                    ifupdownobj.logger.debug('%s: %s : running module %s'
-                            %(ifacename, op, mname))
+                    msg = ('%s: %s : running module %s' %(ifacename, op, mname))
                     if op == 'query-checkcurr':
                         # Dont check curr if the interface object was 
                         # auto generated
                         if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
                             continue
-                        m.run(ifaceobj, op,
-                              query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj))
+                        ifupdownobj.logger.debug(msg)
+                        m.run(ifaceobj, op, query_ifaceobj)
                     else:
+                        ifupdownobj.logger.debug(msg)
                         m.run(ifaceobj, op)
             except Exception, e:
                 err = 1
                 ifupdownobj.log_error(str(e))
+                err = 0  # error can be ignored by log_error, in which case
+                         # reset err flag
             finally:
-                if err == 1:
-                    ifupdownobj.set_iface_state(ifaceobj,
-                                ifaceState.from_str(op),
-                                ifaceStatus.ERROR)
+                if err or ifaceobj.status == ifaceStatus.ERROR:
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                ifaceStatus.ERROR)
+                    if 'up' in  op or 'down' in op:
+                        cls._SCHED_RETVAL = False
                 else:
-                    ifupdownobj.set_iface_state(ifaceobj,
-                                ifaceState.from_str(op),
-                                ifaceStatus.SUCCESS)
+                    ifaceobj.set_state_n_status(ifaceState.from_str(op),
+                                                ifaceStatus.SUCCESS)
 
-        # execute /etc/network/ scripts 
-        mlist = ifupdownobj.script_ops.get(op)
-        if not mlist:
-            return
-        for mname in mlist:
-            ifupdownobj.logger.debug('%s: %s : running script %s'
+        if ifupdownobj.COMPAT_EXEC_SCRIPTS:
+            # execute /etc/network/ scripts 
+            for mname in ifupdownobj.script_ops.get(op, []):
+                ifupdownobj.logger.debug('%s: %s : running script %s'
                     %(ifacename, op, mname))
-            try:
-                ifupdownobj.exec_command(mname, cmdenv=cenv)
-            except Exception, e:
-                err = 1
-                ifupdownobj.log_error(str(e))
+                try:
+                    ifupdownobj.exec_command(mname, cmdenv=cenv)
+                except Exception, e:
+                    ifupdownobj.log_error(str(e))
 
     @classmethod
-    def run_iface_ops(cls, ifupdownobj, ifaceobj, ops):
-        """ Runs all sub operations on an interface """
+    def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
+        """ Runs all operations on a list of interface
+            configurations for the same interface
+        """
+        # minor optimization. If operation is 'down', proceed only
+        # if interface exists in the system
+        ifacename = ifaceobjs[0].name
+        if ('down' in ops[0] and
+                not ifupdownobj.link_exists(ifacename)):
+            ifupdownobj.logger.debug('%s: does not exist' %ifacename)
+            # run posthook before you get out of here, so that
+            # appropriate cleanup is done
+            posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+            if posthookfunc:
+                for ifaceobj in ifaceobjs:
+                    ifaceobj.status = ifaceStatus.SUCCESS
+                    posthookfunc(ifupdownobj, ifaceobj, 'down')
+            return 
+        for op in ops:
+            # first run ifupdownobj handlers. This is good enough
+            # for the first object in the list
+            handler = ifupdownobj.ops_handlers.get(op)
+            if handler:
+                if (not ifaceobjs[0].addr_method or
+                    (ifaceobjs[0].addr_method and
+                    ifaceobjs[0].addr_method != 'manual')):
+                    handler(ifupdownobj, ifaceobjs[0])
+            for ifaceobj in ifaceobjs:
+                cls.run_iface_op(ifupdownobj, ifaceobj, op,
+                    cenv=ifupdownobj.generate_running_env(ifaceobj, op)
+                        if ifupdownobj.COMPAT_EXEC_SCRIPTS else None) 
+                posthookfunc = ifupdownobj.sched_hooks.get('posthook')
+                if posthookfunc:
+                    posthookfunc(ifupdownobj, ifaceobj, op)
 
-        # For backward compatibility execute scripts with
-        # environent set
-        cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0])
+    @classmethod
+    def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
+                           followdependents=False):
+        """ Check if upperifaces are hanging off us and help caller decide
+        if he can proceed with the ops on this device
 
-        # Each sub operation has a module list
-        [cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
-                        for op in ops]
+        Returns True or False indicating the caller to proceed with the
+        operation.
+        """
+        # proceed only for down operation
+        if 'down' not in ops[0]:
+            return True
+
+        if (ifupdownobj.FORCE or
+                not ifupdownobj.ADDONS_ENABLE or
+                (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
+                ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
+                not ifupdownobj.ALL)):
+            return True
+
+        ulist = ifaceobj.upperifaces
+        if not ulist:
+            return True
+
+        # Get the list of upper ifaces other than the parent
+        tmpulist = ([u for u in ulist if u != parent] if parent
+                    else ulist)
+        if not tmpulist:
+            return True
+        # XXX: This is expensive. Find a cheaper way to do this.
+        # if any of the upperdevs are present,
+        # return false to the caller to skip this interface
+        for u in tmpulist:
+            if ifupdownobj.link_exists(u):
+                if not ifupdownobj.ALL:
+                    if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
+                        ifupdownobj.logger.info('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                    else:
+                        ifupdownobj.logger.warn('%s: skipping interface down,'
+                            %ifaceobj.name + ' upperiface %s still around ' %u)
+                return False
+        return True
 
     @classmethod
     def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
@@ -111,52 +189,26 @@ class ifaceScheduler():
                         followdependents=True):
         """ runs interface by traversing all nodes rooted at itself """
 
-        # minor optimization. If operation is 'down', proceed only
-        # if interface exists in the system
-        if 'down' in ops[0] and not ifupdownobj.link_exists(ifacename):
-            ifupdownobj.logger.info('%s: does not exist' %ifacename)
-            return 
-
         # Each ifacename can have a list of iface objects
-        ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
-        if ifaceobjs is None:
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
             raise Exception('%s: not found' %ifacename)
 
         for ifaceobj in ifaceobjs:
-            # Deal with upperdevs first
-            ulist = ifaceobj.get_upperifaces()
-            if ulist:
-                tmpulist = ([u for u in ulist if u != parent] if parent
-                            else ulist)
-                if tmpulist:
-                    if 'down' in ops[0]:
-                        # XXX: This is expensive. Find a cheaper way to do this 
-                        # if any of the upperdevs are present,
-                        # dont down this interface
-                        for u in tmpulist:
-                            if ifupdownobj.link_exists(u):
-                                if not ifupdownobj.ALL:
-                                    ifupdownobj.logger.warn('%s: ' %ifacename +
-                                            ' skip interface down,' +
-                                            ' upperiface %s still around' %u)
-                                return
-                    elif 'up' in ops[0] and not ifupdownobj.ALL:
-                        # For 'up', just warn that there is an upperdev which is
-                        # probably not up
-                        for u in tmpulist:
-                            if not ifupdownobj.link_exists(u):
-                                ifupdownobj.logger.warn('%s: upper iface %s '
-                                         %(ifacename, u) + 'does not exist')
-
-            if order == ifaceSchedulerFlags.INORDER:
-                # If inorder, run the iface first and then its dependents
-                cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
+            if not cls._check_upperifaces(ifupdownobj, ifaceobj,
+                                          ops, parent, followdependents):
+                return
+
+        # If inorder, run the iface first and then its dependents
+        if order == ifaceSchedulerFlags.INORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
 
+        for ifaceobj in ifaceobjs:
             # Run lowerifaces or dependents
-            dlist = ifaceobj.get_lowerifaces()
+            dlist = ifaceobj.lowerifaces
             if dlist:
-                ifupdownobj.logger.info('%s:' %ifacename +
-                    ' found dependents: %s' %str(dlist))
+                ifupdownobj.logger.debug('%s: found dependents %s'
+                            %(ifacename, str(dlist)))
                 try:
                     if not followdependents:
                         # XXX: this is yet another extra step,
@@ -165,12 +217,11 @@ class ifaceScheduler():
                         # not follow dependents, we must follow the ones
                         # that dont have user given config. Because we own them
                         new_dlist = [d for d in dlist
-                                     if ifupdownobj.is_iface_noconfig(d)]
+                                    if ifupdownobj.is_iface_noconfig(d)]
                         if new_dlist:
                             cls.run_iface_list(ifupdownobj, new_dlist, ops,
-                                                ifacename, order,
-                                                followdependents,
-                                                continueonfailure=False)
+                                           ifacename, order, followdependents,
+                                           continueonfailure=False)
                     else:
                         cls.run_iface_list(ifupdownobj, dlist, ops,
                                             ifacename, order,
@@ -181,11 +232,11 @@ class ifaceScheduler():
                         pass
                     else:
                         # Dont bring the iface up if children did not come up
-                        ifaceobj.set_state(ifaceState.NEW)
-                        ifaceobj.set_status(ifaceStatus.ERROR)
+                        ifaceobj.set_state_n_status(ifaceState.NEW,
+                                                ifaceStatus.ERROR)
                         raise
-            if order == ifaceSchedulerFlags.POSTORDER:
-                cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
+        if order == ifaceSchedulerFlags.POSTORDER:
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
 
     @classmethod
     def run_iface_list(cls, ifupdownobj, ifacenames,
@@ -207,295 +258,176 @@ class ifaceScheduler():
                     if (ifupdownobj.ignore_error(str(e))):
                         pass
                     else:
-                        raise Exception('error running iface %s (%s)'
-                                %(ifacename, str(e)))
+                        raise Exception('%s : (%s)' %(ifacename, str(e)))
 
     @classmethod
-    def run_iface_dependency_graphs(cls, ifupdownobj,
-                dependency_graph, ops, indegrees=None,
-                order=ifaceSchedulerFlags.POSTORDER,
-                followdependents=True):
-        """ Runs iface dependeny graph by visiting all the nodes
-        
-        Parameters:
-        -----------
-        ifupdownobj : ifupdown object (used for getting and updating iface
-                                        object state)
-        dependency_graph : dependency graph in adjacency list
-                            format (contains more than one dependency graph)
-        ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
-
-        indegrees : indegree array if present is used to determine roots
-                    of the graphs in the dependency_graph
-        """
-        run_queue = []
-
-        if indegrees is None:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graph.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-
-        sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph,
-                                                          dict(indegrees))
-        ifupdownobj.logger.debug('sorted ifacenames %s : '
-                                 %str(sorted_ifacenames))
-
-        # Build a list of ifaces that dont have any dependencies
-        for ifacename in sorted_ifacenames:
-            if not indegrees.get(ifacename):
-                run_queue.append(ifacename)
-
-        ifupdownobj.logger.info('graph roots (interfaces that dont have '
-                                'dependents):' + ' %s' %str(run_queue))
-
-        return cls.run_iface_list(ifupdownobj, run_queue, ops,
-                                  parent=None,order=order,
-                                  followdependents=followdependents)
-
-    @classmethod
-    def run_iface(cls, ifupdownobj, ifacename, ops):
-        """ Runs operation on an interface """
-
-        ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
-        for i in ifaceobjs:
-            cls.run_iface_ops(ifupdownobj, i, ops)
-
-    @classmethod
-    def run_iface_list_op(cls, ifupdownobj, ifacenames, op,
-                          sorted_by_dependency=False):
-        """ Runs interface list through sub operation handler. """
-
-        ifupdownobj.logger.debug('running operation %s on all given interfaces'
-                                 %op)
-        iface_run_queue = deque(ifacenames)
-        for i in range(0, len(iface_run_queue)):
-            if op.endswith('up'):
-                # XXX: simplify this
-                if sorted_by_dependency:
-                    ifacename = iface_run_queue.pop()
-                else:
-                    ifacename = iface_run_queue.popleft()
-            else:
-                if sorted_by_dependency:
-                    ifacename = iface_run_queue.popleft()
-                else:
-                    ifacename = iface_run_queue.pop()
-
-            try:
-                ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
-                for ifaceobj in ifaceobjs:
-                    cenv = ifupdownobj.generate_running_env(ifaceobj, op)
-                    cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
-            except Exception, e:
-                ifupdownobj.log_error(str(e))
-
-    @classmethod
-    def run_iface_list_ops(cls, ifupdownobj, ifacenames, ops,
-                           sorted_by_dependency=False):
-        """ Runs interface list through sub operations handler
-
-        Unlike run_iface_list, this method executes a sub operation on the
-        entire interface list before proceeding to the next sub-operation.
-        ie operation 'pre-up' is run through the entire interface list before
-        'up'
-        """
-        # Each sub operation has a module list
-        [cls.run_iface_list_op(ifupdownobj, ifacenames, op,
-                sorted_by_dependency) for op in ops]
-
-    @classmethod
-    def run_iface_dependency_graphs_sorted(cls, ifupdownobj,
-                                           dependency_graphs,
-                                           ops, indegrees=None,
-                                           graphsortall=False):
-        """ runs interface dependency graph by topologically sorting the interfaces """
-
-        if indegrees is None:
-            indegrees = OrderedDict()
-            for ifacename in dependency_graphs.keys():
-                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-
-        ifupdownobj.logger.debug('indegree array :')
-        ifupdownobj.logger.debug(ifupdownobj.pp.pformat(indegrees))
-
-        try:
-            ifupdownobj.logger.debug('calling topological sort on the graph ' +
-                                      '...')
-            if graphsortall:
-                sorted_ifacenames = graph.topological_sort_graphs_all(
-                                            dependency_graphs, indegrees)
-            else:
-                sorted_ifacenames = graph.topological_sort_graphs(
-                                            dependency_graphs, indegrees)
-        except Exception:
-            raise
-
-        ifupdownobj.logger.debug('sorted iface list = %s' %sorted_ifacenames)
-        cls.run_iface_list_ops(ifupdownobj, sorted_ifacenames, ops,
-                               sorted_by_dependency=True)
-
-
-    """ Methods to execute interfaces in parallel """
-    @classmethod
-    def init_tokens(cls, count):
-        cls.token_pool = BoundedSemaphore(count)
-
-    @classmethod
-    def accquire_token(cls, logprefix=''):
-        cls.token_pool.acquire()
-
-    @classmethod
-    def release_token(cls, logprefix=''):
-        cls.token_pool.release()
-
-    @classmethod
-    def run_iface_parallel(cls, ifupdownobj, ifacename, op):
-        """ Configures interface in parallel.
-        
-        Executes all its direct dependents in parallel
-        
-        """
-
-        ifupdownobj.logger.debug('%s:' %ifacename + ' %s' %op)
-        cls.accquire_token(iface)
+    def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
+                        followdependents=True, skip_root=False):
+        """ runs interface by traversing all nodes rooted at itself """
 
-        # Each iface can have a list of objects
-        ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
-        if ifaceobjs is None:
-            ifupdownobj.logger.warning('%s: ' %ifacename + 'not found')
-            cls.release_token(ifacename)
-            return -1
+        # Each ifacename can have a list of iface objects
+        ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+        if not ifaceobjs:
+            raise Exception('%s: not found' %ifacename)
 
+        if not skip_root:
+            # run the iface first and then its upperifaces
+            cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
         for ifaceobj in ifaceobjs:
-            # Run dependents
-            dlist = ifaceobj.get_lowerifaces()
-            if dlist:
-                ifupdownobj.logger.debug('%s:' %ifacename +
-                    ' found dependents: %s' %str(dlist))
+            # Run upperifaces
+            ulist = ifaceobj.upperifaces
+            if ulist:
+                ifupdownobj.logger.debug('%s: found upperifaces %s'
+                                            %(ifacename, str(ulist)))
                 try:
-                    cls.release_token(ifacename)
-                    cls.run_iface_list_parallel(ifacename, ifupdownobj,
-                                                 dlist, op)
-                    cls.accquire_token(ifacename)
+                    cls.run_iface_list_upper(ifupdownobj, ulist, ops,
+                                            ifacename,
+                                            followdependents,
+                                            continueonfailure=True)
                 except Exception, e:
-                    if ifupdownobj.ignore_error(str(e)):
+                    if (ifupdownobj.ignore_error(str(e))):
                         pass
                     else:
-                        # Dont bring the iface up if children did not come up
-                        ifupdownobj.logger.debug('%s:' %ifacename +
-                            ' there was an error bringing %s' %op +
-                            ' dependents (%s)', str(e))
-                        ifupdownobj.set_iface_state(ifaceobj,
-                            ifaceState.from_str(ops[0]),
-                            ifaceStatus.ERROR)
-                        return -1
-
-            # Run all sub operations sequentially
-            try:
-                ifupdownobj.logger.debug('%s:' %ifacename +
-                                         ' running sub-operations')
-                cls.run_iface_ops(ifupdownobj, ifaceobj, op)
-            except Exception, e:
-                ifupdownobj.logger.error('%s:' %ifacename +
-                    ' error running sub operations (%s)' %str(e))
-
-        cls.release_token(ifacename)
+                        raise
 
     @classmethod
-    def run_iface_list_parallel(cls, parent, ifupdownobj, ifacenames, op):
-        """ Runs interface list in parallel """
-
-        running_threads = OrderedDict()
-        err = 0
+    def run_iface_list_upper(cls, ifupdownobj, ifacenames,
+                       ops, parent=None, followdependents=True,
+                       continueonfailure=True, skip_root=False):
+        """ Runs interface list """
 
         for ifacename in ifacenames:
             try:
-                cls.accquire_token(parent)
-                running_threads[ifacename] = Thread(None,
-                    cls.run_iface_parallel, ifacename,
-                    args=(ifupdownobj, ifacename, op))
-                running_threads[ifacename].start()
-                cls.release_token(parent)
+              cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
+                      followdependents, skip_root)
             except Exception, e:
-                cls.release_token(parent)
-                if ifupdownobj.ignore_error(str(e)):
+                if continueonfailure:
+                    if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
+                        traceback.print_tb(sys.exc_info()[2])
+                    ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
                     pass
                 else:
-                    raise Exception('error starting thread for iface %s'
-                            %ifacename)
-
-
-        ifupdownobj.logger.debug('%s ' %parent +
-                                 'waiting for all the threads ...')
-        for ifacename, t  in running_threads.items():
-            t.join()
-            if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS:
-                err += 1
-
-        return err
+                    if (ifupdownobj.ignore_error(str(e))):
+                        pass
+                    else:
+                        raise Exception('%s : (%s)' %(ifacename, str(e)))
 
     @classmethod
-    def run_iface_graphs_parallel(cls, parent, ifupdownobj, ifacenames, op):
-        """ Runs iface graphs in parallel """
-
-        running_threads = OrderedDict()
-        err = 0
-
-        for ifacename in ifacenames:
-            try:
-                cls.accquire_graph_token(parent)
-                running_threads[ifacename] = Thread(None,
-                    cls.run_iface_parallel, ifacename,
-                    args=(ifupdownobj, ifacename, op))
-                running_threads[ifacename].start()
-                cls.release_graph_token(parent)
-            except Exception, e:
-                cls.release_graph_token(parent)
-                if ifupdownobj.ignore_error(str(e)):
-                    pass
-                else:
-                    raise Exception('error starting thread for iface %s'
-                            %ifacename)
-
-        ifupdownobj.logger.info('%s ' %parent +
-                                'waiting for all the threads ...')
-        for ifacename, t in running_threads.items():
-            t.join()
-            # Check status of thread
-            # XXX: Check all objs
-            if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS:
-                err += 1
-        return err
+    def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
+                              dependency_graph, indegrees=None):
+        if len(ifacenames) == 1:
+            return ifacenames
+        # Get a sorted list of all interfaces
+        if not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
+        ifacenames_all_sorted = graph.topological_sort_graphs_all(
+                                        dependency_graph, indegrees)
+        # if ALL was set, return all interfaces
+        if ifupdownobj.ALL:
+            return ifacenames_all_sorted
+
+        # else return ifacenames passed as argument in sorted order
+        ifacenames_sorted = []
+        [ifacenames_sorted.append(ifacename)
+                        for ifacename in ifacenames_all_sorted
+                            if ifacename in ifacenames]
+        return ifacenames_sorted
 
     @classmethod
-    def run_iface_dependency_graph_parallel(cls, ifupdownobj, dependency_graph,
-                                            operation):
-        """ Runs iface dependeny graph in parallel.
+    def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
+                dependency_graph=None, indegrees=None,
+                order=ifaceSchedulerFlags.POSTORDER,
+                followdependents=True):
+        """ Runs iface dependeny graph by visiting all the nodes
         
-        arguments:
-        ifupdownobj -- ifupdown object (used for getting and updating iface
+        Parameters:
+        -----------
+        ifupdownobj : ifupdown object (used for getting and updating iface
                                         object state)
-        dependency_graph -- dependency graph with 
-        operation -- 'up' or 'down' or 'query'
+        dependency_graph : dependency graph in adjacency list
+                            format (contains more than one dependency graph)
+        ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
 
+        indegrees : indegree array if present is used to topologically sort
+                    the graphs in the dependency_graph
         """
-
-        ifupdownobj.logger.debug('running dependency graph in parallel ..')
+        #
+        # Algo:
+        # if ALL/auto interfaces are specified,
+        #   - walk the dependency tree in postorder or inorder depending
+        #     on the operation.
+        #     (This is to run interfaces correctly in order)
+        # else:
+        #   - sort iface list if the ifaces belong to a "class"
+        #   - else just run iface list in the order they were specified
+        #
+        # Run any upperifaces if available
+        #
+        followupperifaces = []
         run_queue = []
-        # Build a list of ifaces that dont have any dependencies
-        for ifacename in dependency_graph.keys():
-            if ifupdownobj.get_iface_refcnt(ifacename) == 0:
-                run_queue.append(ifacename)
-
-        ifupdownobj.logger.debug('graph roots (interfaces that dont'
-                    ' have dependents):' + ' %s' %str(run_queue))
-        cls.init_tokens(ifupdownobj.get_njobs())
-        return cls.run_iface_list_parallel('main', ifupdownobj, run_queue,
-                                            operation)
-
-        # OR
-        # Run one graph at a time
-        #for iface in run_queue:
-        #    self.run_iface_list_parallel('main', ifupdownobj, [iface],
-        #            operation)
+        skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
+        if not skip_ifacesort and not indegrees:
+            indegrees = OrderedDict()
+            for ifacename in dependency_graph.keys():
+                indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
 
+        if not ifupdownobj.ALL:
+            # If there is any interface that does exist, maybe it is a
+            # logical interface and we have to followupperifaces when it
+            # comes up, so get that list.
+            followupperifaces = (True if
+                                    [i for i in ifacenames
+                                        if not ifupdownobj.link_exists(i)]
+                                        else False)
+            if not skip_ifacesort and ifupdownobj.IFACE_CLASS:
+                # sort interfaces only if allow class was specified and
+                # not skip_ifacesort
+                run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
+                                    ops, dependency_graph, indegrees)
+                if run_queue and 'up' in ops[0]:
+                    run_queue.reverse()
+        else:
+            # if -a is set, we dont really have to sort. We pick the interfaces
+            # that have no parents and 
+            if not skip_ifacesort:
+                sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
+                                            ifacenames, ops, dependency_graph,
+                                            indegrees)
+                if sorted_ifacenames:
+                    # pick interfaces that user asked
+                    # and those that dont have any dependents first
+                    [run_queue.append(ifacename)
+                        for ifacename in sorted_ifacenames
+                            if ifacename in ifacenames and
+                            not indegrees.get(ifacename)]
+                    ifupdownobj.logger.debug('graph roots (interfaces that ' +
+                            'dont have dependents):' + ' %s' %str(run_queue))
+                else:
+                    ifupdownobj.logger.warn('interface sort returned None')
+
+        # If queue not present, just run interfaces that were asked by the user
+        if not run_queue:
+            run_queue = list(ifacenames)
+            if 'down' in ops[0]:
+                run_queue.reverse()
+
+        # run interface list
+        ifupdownobj.logger.info('running interfaces: %s' %str(run_queue))
+        cls.run_iface_list(ifupdownobj, run_queue, ops,
+                           parent=None, order=order,
+                           followdependents=followdependents)
+        if (((not ifupdownobj.ALL and followdependents) or
+                followupperifaces) and
+                'up' in ops[0]):
+            # If user had given a set of interfaces to bring up
+            # try and execute 'up' on the upperifaces
+            ifupdownobj.logger.info('running upperifaces if available ..')
+            cls._STATE_CHECK = False
+            cls.run_iface_list_upper(ifupdownobj, ifacenames, ops,
+                                     skip_root=True)
+            cls._STATE_CHECK = True
+
+        if not cls._SCHED_RETVAL:
+            raise Exception()