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

Fix bug during handling multiple iface sections for same interface

Ticket: CM-1438
Reviewed By:
Testing Done: Tested ifupdown2 sanity + multiple iface sections for an
interface

- This patch fixes a few shortcomings in the multiple iface sections
for same interface (partly because i was only covering
backward compatibility cases earlier)
- Since this is a very common configuration pattern, this patch cleans
  it up
- also restructures some code
- main change is:
    before:
        for iface in ifaces:
            for op in ops:
                run op on iface

    after:
        for op in ops:
            for iface in ifaces:
                run op on iface
This commit is contained in:
roopa
2014-05-26 09:03:29 -07:00
parent 4931e447fe
commit 923290bd42
3 changed files with 82 additions and 61 deletions

View File

@@ -169,6 +169,7 @@ class iface():
# flag to indicate that the object was created from pickled state # flag to indicate that the object was created from pickled state
_PICKLED = 0x1 _PICKLED = 0x1
HAS_SIBLINGS = 0x2
version = '0.1' version = '0.1'

View File

@@ -188,21 +188,26 @@ class ifupdownMain(ifupdownBase):
return ifaceobj return ifaceobj
def create_n_save_ifaceobjcurr(self, ifaceobj): def create_n_save_ifaceobjcurr(self, ifaceobj):
""" creates a copy of iface object and adds it to the iface dict containing current iface objects """ creates a copy of iface object and adds it to the iface
dict containing current iface objects
""" """
ifaceobjcurr = self.get_ifaceobjcurr(ifaceobj.name)
if ifaceobjcurr:
return ifaceobjcurr
ifaceobjcurr = iface() ifaceobjcurr = iface()
ifaceobjcurr.name = ifaceobj.name ifaceobjcurr.name = ifaceobj.name
ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
ifaceobjcurr.priv_flags = ifaceobj.priv_flags ifaceobjcurr.priv_flags = ifaceobj.priv_flags
ifaceobjcurr.auto = ifaceobj.auto ifaceobjcurr.auto = ifaceobj.auto
self.ifaceobjcurrdict[ifaceobj.name] = ifaceobjcurr self.ifaceobjcurrdict.setdefault(ifaceobj.name,
[]).append(ifaceobjcurr)
return ifaceobjcurr return ifaceobjcurr
def get_ifaceobjcurr(self, ifacename): def get_ifaceobjcurr(self, ifacename, idx=0):
return self.ifaceobjcurrdict.get(ifacename) ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
if not ifaceobjlist:
return None
if not idx:
return ifaceobjlist
else:
return ifaceobjlist[idx]
def get_ifaceobjrunning(self, ifacename): def get_ifaceobjrunning(self, ifacename):
return self.ifaceobjrunningdict.get(ifacename) return self.ifaceobjrunningdict.get(ifacename)
@@ -349,6 +354,8 @@ class ifupdownMain(ifupdownBase):
if ifaceobj.compare(currentifaceobjlist[0]): if ifaceobj.compare(currentifaceobjlist[0]):
self.logger.warn('duplicate interface %s found' %ifaceobj.name) self.logger.warn('duplicate interface %s found' %ifaceobj.name)
return return
currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
ifaceobj.flags |= iface.HAS_SIBLINGS
self.ifaceobjdict[ifaceobj.name].append(ifaceobj) self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
def _iface_configattr_syntax_checker(self, attrname, attrval): def _iface_configattr_syntax_checker(self, attrname, attrval):
@@ -938,19 +945,20 @@ class ifupdownMain(ifupdownBase):
def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs): def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
ret = 0 ret = 0
for i in ifacenames: for i in ifacenames:
ifaceobj = self.get_ifaceobjcurr(i) ifaceobjscurr = self.get_ifaceobjcurr(i)
if not ifaceobj: continue if not ifaceobjscurr: continue
if (ifaceobj.status == ifaceStatus.NOTFOUND or for ifaceobj in ifaceobjscurr:
ifaceobj.status == ifaceStatus.ERROR): if (ifaceobj.status == ifaceStatus.NOTFOUND or
ret = 1 ifaceobj.status == ifaceStatus.ERROR):
if self.is_ifaceobj_noconfig(ifaceobj): ret = 1
continue if self.is_ifaceobj_noconfig(ifaceobj):
ifaceobjs.append(ifaceobj) continue
if self.WITH_DEPENDS and not self.ALL: ifaceobjs.append(ifaceobj)
dlist = ifaceobj.lowerifaces if self.WITH_DEPENDS and not self.ALL:
if not dlist: continue dlist = ifaceobj.lowerifaces
dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs) if not dlist: continue
if dret: ret = 1 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
if dret: ret = 1
return ret return ret
def print_ifaceobjscurr_pretty(self, ifacenames, format='native'): def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):

View File

@@ -49,7 +49,8 @@ class ifaceScheduler():
_STATE_CHECK = True _STATE_CHECK = True
@classmethod @classmethod
def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv): def run_iface_op(cls, ifupdownobj, ifaceobj, op, query_ifaceobj=None,
cenv=None):
""" Runs sub operation on an interface """ """ Runs sub operation on an interface """
ifacename = ifaceobj.name ifacename = ifaceobj.name
@@ -58,16 +59,7 @@ class ifaceScheduler():
(ifaceobj.status == ifaceStatus.SUCCESS)): (ifaceobj.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
# first run ifupdownobj handlers
handler = ifupdownobj.ops_handlers.get(op)
if handler:
if not ifaceobj.addr_method or (ifaceobj.addr_method and
ifaceobj.addr_method != 'manual'):
handler(ifupdownobj, ifaceobj)
if not ifupdownobj.ADDONS_ENABLE: return if not ifupdownobj.ADDONS_ENABLE: return
for mname in ifupdownobj.module_ops.get(op): for mname in ifupdownobj.module_ops.get(op):
m = ifupdownobj.modules.get(mname) m = ifupdownobj.modules.get(mname)
err = 0 err = 0
@@ -81,7 +73,7 @@ class ifaceScheduler():
continue continue
ifupdownobj.logger.debug(msg) ifupdownobj.logger.debug(msg)
m.run(ifaceobj, op, m.run(ifaceobj, op,
query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)) query_ifaceobj)
else: else:
ifupdownobj.logger.debug(msg) ifupdownobj.logger.debug(msg)
m.run(ifaceobj, op) m.run(ifaceobj, op)
@@ -107,23 +99,42 @@ class ifaceScheduler():
ifupdownobj.log_error(str(e)) ifupdownobj.log_error(str(e))
@classmethod @classmethod
def run_iface_ops(cls, ifupdownobj, ifaceobj, ops): def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
""" Runs all operations on an interface """ """ Runs all operations on a list of interface
ifacename = ifaceobj.name configurations for the same interface
"""
# minor optimization. If operation is 'down', proceed only # minor optimization. If operation is 'down', proceed only
# if interface exists in the system # if interface exists in the system
if 'down' in ops[0] and not ifupdownobj.link_exists(ifacename): ifacename = ifaceobjs[0].name
if ('down' in ops[0] and
not ifupdownobj.link_exists(ifacename)):
ifupdownobj.logger.debug('%s: does not exist' %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 return
cenv=None for op in ops:
if ifupdownobj.COMPAT_EXEC_SCRIPTS: # first run ifupdownobj handlers. This is good enough
# For backward compatibility generate env variables # for the first object in the list
# for attributes handler = ifupdownobj.ops_handlers.get(op)
cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0]) if handler:
map(lambda op: cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv), ops) if (not ifaceobjs[0].addr_method or
posthookfunc = ifupdownobj.sched_hooks.get('posthook') (ifaceobjs[0].addr_method and
if posthookfunc: ifaceobjs[0].addr_method != 'manual')):
posthookfunc(ifupdownobj, ifaceobj, ops[0]) handler(ifupdownobj, ifaceobjs[0])
for ifaceobj in ifaceobjs:
cls.run_iface_op(ifupdownobj, ifaceobj, op,
query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(
ifaceobj) if op == 'query-checkcurr' else None,
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 @classmethod
def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent, def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
@@ -182,10 +193,12 @@ class ifaceScheduler():
if not cls._check_upperifaces(ifupdownobj, ifaceobj, if not cls._check_upperifaces(ifupdownobj, ifaceobj,
ops, parent, followdependents): ops, parent, followdependents):
return return
if order == ifaceSchedulerFlags.INORDER:
# If inorder, run the iface first and then its dependents
cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
# 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 # Run lowerifaces or dependents
dlist = ifaceobj.lowerifaces dlist = ifaceobj.lowerifaces
if dlist: if dlist:
@@ -199,12 +212,11 @@ class ifaceScheduler():
# not follow dependents, we must follow the ones # not follow dependents, we must follow the ones
# that dont have user given config. Because we own them # that dont have user given config. Because we own them
new_dlist = [d for d in dlist new_dlist = [d for d in dlist
if ifupdownobj.is_iface_noconfig(d)] if ifupdownobj.is_iface_noconfig(d)]
if new_dlist: if new_dlist:
cls.run_iface_list(ifupdownobj, new_dlist, ops, cls.run_iface_list(ifupdownobj, new_dlist, ops,
ifacename, order, ifacename, order, followdependents,
followdependents, continueonfailure=False)
continueonfailure=False)
else: else:
cls.run_iface_list(ifupdownobj, dlist, ops, cls.run_iface_list(ifupdownobj, dlist, ops,
ifacename, order, ifacename, order,
@@ -216,10 +228,10 @@ class ifaceScheduler():
else: else:
# Dont bring the iface up if children did not come up # Dont bring the iface up if children did not come up
ifaceobj.set_state_n_status(ifaceState.NEW, ifaceobj.set_state_n_status(ifaceState.NEW,
ifaceStatus.ERROR) ifaceStatus.ERROR)
raise raise
if order == ifaceSchedulerFlags.POSTORDER: if order == ifaceSchedulerFlags.POSTORDER:
cls.run_iface_ops(ifupdownobj, ifaceobj, ops) cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
@classmethod @classmethod
def run_iface_list(cls, ifupdownobj, ifacenames, def run_iface_list(cls, ifupdownobj, ifacenames,
@@ -253,11 +265,10 @@ class ifaceScheduler():
if not ifaceobjs: if not ifaceobjs:
raise Exception('%s: not found' %ifacename) 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: 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 # Run upperifaces
ulist = ifaceobj.upperifaces ulist = ifaceobj.upperifaces
if ulist: if ulist:
@@ -320,13 +331,14 @@ class ifaceScheduler():
# logical interface and we have to followupperifaces # logical interface and we have to followupperifaces
followupperifaces = (True if followupperifaces = (True if
[i for i in ifacenames [i for i in ifacenames
if not ifupdownobj.link_exists(i)] if not ifupdownobj.link_exists(i)]
else False) else False)
cls.run_iface_list(ifupdownobj, ifacenames, ops, cls.run_iface_list(ifupdownobj, ifacenames, ops,
parent=None,order=order, parent=None,order=order,
followdependents=followdependents) followdependents=followdependents)
if (not ifupdownobj.ALL and if (not ifupdownobj.ALL and
(followdependents or followupperifaces) and 'up' in ops[0]): (followdependents or followupperifaces) and
'up' in ops[0]):
# If user had given a set of interfaces to bring up # If user had given a set of interfaces to bring up
# try and execute 'up' on the upperifaces # try and execute 'up' on the upperifaces
ifupdownobj.logger.info('running upperifaces if available') ifupdownobj.logger.info('running upperifaces if available')