mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
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.
466 lines
13 KiB
Python
466 lines
13 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright 2013. Cumulus Networks, Inc.
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
#
|
|
# iface --
|
|
# interface object
|
|
#
|
|
from collections import OrderedDict
|
|
#from json import *
|
|
import json
|
|
import logging
|
|
|
|
tickmark = ' (' + u'\u2713'.encode('utf8') + ')'
|
|
crossmark = ' (' + u'\u2717'.encode('utf8') + ')'
|
|
|
|
class ifaceFlags():
|
|
NONE = 0x1
|
|
FOLLOW_DEPENDENTS = 0x2
|
|
|
|
class ifaceStatus():
|
|
"""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():
|
|
|
|
""" iface states """
|
|
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():
|
|
""" flags """
|
|
# 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_lines = []
|
|
self.linkstate = None
|
|
|
|
def inc_refcnt(self):
|
|
self.refcnt += 1
|
|
|
|
def dec_refcnt(self):
|
|
self.refcnt -= 1
|
|
|
|
def get_refcnt(self):
|
|
return self.refcnt
|
|
|
|
def set_refcnt(self, cnt):
|
|
self.refcnt = 0
|
|
|
|
def set_name(self, name):
|
|
self.name = name
|
|
|
|
def get_name(self):
|
|
return self.name
|
|
|
|
def set_addr_family(self, family):
|
|
self.addr_family = family
|
|
|
|
def get_addr_family(self):
|
|
return self.addr_family
|
|
|
|
def set_addr_method(self, method):
|
|
self.addr_method = method
|
|
|
|
def get_addr_method(self):
|
|
return self.addr_method
|
|
|
|
def set_config(self, config_dict):
|
|
self.config = config_dict
|
|
|
|
def get_config(self):
|
|
return self.config
|
|
|
|
def is_config_present(self):
|
|
addr_method = self.get_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 get_auto(self):
|
|
return self.auto
|
|
|
|
def set_auto(self):
|
|
self.auto = True
|
|
|
|
def reset_auto(self):
|
|
self.auto = False
|
|
|
|
def get_classes(self):
|
|
return self.classes
|
|
|
|
def set_classes(self, classes):
|
|
""" sets interface class list to the one passed as arg """
|
|
self.classes = classes
|
|
|
|
def set_class(self, classname):
|
|
""" Appends a class to the list """
|
|
self.classes.append(classname)
|
|
|
|
def belongs_to_class(self, intfclass):
|
|
if intfclass in self.classes:
|
|
return True
|
|
return False
|
|
|
|
def set_priv_flags(self, priv_flags):
|
|
self.priv_flags = priv_flags
|
|
|
|
def get_priv_flags(self):
|
|
return self.priv_flags
|
|
|
|
def get_state(self):
|
|
return self.state
|
|
|
|
def get_state_str(self):
|
|
return ifaceState.to_str(self.state)
|
|
|
|
def set_state(self, state):
|
|
self.state = state
|
|
|
|
def get_status(self):
|
|
return self.status
|
|
|
|
def get_status_str(self):
|
|
return ifaceStatus.to_str(self.status)
|
|
|
|
def set_status(self, status):
|
|
self.status = status
|
|
|
|
def set_state_n_status(self, state, status):
|
|
self.state = state
|
|
self.status = status
|
|
|
|
def state_str_to_hex(self, state_str):
|
|
return self.state_str_map.get(state_str)
|
|
|
|
def set_flag(self, flag):
|
|
self.flags |= flag
|
|
|
|
def clear_flag(self, flag):
|
|
self.flags &= ~flag
|
|
|
|
def set_lowerifaces(self, dlist):
|
|
self.lowerifaces = dlist
|
|
|
|
def get_lowerifaces(self):
|
|
return self.lowerifaces
|
|
|
|
def set_upperifaces(self, dlist):
|
|
self.upperifaces = dlist
|
|
|
|
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_upperifaces(self):
|
|
return self.upperifaces
|
|
|
|
def set_linkstate(self, l):
|
|
self.linkstate = l
|
|
|
|
def get_linkstate(self):
|
|
return self.linkstate
|
|
|
|
def get_attr_value(self, attr_name):
|
|
config = self.get_config()
|
|
|
|
return config.get(attr_name)
|
|
|
|
def get_attr_value_first(self, attr_name):
|
|
config = self.get_config()
|
|
attr_value_list = 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):
|
|
config = self.get_config()
|
|
|
|
attr_value_list = config.get(attr_name)
|
|
if attr_value_list:
|
|
try:
|
|
return attr_value_list[attr_index]
|
|
except:
|
|
return None
|
|
return None
|
|
|
|
def get_env(self):
|
|
if not self.env:
|
|
self.generate_env()
|
|
return self.env
|
|
|
|
def set_env(self, env):
|
|
self.env = env
|
|
|
|
def generate_env(self):
|
|
env = {}
|
|
config = self.get_config()
|
|
env['IFACE'] = self.get_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.set_env(env)
|
|
|
|
def update_config(self, attr_name, attr_value):
|
|
if not self.config.get(attr_name):
|
|
self.config[attr_name] = [attr_value]
|
|
else:
|
|
self.config[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 = ''
|
|
|
|
if self.config.get(attr_name):
|
|
self.config[attr_name].append(attr_value)
|
|
self.config_status[attr_name].append(attr_status)
|
|
else:
|
|
self.config[attr_name] = [attr_value]
|
|
self.config_status[attr_name] = [attr_status]
|
|
|
|
# set global iface state
|
|
if attr_status:
|
|
self.set_status(ifaceStatus.ERROR)
|
|
elif self.get_status() != ifaceStatus.ERROR:
|
|
# Not already error, mark success
|
|
self.set_status(ifaceStatus.SUCCESS)
|
|
|
|
def get_config_attr_status(self, attr_name, idx=0):
|
|
self.config_status.get(attr_name, [])[idx]
|
|
|
|
def get_config_attr_status_str(self, attr_name, idx=0):
|
|
ret = self.config_status.get(attr_name, [])[idx]
|
|
if ret:
|
|
return crossmark
|
|
else:
|
|
return tickmark
|
|
|
|
def is_different(self, dstiface):
|
|
if self.name != dstiface.name: return True
|
|
if self.addr_family != dstiface.addr_family: return True
|
|
if self.addr_method != dstiface.addr_method: return True
|
|
if self.auto != dstiface.auto: return True
|
|
if self.classes != dstiface.classes: return True
|
|
|
|
if any(True for k in self.config if k not in dstiface.config):
|
|
return True
|
|
|
|
if any(True for k,v in self.config.items()
|
|
if v != dstiface.config.get(k)): return True
|
|
|
|
return False
|
|
|
|
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_lines']
|
|
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_lines = []
|
|
self.flags |= self.PICKLED
|
|
|
|
def dump_raw(self, logger):
|
|
indent = ' '
|
|
print (self.raw_lines[0])
|
|
for i in range(1, len(self.raw_lines)):
|
|
print (indent + self.raw_lines[i])
|
|
|
|
def dump(self, logger):
|
|
indent = '\t'
|
|
logger.info(self.get_name() + ' : {')
|
|
logger.info(indent + 'family: %s' %self.get_addr_family())
|
|
logger.info(indent + 'method: %s' %self.get_addr_method())
|
|
logger.info(indent + 'flags: %x' %self.flags)
|
|
logger.info(indent + 'state: %s'
|
|
%ifaceState.to_str(self.get_state()))
|
|
logger.info(indent + 'status: %s'
|
|
%ifaceStatus.to_str(self.get_status()))
|
|
logger.info(indent + 'refcnt: %d' %self.get_refcnt())
|
|
d = self.get_lowerifaces()
|
|
if d:
|
|
logger.info(indent + 'lowerdevs: %s' %str(d))
|
|
else:
|
|
logger.info(indent + 'lowerdevs: None')
|
|
|
|
logger.info(indent + 'config: ')
|
|
config = self.get_config()
|
|
if config:
|
|
logger.info(indent + indent + str(config))
|
|
logger.info('}')
|
|
|
|
def dump_pretty(self, with_status=False):
|
|
indent = '\t'
|
|
outbuf = ''
|
|
if self.get_auto():
|
|
outbuf += 'auto %s\n' %self.get_name()
|
|
outbuf += 'iface %s' %self.get_name()
|
|
if self.get_addr_family():
|
|
outbuf += ' %s' %self.get_addr_family()
|
|
if self.get_addr_method():
|
|
outbuf += ' %s' %self.get_addr_method()
|
|
outbuf += '\n'
|
|
config = self.get_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)
|