1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

execute 'up' on upper devices if ifup is called with --with-depends

Ticket: CM-1438
Reviewed By: review pending
Testing Done: Tested ifup/ifdown

Before this patch, `ifup --with-depends <iface>` only brought up
lowerdevices. Because those were enough for iface to function.

And if ifaces above it (upperdevices) needed fixing, user could just
execute `ifup --with-depends <ifaceupper>`.

But in a recent, bond under a bridge bug in 2.0, got me thinking that
its probably better to up the upperdevices which might be impacted as
well. and this patch does just that.

The patch includes changes to make ifupdown generate dependency
information for all interfaces even if the user requested to operate
on a single interface. This is to get a full view of the interfaces file.
This might add some overhead. Should not change anything during boot.
Still looking at ways to optimize.
This commit is contained in:
roopa
2014-03-18 16:38:00 -07:00
parent dab8d81ec7
commit c798b0f4aa
5 changed files with 127 additions and 120 deletions

View File

@@ -53,51 +53,6 @@ class graph():
return S return S
@classmethod
def topological_sort_graph(cls, dependency_graph, indegrees, rootifname):
S = []
Q = deque()
Q.append(rootifname)
while len(Q):
# initialize queue
x = Q.popleft()
# Get dependents of x
dlist = dependency_graph.get(x)
if not dlist:
S.append(x)
continue
for y in dlist:
indegrees[y] = indegrees.get(y) - 1
if indegrees.get(y) == 0:
Q.append(y)
S.append(x)
return S
@classmethod
def topological_sort_graphs(cls, dependency_graphs, indegrees):
""" Sorts graph one at a time merges all the sorted graph
lists and returns a combined list
"""
sorted_graphs_list = []
for ifname,indegree in indegrees.items():
if indegree == 0:
sorted_graphs_list += cls.topological_sort_graph(
dependency_graphs, indegrees, ifname)
# If some indegrees are non zero, we have a cycle
for ifname,indegree in indegrees.items():
if indegree != 0:
raise Exception('cycle found involving iface %s' %ifname +
' (indegree %d)' %indegree)
return sorted_graphs_list
@classmethod @classmethod
def generate_dots(cls, dependency_graph, indegrees): def generate_dots(cls, dependency_graph, indegrees):
gvgraph = GvGen() gvgraph = GvGen()

View File

@@ -382,6 +382,7 @@ class iface():
del odict['state'] del odict['state']
del odict['status'] del odict['status']
del odict['lowerifaces'] del odict['lowerifaces']
del odict['upperifaces']
del odict['refcnt'] del odict['refcnt']
del odict['config_status'] del odict['config_status']
del odict['flags'] del odict['flags']
@@ -399,6 +400,7 @@ class iface():
self.refcnt = 0 self.refcnt = 0
self.flags = 0 self.flags = 0
self.lowerifaces = None self.lowerifaces = None
self.upperifaces = None
self.linkstate = None self.linkstate = None
self.env = None self.env = None
self.priv_flags = 0 self.priv_flags = 0

View File

@@ -27,7 +27,6 @@ class ifupdownMain(ifupdownBase):
# Flags # Flags
WITH_DEPENDS = False WITH_DEPENDS = False
ALL = False ALL = False
STATE_CHECK = False
COMPAT_EXEC_SCRIPTS = False COMPAT_EXEC_SCRIPTS = False
STATEMANAGER_ENABLE = True STATEMANAGER_ENABLE = True
STATEMANAGER_UPDATE = True STATEMANAGER_UPDATE = True
@@ -219,6 +218,9 @@ class ifupdownMain(ifupdownBase):
return ifaceobjs[0] return ifaceobjs[0]
return None return None
def get_ifacenames(self):
return self.ifaceobjdict.keys()
def get_iface_obj_last(self, ifacename): def get_iface_obj_last(self, ifacename):
return self.ifaceobjdict.get(ifacename)[-1] return self.ifaceobjdict.get(ifacename)[-1]
@@ -368,11 +370,12 @@ class ifupdownMain(ifupdownBase):
break break
return dlist return dlist
def populate_dependency_info(self, ifacenames, ops): def populate_dependency_info(self, ops, ifacenames=None):
""" recursive function to generate iface dependency info """ """ recursive function to generate iface dependency info """
if not ifacenames: if not ifacenames:
ifacenames = self.ifaceobjdict.keys() ifacenames = self.ifaceobjdict.keys()
self.logger.debug('populating dependency info for %s' %str(ifacenames)) self.logger.debug('populating dependency info for %s' %str(ifacenames))
iqueue = deque(ifacenames) iqueue = deque(ifacenames)
while iqueue: while iqueue:
@@ -549,49 +552,26 @@ class ifupdownMain(ifupdownBase):
iface_objs.append(iface_obj) iface_objs.append(iface_obj)
return iface_objs return iface_objs
def run_without_dependents(self, ops, ifacenames):
""" Run interface list without their dependents """
if not ifacenames:
raise ifupdownInvalidValue('no interfaces found')
self.logger.debug('run_without_dependents for ops %s for %s'
%(str(ops), str(ifacenames)))
ifaceScheduler.run_iface_list(self, ifacenames, ops, parent=None,
order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0]
else ifaceSchedulerFlags.POSTORDER,
followdependents=False)
def _pretty_print_ordered_dict(self, argdict): def _pretty_print_ordered_dict(self, argdict):
for k, vlist in argdict.items(): for k, vlist in argdict.items():
self.logger.info('%s : %s' %(k, str(vlist))) self.logger.info('%s : %s' %(k, str(vlist)))
def run_with_dependents(self, ops, ifacenames): def sched_ifaces(self, ifacenames, ops):
ret = 0 self.logger.debug('scheduling \'%s\' for %s'
self.logger.debug('running \'%s\' with dependents for %s'
%(str(ops), str(ifacenames))) %(str(ops), str(ifacenames)))
if not ifacenames:
ifacenames = self.ifaceobjdict.keys()
self.logger.info('dependency graph:') self.logger.info('dependency graph:')
self._pretty_print_ordered_dict(self.dependency_graph) self._pretty_print_ordered_dict(self.dependency_graph)
if self.njobs > 1: return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
ret = ifaceScheduler.run_iface_dependency_graph_parallel(self, dependency_graph=self.dependency_graph,
self.dependency_graph, ops)
else:
ret = ifaceScheduler.run_iface_dependency_graphs(self,
self.dependency_graph, ops,
order=ifaceSchedulerFlags.INORDER order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0] if 'down' in ops[0]
else ifaceSchedulerFlags.POSTORDER) else ifaceSchedulerFlags.POSTORDER,
return ret followdependents=True if self.WITH_DEPENDS else False)
def print_dependency(self, ifacenames, format): def print_dependency(self, ifacenames, format):
if ifacenames is None: if not ifacenames:
ifacenames = self.ifaceobjdict.keys() ifacenames = self.ifaceobjdict.keys()
if format == 'list': if format == 'list':
@@ -706,16 +686,14 @@ class ifupdownMain(ifupdownBase):
if not filtered_ifacenames: if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists') raise Exception('no ifaces found matching given allow lists')
self.populate_dependency_info(filtered_ifacenames, ops)
if printdependency: if printdependency:
self.populate_dependency_info(ops, filtered_ifacenames)
self.print_dependency(filtered_ifacenames, printdependency) self.print_dependency(filtered_ifacenames, printdependency)
return return
if self.WITH_DEPENDS:
self.run_with_dependents(ops, filtered_ifacenames)
else: else:
self.run_without_dependents(ops, filtered_ifacenames) self.populate_dependency_info(ops)
self.sched_ifaces(filtered_ifacenames, ops)
if self.DRYRUN and self.ADDONS_ENABLE: if self.DRYRUN and self.ADDONS_ENABLE:
return return
@@ -758,16 +736,14 @@ class ifupdownMain(ifupdownBase):
if not filtered_ifacenames: if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists') raise Exception('no ifaces found matching given allow lists')
self.populate_dependency_info(filtered_ifacenames, ops)
if printdependency: if printdependency:
self.populate_dependency_info(ops, filtered_ifacenames)
self.print_dependency(filtered_ifacenames, printdependency) self.print_dependency(filtered_ifacenames, printdependency)
return return
if self.WITH_DEPENDS:
self.run_with_dependents(ops, filtered_ifacenames)
else: else:
self.run_without_dependents(ops, filtered_ifacenames) self.populate_dependency_info(ops)
self.sched_ifaces(filtered_ifacenames, ops)
if self.DRYRUN and self.ADDONS_ENABLE: if self.DRYRUN and self.ADDONS_ENABLE:
return return
@@ -817,20 +793,19 @@ class ifupdownMain(ifupdownBase):
raise Exception('no ifaces found matching ' + raise Exception('no ifaces found matching ' +
'given allow lists') 'given allow lists')
self.populate_dependency_info(filtered_ifacenames, ops)
if ops[0] == 'query-dependency' and printdependency: if ops[0] == 'query-dependency' and printdependency:
self.populate_dependency_info(ops, filtered_ifacenames)
self.print_dependency(filtered_ifacenames, printdependency) self.print_dependency(filtered_ifacenames, printdependency)
return return
else:
self.populate_dependency_info(ops)
if ops[0] == 'query': if ops[0] == 'query':
return self.print_ifaceobjs_pretty(filtered_ifacenames, format) return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
elif ops[0] == 'query-raw': elif ops[0] == 'query-raw':
return self.print_ifaceobjs_raw(filtered_ifacenames) return self.print_ifaceobjs_raw(filtered_ifacenames)
if self.WITH_DEPENDS: self.sched_ifaces(filtered_ifacenames, ops)
self.run_with_dependents(ops, filtered_ifacenames)
else:
self.run_without_dependents(ops, filtered_ifacenames)
if ops[0] == 'query-checkcurr': if ops[0] == 'query-checkcurr':
ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format) ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
@@ -858,7 +833,7 @@ class ifupdownMain(ifupdownBase):
raise raise
# generate dependency graph of interfaces # generate dependency graph of interfaces
self.populate_dependency_info(ifacenames, upops) self.populate_dependency_info(upops)
# Save a copy of new iface objects and dependency_graph # Save a copy of new iface objects and dependency_graph
new_ifaceobjdict = dict(self.get_ifaceobjdict()) new_ifaceobjdict = dict(self.get_ifaceobjdict())
@@ -918,8 +893,8 @@ class ifupdownMain(ifupdownBase):
# reinitialize dependency graph # reinitialize dependency graph
self.dependency_graph = OrderedDict({}) self.dependency_graph = OrderedDict({})
# Generate dependency info for old config # Generate dependency info for old config
self.populate_dependency_info(ifacedownlist, downops) self.populate_dependency_info(downops)
self.run_with_dependents(downops, ifacedownlist) self.sched_ifaces(ifacedownlist, downops)
else: else:
self.logger.debug('no interfaces to down ..') self.logger.debug('no interfaces to down ..')
@@ -934,12 +909,11 @@ class ifupdownMain(ifupdownBase):
excludepats, i)] excludepats, i)]
self.logger.info('Executing up on interfaces: %s' self.logger.info('Executing up on interfaces: %s'
%str(filtered_ifacenames)) %str(filtered_ifacenames))
if self.WITH_DEPENDS:
self.run_with_dependents(upops, filtered_ifacenames) self.sched_ifaces(filtered_ifacenames, upops)
else:
self.run_without_dependents(upops, filtered_ifacenames)
if self.DRYRUN: if self.DRYRUN:
return return
self.save_state() self.save_state()
def dump(self): def dump(self):
@@ -947,8 +921,8 @@ class ifupdownMain(ifupdownBase):
print 'ifupdown object dump' print 'ifupdown object dump'
print self.pp.pprint(self.modules) print self.pp.pprint(self.modules)
print self.pp.pprint(self.ifaces) print self.pp.pprint(self.ifaceobjdict)
self.state_manager.dump() #self.state_manager.dump()
def print_state(self, ifacenames=None): def print_state(self, ifacenames=None):
self.statemanager.dump(ifacenames) self.statemanager.dump(ifacenames)

View File

@@ -21,8 +21,8 @@ from threading import *
from ifupdownbase import * from ifupdownbase import *
class ifaceSchedulerFlags(): class ifaceSchedulerFlags():
INORDER = 1 INORDER = 0x1
POSTORDER = 2 POSTORDER = 0x2
class ifaceScheduler(): class ifaceScheduler():
""" scheduler functions to schedule configuration of interfaces. """ scheduler functions to schedule configuration of interfaces.
@@ -31,6 +31,8 @@ class ifaceScheduler():
or dependency graph format. or dependency graph format.
""" """
_STATE_CHECK = True
token_pool = None token_pool = None
@classmethod @classmethod
@@ -38,8 +40,9 @@ class ifaceScheduler():
""" Runs sub operation on an interface """ """ Runs sub operation on an interface """
ifacename = ifaceobj.get_name() ifacename = ifaceobj.get_name()
if (ifaceobj.get_state() >= ifaceState.from_str(op) and if (cls._STATE_CHECK and
ifaceobj.get_status() == ifaceStatus.SUCCESS): (ifaceobj.get_state() >= ifaceState.from_str(op)) and
(ifaceobj.get_status() == ifaceStatus.SUCCESS)):
ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op)) ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
return return
@@ -111,11 +114,14 @@ class ifaceScheduler():
@classmethod @classmethod
def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent): def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent, followdependents=False):
""" Check if conflicting upper ifaces are around and warn if required """ Check if conflicting upper ifaces are around and warn if required
Returns False if this interface needs to be skipped, else return True """ Returns False if this interface needs to be skipped, else return True """
if 'up' in ops[0] and followdependents:
return True
ifacename = ifaceobj.get_name() ifacename = ifaceobj.get_name()
# Deal with upperdevs first # Deal with upperdevs first
ulist = ifaceobj.get_upperifaces() ulist = ifaceobj.get_upperifaces()
@@ -156,7 +162,8 @@ class ifaceScheduler():
raise Exception('%s: not found' %ifacename) raise Exception('%s: not found' %ifacename)
for ifaceobj in ifaceobjs: for ifaceobj in ifaceobjs:
if not cls._check_upperifaces(ifupdownobj, ifaceobj, ops, parent): if not cls._check_upperifaces(ifupdownobj, ifaceobj, ops, parent,
followdependents):
return return
if order == ifaceSchedulerFlags.INORDER: if order == ifaceSchedulerFlags.INORDER:
# If inorder, run the iface first and then its dependents # If inorder, run the iface first and then its dependents
@@ -221,8 +228,62 @@ class ifaceScheduler():
%(ifacename, str(e))) %(ifacename, str(e)))
@classmethod @classmethod
def run_iface_dependency_graphs(cls, ifupdownobj, def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
dependency_graph, ops, indegrees=None, followdependents=True, skip_root=False):
""" 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)
for ifaceobj in ifaceobjs:
if not skip_root:
# run the iface first and then its upperifaces
cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
# Run upperifaces
ulist = ifaceobj.get_upperifaces()
if ulist:
ifupdownobj.logger.debug('%s:' %ifacename +
' found upperifaces: %s' %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
@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:
cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
followdependents, skip_root)
except Exception, 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:
if (ifupdownobj.ignore_error(str(e))):
pass
else:
raise Exception('error running iface %s (%s)'
%(ifacename, str(e)))
@classmethod
def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
dependency_graph=None, indegrees=None,
order=ifaceSchedulerFlags.POSTORDER, order=ifaceSchedulerFlags.POSTORDER,
followdependents=True): followdependents=True):
""" Runs iface dependeny graph by visiting all the nodes """ Runs iface dependeny graph by visiting all the nodes
@@ -238,27 +299,42 @@ class ifaceScheduler():
indegrees : indegree array if present is used to determine roots indegrees : indegree array if present is used to determine roots
of the graphs in the dependency_graph of the graphs in the dependency_graph
""" """
if not ifupdownobj.ALL or not followdependents or len(ifacenames) == 1:
cls.run_iface_list(ifupdownobj, ifacenames, ops,
parent=None,order=order,
followdependents=followdependents)
if not ifupdownobj.ALL and followdependents 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
run_queue = [] run_queue = []
# Get a sorted list of all interfaces
if not indegrees: if not indegrees:
indegrees = OrderedDict() indegrees = OrderedDict()
for ifacename in dependency_graph.keys(): for ifacename in dependency_graph.keys():
indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph, sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph,
dict(indegrees)) dict(indegrees))
ifupdownobj.logger.debug('sorted ifacenames %s : ' ifupdownobj.logger.debug('sorted ifacenames %s : '
%str(sorted_ifacenames)) %str(sorted_ifacenames))
# Build a list of ifaces that dont have any dependencies # From the sorted list, pick interfaces that user asked
for ifacename in sorted_ifacenames: # and those that dont have any dependents first
if not indegrees.get(ifacename): [run_queue.append(ifacename)
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 ' ifupdownobj.logger.debug('graph roots (interfaces that dont have '
'dependents):' + ' %s' %str(run_queue)) 'dependents):' + ' %s' %str(run_queue))
cls.run_iface_list(ifupdownobj, run_queue, ops,
return cls.run_iface_list(ifupdownobj, run_queue, ops,
parent=None,order=order, parent=None,order=order,
followdependents=followdependents) followdependents=followdependents)

View File

@@ -78,9 +78,6 @@ def run_query(args):
if args.checkcurr: if args.checkcurr:
qop='query-checkcurr' qop='query-checkcurr'
elif args.running: elif args.running:
if not iflist:
iflist = [i for i in os.listdir('/sys/class/net/')
if os.path.isdir('/sys/class/net/%s' %i)]
qop='query-running' qop='query-running'
elif args.raw: elif args.raw:
qop='query-raw' qop='query-raw'
@@ -96,6 +93,9 @@ def run_query(args):
args.perfmode or args.syntaxhelp or args.perfmode or args.syntaxhelp or
(qop != 'query-checkcurr' and (qop != 'query-checkcurr' and
qop != 'query-running')) else True) qop != 'query-running')) else True)
if not iflist and qop == 'query-running':
iflist = [i for i in os.listdir('/sys/class/net/')
if os.path.isdir('/sys/class/net/%s' %i)]
logger.debug('creating ifupdown object ..') logger.debug('creating ifupdown object ..')
ifupdown_handle = ifupdownMain(withdepends=args.withdepends, ifupdown_handle = ifupdownMain(withdepends=args.withdepends,
perfmode=args.perfmode, perfmode=args.perfmode,