diff --git a/pkg/ifupdownmain.py b/pkg/ifupdownmain.py index 56107e2..9eff533 100644 --- a/pkg/ifupdownmain.py +++ b/pkg/ifupdownmain.py @@ -35,6 +35,7 @@ class ifupdownMain(ifupdownBase): # Flags WITH_DEPENDS = False ALL = False + IFACE_CLASS = False COMPAT_EXEC_SCRIPTS = False STATEMANAGER_ENABLE = True STATEMANAGER_UPDATE = True @@ -625,6 +626,8 @@ class ifupdownMain(ifupdownBase): excludepats=None, printdependency=None, syntaxcheck=False): """ up an interface """ + if allow_classes: + self.IFACE_CLASS = True if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False if auto: self.ALL = True @@ -670,6 +673,8 @@ class ifupdownMain(ifupdownBase): excludepats=None, printdependency=None, usecurrentconfig=False): """ down an interface """ + if allow_classes: + self.IFACE_CLASS = True if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False if auto: self.ALL = True @@ -726,9 +731,10 @@ class ifupdownMain(ifupdownBase): format='native'): """ query an interface """ + if allow_classes: + self.IFACE_CLASS = True if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate': return self.statemanager.dump_pretty(ifacenames) - self.STATEMANAGER_UPDATE = False if auto: self.logger.debug('setting flag ALL') @@ -790,7 +796,6 @@ class ifupdownMain(ifupdownBase): def reload(self, upops, downops, auto=False, allow=None, ifacenames=None, excludepats=None, usecurrentconfig=False): """ reload interface config """ - allow_classes = [] new_ifaceobjdict = {} diff --git a/pkg/scheduler.py b/pkg/scheduler.py index b0eaa0c..4ab7636 100644 --- a/pkg/scheduler.py +++ b/pkg/scheduler.py @@ -307,6 +307,29 @@ class ifaceScheduler(): else: raise Exception('%s : (%s)' %(ifacename, str(e))) + @classmethod + 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 sched_ifaces(cls, ifupdownobj, ifacenames, ops, dependency_graph=None, indegrees=None, @@ -322,64 +345,81 @@ class ifaceScheduler(): 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 + indegrees : indegree array if present is used to topologically sort + the graphs in the dependency_graph """ + # + # 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 = [] + 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 or not followdependents or len(ifacenames) == 1: + if not ifupdownobj.ALL: # If there is any interface that does exist, maybe it is a - # logical interface and we have to followupperifaces + # 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) - 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 = [] - # 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)) - if run_queue: - cls.run_iface_list(ifupdownobj, run_queue, ops, - parent=None,order=order, - followdependents=followdependents) + 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: - cls.run_iface_list(ifupdownobj, ifacenames, ops, - parent=None,order=order, - followdependents=followdependents) + # 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 diff --git a/sbin/ifupdown b/sbin/ifupdown index 43d168a..09038ec 100755 --- a/sbin/ifupdown +++ b/sbin/ifupdown @@ -338,12 +338,16 @@ def validate_args(op, args): # return True if op == 'query' and args.syntaxhelp: return True - if not args.iflist and not args.all: + if not args.iflist and not args.all and not args.CLASS: print '\'-a\' option or interface list are required' return False if args.iflist and args.all: print '\'-a\' option and interface list are mutually exclusive' return False + if args.CLASS and (args.all or args.iflist): + print ('\'--allow\' option is mutually exclusive ' + + 'with interface list and \'-a\'') + return False return True def read_config():