# interface scheduler
#
-import os
-import re
from statemanager import *
from iface import *
from graph import *
from collections import deque
from collections import OrderedDict
-import imp
-import pprint
import logging
+import traceback
+import sys
from graph import *
from collections import deque
from threading import *
from ifupdownbase import *
-class ifaceScheduler(ifupdownBase):
- """ scheduler to schedule configuration of interfaces.
+class ifaceSchedulerFlags():
+ 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]
"""
- def __init__(self, force=False):
- self.logger = logging.getLogger('ifupdown.' +
- self.__class__.__name__)
- self.FORCE = force
+ _STATE_CHECK = True
- def run_iface_subop(self, ifupdownobj, ifaceobj, op, subop, mdict, cenv):
+ @classmethod
+ def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
""" Runs sub operation on an interface """
-
- self.logger.debug('%s: ' %ifaceobj.get_name() + 'op %s' %op +
- ' subop = %s' %subop)
-
- for mname, mdata in mdict.items():
- m = mdata.get('module')
+ ifacename = ifaceobj.name
+
+ if (cls._STATE_CHECK and
+ (ifaceobj.state >= ifaceState.from_str(op)) and
+ (ifaceobj.status == ifaceStatus.SUCCESS)):
+ ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
+ return
+ 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 (mdata.get('ftype') == 'pmodule' and
- hasattr(m, 'run') == True):
- self.logger.debug('%s: ' %ifaceobj.get_name() +
- 'running module %s' %mname +
- ' op %s' %op + ' subop %s' %subop)
+ if hasattr(m, 'run'):
+ msg = ('%s: %s : running module %s' %(ifacename, op, mname))
if op == 'query-checkcurr':
- m.run(ifaceobj, subop, query_check=True,
- query_ifaceobj=ifupdownobj.create_ifaceobjcurr(
- ifaceobj))
+ # Dont check curr if the interface object was
+ # auto generated
+ if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
+ continue
+ ifupdownobj.logger.debug(msg)
+ m.run(ifaceobj, op, query_ifaceobj)
else:
- m.run(ifaceobj, subop)
- else:
- self.logger.debug('%s: ' %ifaceobj.get_name() +
- 'running script %s' %mname +
- ' op %s' %op + ' subop %s' %subop)
- self.exec_command(m, cmdenv=cenv)
+ ifupdownobj.logger.debug(msg)
+ m.run(ifaceobj, op)
except Exception, e:
err = 1
- self.log_error(str(e))
+ ifupdownobj.log_error(str(e))
finally:
- if op[:5] != 'query':
- if err == 1:
- ifupdownobj.set_iface_state(ifaceobj,
- ifaceState.from_str(subop),
- ifaceStatus.ERROR)
- else:
- ifupdownobj.set_iface_state(ifaceobj,
- ifaceState.from_str(subop),
- ifaceStatus.SUCCESS)
-
- def run_iface_subops(self, ifupdownobj, ifaceobj, op):
- """ Runs all sub operations on an interface """
-
- # For backward compatibility execute scripts with
- # environent set
- cenv = ifupdownobj.generate_running_env(ifaceobj, op)
-
- # Each sub operation has a module list
- subopdict = ifupdownobj.operations.get(op)
- for subop, mdict in subopdict.items():
- self.run_iface_subop(ifupdownobj, ifaceobj, op, subop, mdict, cenv)
-
-
- def run_iface(self, ifupdownobj, ifacename, op):
- """ Runs operation on an interface """
-
- ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
- for i in ifaceobjs:
- if (op != 'query' and ifupdownobj.STATE_CHECK == True and
- ifupdownobj.is_valid_state_transition(i, op) == False and
- ifupdownobj.FORCE == False):
- self.logger.warning('%s' %ifacename +
- ' already %s' %op)
- continue
-
- self.run_iface_subops(ifupdownobj, i, op)
-
-
- def run_iface_list(self, ifupdownobj, ifacenames, operation,
- sorted_by_dependency=False):
- """ Runs interface list serially executing all sub operations on
- each interface at a time. """
-
- self.logger.debug('run_iface_list: running interface list for ' +
- 'operation %s' %operation)
-
- iface_run_queue = deque(ifacenames)
- for i in range(0, len(iface_run_queue)):
- if operation == 'up':
- # XXX: simplify this
- if sorted_by_dependency == True:
- ifacename = iface_run_queue.pop()
- else:
- ifacename = iface_run_queue.popleft()
- else:
- if sorted_by_dependency == True:
- ifacename = iface_run_queue.popleft()
+ if err:
+ ifaceobj.set_state_n_status(ifaceState.from_str(op),
+ ifaceStatus.ERROR)
else:
- ifacename = iface_run_queue.pop()
-
- try:
- self.run_iface(ifupdownobj, ifacename, operation)
- except Exception, e:
- self.log_error(str(e))
-
- def run_iface_list_subop(self, ifupdownobj, ifacenames, op, subop, mdict,
- sorted_by_dependency=False):
- """ Runs interface list through sub operation handler. """
-
- self.logger.debug('running sub operation %s on all given interfaces' %op)
- iface_run_queue = deque(ifacenames)
- for i in range(0, len(iface_run_queue)):
- if op == 'up':
- # XXX: simplify this
- if sorted_by_dependency == True:
- ifacename = iface_run_queue.pop()
- else:
- ifacename = iface_run_queue.popleft()
- else:
- if sorted_by_dependency == True:
- ifacename = iface_run_queue.popleft()
- else:
- ifacename = iface_run_queue.pop()
-
- try:
- ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
- for ifaceobj in ifaceobjs:
- if (op != 'query' and ifupdownobj.STATE_CHECK == True and
- ifupdownobj.is_valid_state_transition(ifaceobj,
- op) == False and ifupdownobj.FORCE == False):
- if subop == 'post-down' or subop == 'post-up':
- self.logger.warning('%s: ' %ifacename +
- ' already %s' %op)
- continue
-
- cenv = ifupdownobj.generate_running_env(ifaceobj, op)
- self.run_iface_subop(ifupdownobj, ifaceobj, op, subop,
- mdict, cenv)
- except Exception, e:
- self.log_error(str(e))
-
- def run_iface_list_stages(self, ifupdownobj, ifacenames, op,
- sorted_by_dependency=False):
- """ Runs interface list through sub operations handler
+ ifaceobj.set_state_n_status(ifaceState.from_str(op),
+ ifaceStatus.SUCCESS)
+
+ 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:
+ ifupdownobj.log_error(str(e))
- 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'
+ @classmethod
+ def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
+ """ Runs all operations on a list of interface
+ configurations for the same interface
"""
-
- self.logger.debug('run_iface_list_stages: running interface list for %s'
- %op)
-
- # Each sub operation has a module list
- subopdict = ifupdownobj.operations.get(op)
- for subop, mdict in subopdict.items():
- self.run_iface_list_subop(ifupdownobj, ifacenames, op, subop, mdict,
- sorted_by_dependency)
-
-
- def run_iface_dependency_graph(self, ifupdownobj, dependency_graph,
- operation):
- """ runs interface dependency graph """
-
- indegrees = OrderedDict()
-
- self.logger.debug('creating indegree array ...')
- for ifacename in dependency_graph.keys():
- indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
-
- if self.logger.isEnabledFor(logging.DEBUG) == True:
- self.logger.debug('indegree array :')
- ifupdownobj.pp.pprint(indegrees)
-
- try:
- self.logger.debug('calling topological sort on the graph ...')
- sorted_ifacenames = graph.topological_sort(dependency_graph,
- indegrees)
- except Exception, e:
- raise
-
- self.logger.debug('sorted iface list = %s' %sorted_ifacenames)
-
- #self.run_iface_list(ifupdownobj, sorted_ifacenames, operation,
- # sorted_by_dependency=True)
-
- self.run_iface_list_stages(ifupdownobj, sorted_ifacenames, operation,
- sorted_by_dependency=True)
-
-
- def init_tokens(self, count):
- self.token_pool = BoundedSemaphore(count)
- self.logger.debug('initialized bounded semaphore with %d' %count)
-
- def accquire_token(self, logprefix=''):
- self.token_pool.acquire()
- self.logger.debug('%s ' %logprefix + 'acquired token')
-
- def release_token(self, logprefix=''):
- self.token_pool.release()
- self.logger.debug('%s ' %logprefix + 'release token')
-
- def run_iface_parallel(self, ifupdownobj, ifacename, op):
- """ Configures interface in parallel.
-
- Executes all its direct dependents in parallel
-
+ # 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)
+
+ @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
+
+ 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,
+ order=ifaceSchedulerFlags.POSTORDER,
+ followdependents=True):
+ """ runs interface by traversing all nodes rooted at itself """
+
+ # Each ifacename can have a list of iface objects
+ ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+ if not ifaceobjs:
+ raise Exception('%s: not found' %ifacename)
- self.logger.debug('%s:' %ifacename + ' %s' %op)
- self.accquire_token(iface)
+ for ifaceobj in ifaceobjs:
+ if not cls._check_upperifaces(ifupdownobj, ifaceobj,
+ ops, parent, followdependents):
+ return
- # Each iface can have a list of objects
- ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
- if ifaceobjs is None:
- self.logger.warning('%s: ' %ifacename + 'not found')
- self.release_token(ifacename)
- return -1
+ # 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 dependents
- dlist = ifaceobj.get_dependents()
- if dlist is not None and len(dlist) > 0:
- self.logger.debug('%s:' %ifacename +
- ' found dependents: %s' %str(dlist))
+ # Run lowerifaces or dependents
+ dlist = ifaceobj.lowerifaces
+ if dlist:
+ ifupdownobj.logger.debug('%s: found dependents %s'
+ %(ifacename, str(dlist)))
try:
- self.release_token(ifacename)
- self.run_iface_list_parallel(ifacename, ifupdownobj,
- dlist, op)
- self.accquire_token(ifacename)
+ if not followdependents:
+ # XXX: this is yet another extra step,
+ # but is needed for interfaces that are
+ # implicit dependents. even though we are asked to
+ # 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 new_dlist:
+ cls.run_iface_list(ifupdownobj, new_dlist, ops,
+ ifacename, order, followdependents,
+ continueonfailure=False)
+ else:
+ cls.run_iface_list(ifupdownobj, dlist, ops,
+ ifacename, order,
+ followdependents,
+ continueonfailure=False)
except Exception, e:
- if (self.ignore_error(str(e)) == True):
+ if (ifupdownobj.ignore_error(str(e))):
pass
else:
# Dont bring the iface up if children did not come up
- self.logger.debug('%s:' %ifacename +
- ' there was an error bringing %s' %op +
- ' dependents (%s)', str(e))
- ifupdownobj.set_iface_state(ifaceobj,
- ifaceState.from_str(
- ifupdownobj.get_subops(op)[0]),
- ifaceStatus.ERROR)
- return -1
-
- if (op != 'query' and ifupdownobj.STATE_CHECK == True and
- ifupdownobj.is_valid_state_transition(ifaceobj,
- op) == False and ifupdownobj.FORCE == False):
- self.logger.warning('%s:' %ifacename + ' already %s' %op)
- continue
-
-
- # Run all sub operations sequentially
- try:
- self.logger.debug('%s:' %ifacename + ' running sub-operations')
- self.run_iface_subops(ifupdownobj, ifaceobj, op)
- except Exception, e:
- self.logger.error('%s:' %ifacename +
- ' error running sub operations (%s)' %str(e))
-
- self.release_token(ifacename)
-
-
- def run_iface_list_parallel(self, parent, ifupdownobj, ifacenames, op):
- """ Runs interface list in parallel """
-
- running_threads = OrderedDict()
- err = 0
+ ifaceobj.set_state_n_status(ifaceState.NEW,
+ ifaceStatus.ERROR)
+ raise
+ if order == ifaceSchedulerFlags.POSTORDER:
+ cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
+
+ @classmethod
+ def run_iface_list(cls, ifupdownobj, ifacenames,
+ ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
+ followdependents=True, continueonfailure=True):
+ """ Runs interface list """
for ifacename in ifacenames:
try:
- self.accquire_token(parent)
- running_threads[ifacename] = Thread(None,
- self.run_iface_parallel, ifacename,
- args=(ifupdownobj, ifacename, op))
- running_threads[ifacename].start()
- self.release_token(parent)
+ cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
+ order, followdependents)
except Exception, e:
- self.release_token(parent)
- if (ifupdownobj.ignore_error(str(e)) == True):
+ 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)
-
+ if (ifupdownobj.ignore_error(str(e))):
+ pass
+ else:
+ raise Exception('%s : (%s)' %(ifacename, str(e)))
- self.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
+ @classmethod
+ 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 """
- return err
+ # Each ifacename can have a list of iface objects
+ ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
+ if not ifaceobjs:
+ raise Exception('%s: not found' %ifacename)
- def run_iface_graphs_parallel(self, parent, ifupdownobj, ifacenames, op):
- """ Runs iface graphs in parallel """
+ 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 upperifaces
+ ulist = ifaceobj.upperifaces
+ if ulist:
+ ifupdownobj.logger.debug('%s: found upperifaces %s'
+ %(ifacename, str(ulist)))
+ try:
+ cls.run_iface_list_upper(ifupdownobj, ulist, ops,
+ ifacename,
+ followdependents,
+ continueonfailure=True)
+ except Exception, e:
+ if (ifupdownobj.ignore_error(str(e))):
+ pass
+ else:
+ raise
- running_threads = OrderedDict()
- err = 0
+ @classmethod
+ 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:
- self.accquire_graph_token(parent)
- running_threads[ifacename] = Thread(None,
- self.run_iface_parallel, ifacename,
- args=(ifupdownobj, ifacename, op))
- running_threads[ifacename].start()
- self.release_graph_token(parent)
+ cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
+ followdependents, skip_root)
except Exception, e:
- self.release_graph_token(parent)
- if (ifupdownobj.ignore_error(str(e)) == True):
+ 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)
-
- self.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 run_iface_dependency_graph_parallel(self, ifupdownobj, dependency_graph,
- operation):
- """ Runs iface dependeny graph in parallel.
+ if (ifupdownobj.ignore_error(str(e))):
+ pass
+ else:
+ raise Exception('%s : (%s)' %(ifacename, str(e)))
+
+ @classmethod
+ 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 determine roots
+ of the graphs in the dependency_graph
"""
- self.logger.debug('running dependency graph in parallel ..')
+ if not ifupdownobj.ALL or not followdependents or len(ifacenames) == 1:
+ # If there is any interface that does exist, maybe it is a
+ # logical interface and we have to followupperifaces
+ followupperifaces = (True if
+ [i for i in ifacenames
+ if not ifupdownobj.link_exists(i)]
+ else False)
+ cls.run_iface_list(ifupdownobj, ifacenames, 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
+ return
+
+ if ifupdownobj.config.get('skip_ifacesort', '0') == '1':
+ # This is a backdoor to skip sorting of interfaces, if required
+ cls.run_iface_list(ifupdownobj, ifacenames, ops,
+ parent=None,order=order,
+ followdependents=followdependents)
+ return
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)
-
- self.logger.debug('graph roots (interfaces that dont have dependents):' +
- ' %s' %str(run_queue))
-
- self.init_tokens(ifupdownobj.get_njobs())
-
- return self.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)
-
+ # 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)
+ sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph,
+ indegrees)
+ ifupdownobj.logger.debug('sorted ifacenames %s : '
+ %str(sorted_ifacenames))
+
+ # From the sorted list, 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))
+ cls.run_iface_list(ifupdownobj, run_queue, ops,
+ parent=None,order=order,
+ followdependents=followdependents)