from graph import *
from sets import Set
-class ifupdownMain():
+class ifupdownMain(ifupdownBase):
# Flags
WITH_DEPENDS = False
# {'<ifacename>' : <ifaceobject>}
ifaceobjcurrdict = OrderedDict()
- # Dictionary representing operation, sub operation and modules
- # for every sub operation
- operations = OrderedDict([('pre-up', []),
+ # Dictionary representing operation and modules
+ # for every operation
+ module_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('query-checkcurr', []),
('post-down' , [])])
# For old style /etc/network/ bash scripts
- operations_compat = OrderedDict([('pre-up', []),
+ script_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('pre-down', []),
('down' , []),
('post-down' , [])])
+ # Handlers for ops that ifupdown2 owns
+ def run_up(self, ifaceobj):
+ ifacename = ifaceobj.get_name()
+ if self.link_exists(ifacename):
+ self.link_up(ifacename)
+
+ def run_down(self, ifaceobj):
+ ifacename = ifaceobj.get_name()
+ if self.link_exists(ifacename):
+ self.link_down(ifacename)
+
+ ops_handlers = OrderedDict([('up', run_up),
+ ('down', run_down)])
def __init__(self, force=False, dryrun=False, nowait=False,
perfmode=False, withdepends=False, njobs=1,
def get_subops(self, op):
""" Returns sub-operation list """
- return self.operations.get(op).keys()
+ return self.module_ops.get(op).keys()
def compat_conv_op_to_mode(self, op):
""" Returns old op name to work with existing scripts """
# Get dependents for interface by querying respective modules
for op in ops:
- for mname in self.operations.get(op):
+ for mname in self.module_ops.get(op):
module = self.modules.get(mname)
if op == 'query-running':
if (hasattr(module,
litems = l.rstrip(' \n').split(',')
operation = litems[0]
mname = litems[1]
- self.operations[operation].append(mname)
+ self.module_ops[operation].append(mname)
def load_addon_modules(self, modules_dir):
""" load python modules from modules_dir
if not modules_dir in sys.path:
sys.path.append(modules_dir)
try:
- for op, mlist in self.operations.items():
+ for op, mlist in self.module_ops.items():
for mname in mlist:
if self.modules.get(mname) is not None:
continue
raise
# Assign all modules to query operations
- self.operations['query-checkcurr'] = self.modules.keys()
- self.operations['query-running'] = self.modules.keys()
- self.operations['query-dependency'] = self.modules.keys()
- self.operations['query'] = self.modules.keys()
- self.operations['query-raw'] = self.modules.keys()
+ self.module_ops['query-checkcurr'] = self.modules.keys()
+ self.module_ops['query-running'] = self.modules.keys()
+ self.module_ops['query-dependency'] = self.modules.keys()
+ self.module_ops['query'] = self.modules.keys()
+ self.module_ops['query-raw'] = self.modules.keys()
def modules_help(self):
indent = ' '
"""
self.logger.info('looking for user scripts under %s' %modules_dir)
- for op, mlist in self.operations_compat.items():
+ for op, mlist in self.script_ops.items():
msubdir = modules_dir + '/if-%s.d' %op
self.logger.info('loading scripts under %s ...' %msubdir)
try:
for module in module_list:
if self.modules.get(module) is not None:
continue
- self.operations_compat[op].append(
+ self.script_ops[op].append(
msubdir + '/' + module)
except:
# continue reading
self.logger.debug('run_without_dependents for ops %s for %s'
%(str(ops), str(ifacenames)))
- ifaceSched = ifaceScheduler(force=self.FORCE)
- ifaceSched.run_iface_list(self, ifacenames, ops, parent=None,
+ ifaceScheduler.run_iface_list(self, ifacenames, ops, parent=None,
order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0]
else ifaceSchedulerFlags.POSTORDER,
self.logger.debug('running \'%s\' with dependents for %s'
%(str(ops), str(ifacenames)))
- ifaceSched = ifaceScheduler()
if ifacenames is None:
ifacenames = self.ifaceobjdict.keys()
self.logger.info(self.pp.pformat(self.dependency_graph))
if self.njobs > 1:
- ret = ifaceSched.run_iface_dependency_graph_parallel(self,
+ ret = ifaceScheduler.run_iface_dependency_graph_parallel(self,
self.dependency_graph, ops)
else:
- ret = ifaceSched.run_iface_dependency_graphs(self,
+ ret = ifaceScheduler.run_iface_dependency_graphs(self,
self.dependency_graph, ops,
order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0]
def print_ifaceobjs_pretty(self, ifacenames, format='native'):
for i in ifacenames:
for ifaceobj in self.get_iface_objs(i):
- if (self.is_ifaceobj_builtin(ifaceobj) or
- not ifaceobj.is_config_present()):
+ if (self.is_ifaceobj_noconfig(ifaceobj)):
continue
if format == 'json':
ifaceobj.dump_json()
elif ifaceobj.get_status() == ifaceStatus.ERROR:
ret = 1
- if (self.is_ifaceobj_builtin(ifaceobj) or
- ifaceobj.is_config_present() == False):
+ if (self.is_ifaceobj_noconfig(ifaceobj)):
continue
if format == 'json':
if dlist is None or len(dlist) == 0: continue
self.print_ifaceobjsrunning_pretty(dlist, format)
return
-
- def print_ifaceobjs_saved_state_pretty(self, ifacenames):
- self.statemanager.print_state_pretty(ifacenames, self.logger)
-
- def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames):
- self.statemanager.print_state_detailed_pretty(ifacenames, self.logger)
INORDER = 1
POSTORDER = 2
-class ifaceScheduler(ifupdownBase):
- """ scheduler to schedule configuration of interfaces.
+class ifaceScheduler():
+ """ scheduler functions to schedule configuration of interfaces.
supports scheduling of interfaces serially in plain interface list
or dependency graph format.
"""
+ token_pool = None
- def __init__(self, force=False):
- self.logger = logging.getLogger('ifupdown.' +
- self.__class__.__name__)
- self.FORCE = force
-
- def run_iface_op(self, ifupdownobj, ifaceobj, op, cenv):
+ @classmethod
+ def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv):
""" Runs sub operation on an interface """
ifacename = ifaceobj.get_name()
if (ifaceobj.get_state() >= ifaceState.from_str(op) and
ifaceobj.get_status() == ifaceStatus.SUCCESS):
- self.logger.debug('%s: already in state %s' %(ifacename, op))
+ ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
return
- for mname in ifupdownobj.operations.get(op):
+ # 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)
+
+ for mname in ifupdownobj.module_ops.get(op):
m = ifupdownobj.modules.get(mname)
err = 0
try:
if hasattr(m, 'run'):
- self.logger.debug('%s: %s : running module %s'
+ ifupdownobj.logger.debug('%s: %s : running module %s'
%(ifacename, op, mname))
if op == 'query-checkcurr':
# Dont check curr if the interface object was
m.run(ifaceobj, op)
except Exception, e:
err = 1
- self.log_error(str(e))
+ ifupdownobj.log_error(str(e))
finally:
if err == 1:
ifupdownobj.set_iface_state(ifaceobj,
ifaceStatus.SUCCESS)
# execute /etc/network/ scripts
- mlist = ifupdownobj.operations_compat.get(op)
+ mlist = ifupdownobj.script_ops.get(op)
if not mlist:
return
for mname in mlist:
- self.logger.debug('%s: %s : running script %s'
+ ifupdownobj.logger.debug('%s: %s : running script %s'
%(ifacename, op, mname))
try:
- self.exec_command(mname, cmdenv=cenv)
+ ifupdownobj.exec_command(mname, cmdenv=cenv)
except Exception, e:
err = 1
- self.log_error(str(e))
+ ifupdownobj.log_error(str(e))
-
- def run_iface_ops(self, ifupdownobj, ifaceobj, ops):
+ @classmethod
+ def run_iface_ops(cls, ifupdownobj, ifaceobj, ops):
""" Runs all sub operations on an interface """
# For backward compatibility execute scripts with
cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0])
# Each sub operation has a module list
- [self.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
+ [cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
for op in ops]
- def run_iface_graph(self, ifupdownobj, ifacename, ops, parent=None,
+ @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 """
# minor optimization. If operation is 'down', proceed only
# if interface exists in the system
- if 'down' in ops[0] and not self.link_exists(ifacename):
- self.logger.info('%s: does not exist' %ifacename)
+ 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
# Deal with upperdevs first
ulist = ifaceobj.get_upperifaces()
if ulist:
- self.logger.debug('%s: parent = %s, ulist = %s'
- %(ifacename, parent, ulist))
tmpulist = ([u for u in ulist if u != parent] if parent
else ulist)
if tmpulist:
- self.logger.debug('%s: parent = %s, tmpulist = %s'
- %(ifacename, parent, 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 self.link_exists(u):
+ if ifupdownobj.link_exists(u):
if not ifupdownobj.ALL:
- self.logger.warn('%s: skip interface '
- 'down upperiface %s still around'
- %(ifacename, u))
+ 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 self.link_exists(u):
- self.logger.warn('%s: upper iface %s does not'
- ' exist' %(ifacename, u))
+ 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
- self.run_iface_ops(ifupdownobj, ifaceobj, ops)
+ cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
# Run lowerifaces or dependents
dlist = ifaceobj.get_lowerifaces()
if dlist:
- self.logger.info('%s:' %ifacename +
+ ifupdownobj.logger.info('%s:' %ifacename +
' found dependents: %s' %str(dlist))
try:
if not followdependents:
new_dlist = [d for d in dlist
if ifupdownobj.is_iface_noconfig(d)]
if new_dlist:
- self.run_iface_list(ifupdownobj, new_dlist, ops,
+ cls.run_iface_list(ifupdownobj, new_dlist, ops,
ifacename, order,
followdependents,
continueonfailure=False)
else:
- self.run_iface_list(ifupdownobj, dlist, ops,
+ cls.run_iface_list(ifupdownobj, dlist, ops,
ifacename, order,
followdependents,
continueonfailure=False)
except Exception, e:
- if (self.ignore_error(str(e))):
+ if (ifupdownobj.ignore_error(str(e))):
pass
else:
# Dont bring the iface up if children did not come up
ifaceobj.set_status(ifaceStatus.ERROR)
raise
if order == ifaceSchedulerFlags.POSTORDER:
- self.run_iface_ops(ifupdownobj, ifaceobj, ops)
-
+ cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
- def run_iface_list(self, ifupdownobj, ifacenames,
+ @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.run_iface_graph(ifupdownobj, ifacename, ops, parent,
+ cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
order, followdependents)
except Exception, e:
if continueonfailure:
- self.logger.error('%s : %s' %(ifacename, str(e)))
+ ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
pass
else:
- if (self.ignore_error(str(e))):
+ if (ifupdownobj.ignore_error(str(e))):
pass
else:
raise Exception('error running iface %s (%s)'
%(ifacename, str(e)))
- def run_iface_dependency_graphs(self, ifupdownobj,
+ @classmethod
+ def run_iface_dependency_graphs(cls, ifupdownobj,
dependency_graph, ops, indegrees=None,
order=ifaceSchedulerFlags.POSTORDER,
followdependents=True):
sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph,
dict(indegrees))
- self.logger.debug('sorted ifacenames %s : ' %str(sorted_ifacenames))
+ 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)
- self.logger.info('graph roots (interfaces that dont have '
- 'dependents):' + ' %s' %str(run_queue))
+ ifupdownobj.logger.info('graph roots (interfaces that dont have '
+ 'dependents):' + ' %s' %str(run_queue))
- return self.run_iface_list(ifupdownobj, run_queue, ops,
- parent=None,order=order,
- followdependents=followdependents)
+ return cls.run_iface_list(ifupdownobj, run_queue, ops,
+ parent=None,order=order,
+ followdependents=followdependents)
-
- def run_iface(self, ifupdownobj, ifacename, ops):
+ @classmethod
+ def run_iface(cls, ifupdownobj, ifacename, ops):
""" Runs operation on an interface """
ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
for i in ifaceobjs:
- self.run_iface_ops(ifupdownobj, i, ops)
+ cls.run_iface_ops(ifupdownobj, i, ops)
- def run_iface_list_op(self, ifupdownobj, ifacenames, op,
- sorted_by_dependency=False):
+ @classmethod
+ def run_iface_list_op(cls, ifupdownobj, ifacenames, op,
+ sorted_by_dependency=False):
""" Runs interface list through sub operation handler. """
- self.logger.debug('running operation %s on all given interfaces'
- %op)
+ 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'):
ifaceobjs = ifupdownobj.get_iface_objs(ifacename)
for ifaceobj in ifaceobjs:
cenv = ifupdownobj.generate_running_env(ifaceobj, op)
- self.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
+ cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv)
except Exception, e:
- self.log_error(str(e))
+ ifupdownobj.log_error(str(e))
- def run_iface_list_ops(self, ifupdownobj, ifacenames, ops,
- sorted_by_dependency=False):
+ @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
ie operation 'pre-up' is run through the entire interface list before
'up'
"""
-
# Each sub operation has a module list
- [self.run_iface_list_op(ifupdownobj, ifacenames, op,
+ [cls.run_iface_list_op(ifupdownobj, ifacenames, op,
sorted_by_dependency) for op in ops]
- def run_iface_dependency_graphs_sorted(self, ifupdownobj,
- dependency_graphs,
- ops, indegrees=None,
- graphsortall=False):
+ @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:
for ifacename in dependency_graphs.keys():
indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
- if self.logger.isEnabledFor(logging.DEBUG):
- self.logger.debug('indegree array :')
- self.logger.debug(ifupdownobj.pp.pformat(indegrees))
+ ifupdownobj.logger.debug('indegree array :')
+ ifupdownobj.logger.debug(ifupdownobj.pp.pformat(indegrees))
try:
- self.logger.debug('calling topological sort on the graph ...')
+ ifupdownobj.logger.debug('calling topological sort on the graph ' +
+ '...')
if graphsortall:
sorted_ifacenames = graph.topological_sort_graphs_all(
dependency_graphs, indegrees)
except Exception:
raise
- self.logger.debug('sorted iface list = %s' %sorted_ifacenames)
- self.run_iface_list_ops(ifupdownobj, sorted_ifacenames, ops,
- sorted_by_dependency=True)
+ 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 """
- def init_tokens(self, count):
- self.token_pool = BoundedSemaphore(count)
- self.logger.debug('initialized bounded semaphore with %d' %count)
+ @classmethod
+ def init_tokens(cls, count):
+ cls.token_pool = BoundedSemaphore(count)
- def accquire_token(self, logprefix=''):
- self.token_pool.acquire()
- self.logger.debug('%s ' %logprefix + 'acquired token')
+ @classmethod
+ def accquire_token(cls, logprefix=''):
+ cls.token_pool.acquire()
- def release_token(self, logprefix=''):
- self.token_pool.release()
- self.logger.debug('%s ' %logprefix + 'release token')
+ @classmethod
+ def release_token(cls, logprefix=''):
+ cls.token_pool.release()
- def run_iface_parallel(self, ifupdownobj, ifacename, op):
+ @classmethod
+ def run_iface_parallel(cls, ifupdownobj, ifacename, op):
""" Configures interface in parallel.
Executes all its direct dependents in parallel
"""
- self.logger.debug('%s:' %ifacename + ' %s' %op)
- self.accquire_token(iface)
+ ifupdownobj.logger.debug('%s:' %ifacename + ' %s' %op)
+ cls.accquire_token(iface)
# 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)
+ ifupdownobj.logger.warning('%s: ' %ifacename + 'not found')
+ cls.release_token(ifacename)
return -1
for ifaceobj in ifaceobjs:
# Run dependents
dlist = ifaceobj.get_lowerifaces()
- if dlist is not None and len(dlist) > 0:
- self.logger.debug('%s:' %ifacename +
+ if dlist:
+ ifupdownobj.logger.debug('%s:' %ifacename +
' found dependents: %s' %str(dlist))
try:
- self.release_token(ifacename)
- self.run_iface_list_parallel(ifacename, ifupdownobj,
+ cls.release_token(ifacename)
+ cls.run_iface_list_parallel(ifacename, ifupdownobj,
dlist, op)
- self.accquire_token(ifacename)
+ cls.accquire_token(ifacename)
except Exception, e:
- if self.ignore_error(str(e)):
+ if ifupdownobj.ignore_error(str(e)):
pass
else:
# Dont bring the iface up if children did not come up
- self.logger.debug('%s:' %ifacename +
+ ifupdownobj.logger.debug('%s:' %ifacename +
' there was an error bringing %s' %op +
' dependents (%s)', str(e))
ifupdownobj.set_iface_state(ifaceobj,
# Run all sub operations sequentially
try:
- self.logger.debug('%s:' %ifacename + ' running sub-operations')
- self.run_iface_ops(ifupdownobj, ifaceobj, op)
+ ifupdownobj.logger.debug('%s:' %ifacename +
+ ' running sub-operations')
+ cls.run_iface_ops(ifupdownobj, ifaceobj, op)
except Exception, e:
- self.logger.error('%s:' %ifacename +
+ ifupdownobj.logger.error('%s:' %ifacename +
' error running sub operations (%s)' %str(e))
- self.release_token(ifacename)
+ cls.release_token(ifacename)
-
- def run_iface_list_parallel(self, parent, ifupdownobj, ifacenames, op):
+ @classmethod
+ def run_iface_list_parallel(cls, parent, ifupdownobj, ifacenames, op):
""" Runs interface list in parallel """
running_threads = OrderedDict()
for ifacename in ifacenames:
try:
- self.accquire_token(parent)
+ cls.accquire_token(parent)
running_threads[ifacename] = Thread(None,
- self.run_iface_parallel, ifacename,
+ cls.run_iface_parallel, ifacename,
args=(ifupdownobj, ifacename, op))
running_threads[ifacename].start()
- self.release_token(parent)
+ cls.release_token(parent)
except Exception, e:
- self.release_token(parent)
+ cls.release_token(parent)
if ifupdownobj.ignore_error(str(e)):
pass
else:
%ifacename)
- self.logger.debug('%s' %parent + 'waiting for all the threads ...')
+ 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:
return err
- def run_iface_graphs_parallel(self, parent, ifupdownobj, ifacenames, op):
+ @classmethod
+ def run_iface_graphs_parallel(cls, parent, ifupdownobj, ifacenames, op):
""" Runs iface graphs in parallel """
running_threads = OrderedDict()
for ifacename in ifacenames:
try:
- self.accquire_graph_token(parent)
+ cls.accquire_graph_token(parent)
running_threads[ifacename] = Thread(None,
- self.run_iface_parallel, ifacename,
+ cls.run_iface_parallel, ifacename,
args=(ifupdownobj, ifacename, op))
running_threads[ifacename].start()
- self.release_graph_token(parent)
+ cls.release_graph_token(parent)
except Exception, e:
- self.release_graph_token(parent)
+ cls.release_graph_token(parent)
if ifupdownobj.ignore_error(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():
+ 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 run_iface_dependency_graph_parallel(self, ifupdownobj, dependency_graph,
+ @classmethod
+ def run_iface_dependency_graph_parallel(cls, ifupdownobj, dependency_graph,
operation):
""" Runs iface dependeny graph in parallel.
"""
- self.logger.debug('running dependency graph in parallel ..')
-
+ ifupdownobj.logger.debug('running dependency graph in parallel ..')
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'
+ ifupdownobj.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,
+ cls.init_tokens(ifupdownobj.get_njobs())
+ return cls.run_iface_list_parallel('main', ifupdownobj, run_queue,
operation)
# OR