1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00
roopa ca3f4fc75a Remove upper device check warnings + implicitly follow upperifaces when
a logical interface comes up

Ticket: CM-2493
Reviewed By:
Testing Done: Tested ifup, ifdown in bond bridge setup

Also, implicitly pick up the upperifaces (even when user has not
specified --with-depends) for logical interfaces.
This is because when a logical interface goes down/deleted, kernel
impilicity deletes its upperifaces. so its better to implicitly bring
up upperifaces.

example

bridge name    bridge id        STP enabled    interfaces
br0        8000.7072cf8c2fca    yes        bond1
                            bond2
br2000        8000.7072cf8c2fca    yes        bond1.2000
                            bond2.2000
br2001        8000.7072cf8c2fca    yes        bond1.2001
                            bond2.2001

bridge name    bridge id        STP enabled    interfaces
br0        8000.000000000000    yes
br2000        8000.000000000000    yes
br2001        8000.000000000000    yes

bridge name    bridge id        STP enabled    interfaces
br0        8000.7072cf8c2fca    yes        bond1
                            bond2
br2000        8000.7072cf8c2fca    yes        bond1.2000
                            bond2.2000
br2001        8000.7072cf8c2fca    yes        bond1.2001
                            bond2.2001
2014-03-27 14:00:00 -07:00

397 lines
12 KiB
Python

#!/usr/bin/python
#
# Copyright 2013. Cumulus Networks, Inc.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# iface --
# interface object
#
"""ifupdown2 network interface object
It closely resembles the 'iface' object in /etc/network/interfaces
file. But can be extended to include any other network interface format
The module contains the following public classes:
- ifaceState -- enumerates iface object state
- ifaceStatus -- enumerates iface object status (success/error)
- ifaceJsonEncoder -- Json encoder for the iface object
- iface -- network in terface object class
"""
from collections import OrderedDict
import json
import logging
_tickmark = ' (' + u'\u2713'.encode('utf8') + ')'
_crossmark = ' (' + u'\u2717'.encode('utf8') + ')'
class ifaceStatus():
"""Enumerates iface status """
UNKNOWN = 0x1
SUCCESS = 0x2
ERROR = 0x3
NOTFOUND = 0x4
@classmethod
def to_str(cls, state):
if state == cls.UNKNOWN:
return 'unknown'
elif state == cls.SUCCESS:
return 'success'
elif state == cls.ERROR:
return 'error'
elif state == cls.NOTFOUND:
return 'notfound'
@classmethod
def from_str(cls, state_str):
if state_str == 'unknown':
return cls.UNKNOWN
elif state_str == 'success':
return cls.SUCCESS
elif state_str == 'error':
return cls.ERROR
class ifaceState():
"""Enumerates iface state """
UNKNOWN = 0x1
NEW = 0x2
PRE_UP = 0x3
UP = 0x4
POST_UP = 0x5
PRE_DOWN = 0x6
DOWN = 0x7
POST_DOWN = 0x8
# Pseudo states
QUERY_CHECKCURR = 0x9
QUERY_RUNNING = 0xa
@classmethod
def to_str(cls, state):
if state == cls.UNKNOWN:
return 'unknown'
elif state == cls.NEW:
return 'new'
elif state == cls.PRE_UP:
return 'pre-up'
elif state == cls.UP:
return 'up'
elif state == cls.POST_UP:
return 'post-up'
elif state == cls.PRE_DOWN:
return 'pre-down'
elif state == cls.DOWN:
return 'down'
elif state == cls.POST_DOWN:
return 'post-down'
elif state == cls.QUERY_CHECKCURR:
return 'query-checkcurr'
elif state == cls.QUERY_RUNNING:
return 'query-running'
@classmethod
def from_str(cls, state_str):
if state_str == 'unknown':
return cls.UNKNOWN
elif state_str == 'new':
return cls.NEW
elif state_str == 'pre-up':
return cls.PRE_UP
elif state_str == 'up':
return cls.UP
elif state_str == 'post-up':
return cls.POST_UP
elif state_str == 'pre-down':
return cls.PRE_DOWN
elif state_str == 'down':
return cls.DOWN
elif state_str == 'post-down':
return cls.POST_DOWN
elif state_str == 'query-checkcurr':
return cls.QUERY_CHECKCURR
elif state_str == 'query-running':
return cls.QUERY_RUNNING
class ifaceJsonEncoder(json.JSONEncoder):
def default(self, o):
retconfig = {}
if o.config:
for k, v in o.config.items():
if len(v) == 1:
retconfig[k] = v[0]
else:
retconfig[k] = v
return OrderedDict({'name' : o.name,
'addr_method' : o.addr_method,
'addr_family' : o.addr_family,
'auto' : o.auto,
'config' : retconfig})
class iface():
""" ifupdown2 interface object class
Attributes:
name Name of the interface
addr_family Address family eg, inet, inet6. Can be None to indicate both address families
addr_method Address method eg, static, manual or None for static
address method
config dictionary of config lines for this interface
state Configuration state of an interface as defined by
ifaceState
status Configuration status of an interface as defined by
ifaceStatus
flags Internal flags used by iface processing
priv_flags private flags owned by module using this class
refcnt reference count, indicating number of interfaces
dependent on this iface
lowerifaces list of interface names lower to this interface or
this interface depends on
upperifaces list of interface names upper to this interface or
the interfaces that depend on this interface
auto True if interface belongs to the auto class
classes List of classes the interface belongs to
env shell environment the interface needs during execution
raw_config raw interface config from file
"""
# flag to indicate that the object was created from pickled state
_PICKLED = 0x1
version = '0.1'
def __init__(self):
self.name = None
self.addr_family = None
self.addr_method = None
self.config = OrderedDict()
self._config_status = {}
self.state = ifaceState.NEW
self.status = ifaceStatus.UNKNOWN
self.flags = 0x0
self.priv_flags = 0x0
self.refcnt = 0
self.lowerifaces = None
self.upperifaces = None
self.auto = False
self.classes = []
self.env = None
self.raw_config = []
self.linkstate = None
def inc_refcnt(self):
self.refcnt += 1
def dec_refcnt(self):
self.refcnt -= 1
def is_config_present(self):
addr_method = self.addr_method
if addr_method:
if (addr_method.find('dhcp') != -1 or
addr_method.find('dhcp6') != -1):
return True
if not self.config:
return False
else:
return True
def set_class(self, classname):
""" Appends a class to the list """
self.classes.append(classname)
def set_state_n_status(self, state, status):
self.state = state
self.status = status
def set_flag(self, flag):
self.flags |= flag
def clear_flag(self, flag):
self.flags &= ~flag
def add_to_upperifaces(self, upperifacename):
if self.upperifaces:
if upperifacename not in self.upperifaces:
self.upperifaces.append(upperifacename)
else:
self.upperifaces = [upperifacename]
def get_attr_value(self, attr_name):
return self.config.get(attr_name)
def get_attr_value_first(self, attr_name):
attr_value_list = self.config.get(attr_name)
if attr_value_list:
return attr_value_list[0]
return None
def get_attr_value_n(self, attr_name, attr_index):
attr_value_list = self.config.get(attr_name)
if attr_value_list:
try:
return attr_value_list[attr_index]
except:
return None
return None
@property
def get_env(self):
if not self.env:
self.generate_env()
return self.env
def generate_env(self):
env = {}
config = self.config
env['IFACE'] = self.name
for attr, attr_value in config.items():
attr_env_name = 'IF_%s' %attr.upper()
env[attr_env_name] = attr_value[0]
if env:
self.env = env
def update_config(self, attr_name, attr_value):
self.config.setdefault(attr_name, []).append(attr_value)
def update_config_dict(self, attrdict):
self.config.update(attrdict)
def update_config_with_status(self, attr_name, attr_value, attr_status=0):
if not attr_value:
attr_value = ''
self.config.setdefault(attr_name, []).append(attr_value)
self._config_status.setdefault(attr_name, []).append(attr_status)
# set global iface state
if attr_status:
self.status = ifaceStatus.ERROR
elif self.status != ifaceStatus.ERROR:
# Not already error, mark success
self.status = ifaceStatus.SUCCESS
def get_config_attr_status(self, attr_name, idx=0):
return self._config_status.get(attr_name, [])[idx]
def get_config_attr_status_str(self, attr_name, idx=0):
ret = self.get_config_attr_status(attr_name, idx)
if ret:
return _crossmark
else:
return _tickmark
def compare(self, dstiface):
""" Compares two objects
Returns True if object self is same as dstiface and False otherwise """
if self.name != dstiface.name: return False
if self.addr_family != dstiface.addr_family: return False
if self.addr_method != dstiface.addr_method: return False
if self.auto != dstiface.auto: return False
if self.classes != dstiface.classes: return False
if any(True for k in self.config if k not in dstiface.config):
return False
if any(True for k,v in self.config.items()
if v != dstiface.config.get(k)): return False
return True
def __getstate__(self):
odict = self.__dict__.copy()
del odict['state']
del odict['status']
del odict['lowerifaces']
del odict['upperifaces']
del odict['refcnt']
del odict['_config_status']
del odict['flags']
del odict['priv_flags']
del odict['raw_config']
del odict['linkstate']
del odict['env']
return odict
def __setstate__(self, dict):
self.__dict__.update(dict)
self._config_status = {}
self.state = ifaceState.NEW
self.status = ifaceStatus.UNKNOWN
self.refcnt = 0
self.flags = 0
self.lowerifaces = None
self.upperifaces = None
self.linkstate = None
self.env = None
self.priv_flags = 0
self.raw_config = []
self.flags |= self._PICKLED
def dump_raw(self, logger):
indent = ' '
if self.auto:
print 'auto %s' %self.name
print (self.raw_config[0])
for i in range(1, len(self.raw_config)):
print(indent + self.raw_config[i])
def dump(self, logger):
indent = '\t'
logger.info(self.name + ' : {')
logger.info(indent + 'family: %s' %self.addr_family)
logger.info(indent + 'method: %s' %self.addr_method)
logger.info(indent + 'flags: %x' %self.flags)
logger.info(indent + 'state: %s'
%ifaceState.to_str(self.state))
logger.info(indent + 'status: %s'
%ifaceStatus.to_str(self.status))
logger.info(indent + 'refcnt: %d' %self.refcnt)
d = self.lowerifaces
if d:
logger.info(indent + 'lowerdevs: %s' %str(d))
else:
logger.info(indent + 'lowerdevs: None')
logger.info(indent + 'config: ')
config = self.config
if config:
logger.info(indent + indent + str(config))
logger.info('}')
def dump_pretty(self, with_status=False):
indent = '\t'
outbuf = ''
if self.auto:
outbuf += 'auto %s\n' %self.name
outbuf += 'iface %s' %self.name
if self.addr_family:
outbuf += ' %s' %self.addr_family
if self.addr_method:
outbuf += ' %s' %self.addr_method
outbuf += '\n'
config = self.config
if config:
for cname, cvaluelist in config.items():
idx = 0
for cv in cvaluelist:
if with_status:
outbuf += indent + '%s %s %s\n' %(cname, cv,
self.get_config_attr_status_str(cname, idx))
else:
outbuf += indent + '%s %s\n' %(cname, cv)
idx += 1
print outbuf
def dump_json(self, with_status=False):
print json.dumps(self, cls=ifaceJsonEncoder, indent=4)