mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
293 lines
12 KiB
Python
293 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
#
|
|
|
|
try:
|
|
from ifupdown2.ifupdown.iface import *
|
|
from ifupdown2.ifupdown.utils import utils
|
|
|
|
from ifupdown2.ifupdownaddons.cache import *
|
|
from ifupdown2.ifupdownaddons.utilsbase import *
|
|
except (ImportError, ModuleNotFoundError):
|
|
from ifupdown.iface import *
|
|
from ifupdown.utils import utils
|
|
|
|
from ifupdownaddons.cache import *
|
|
from ifupdownaddons.utilsbase import *
|
|
|
|
|
|
class mstpctlutil(utilsBase):
|
|
""" This class contains helper methods to interact with mstpd using
|
|
mstputils commands """
|
|
|
|
_DEFAULT_PORT_PRIO = '128'
|
|
|
|
_cache_fill_done = False
|
|
|
|
_bridgeattrmap = {'bridgeid' : 'bridge-id',
|
|
'maxage' : 'max-age',
|
|
'fdelay' : 'forward-delay',
|
|
'txholdcount' : 'tx-hold-count',
|
|
'maxhops' : 'max-hops',
|
|
'ageing' : 'ageing-time',
|
|
'hello' : 'hello-time',
|
|
'forcevers' : 'force-protocol-version'}
|
|
|
|
_bridge_jsonAttr_map = {
|
|
'treeprio': 'bridgeId',
|
|
'maxage': 'maxAge',
|
|
'fdelay': 'fwdDelay',
|
|
'txholdcount': 'txHoldCounter',
|
|
'maxhops': 'maxHops',
|
|
'ageing': 'ageingTime',
|
|
'hello': 'helloTime',
|
|
'forcevers': 'forceProtocolVersion',
|
|
}
|
|
|
|
_bridgeportattrmap = {'portadminedge' : 'admin-edge-port',
|
|
'portp2p' : 'admin-point-to-point',
|
|
'portrestrrole' : 'restricted-role',
|
|
'portrestrtcn' : 'restricted-TCN',
|
|
'bpduguard' : 'bpdu-guard-port',
|
|
'portautoedge' : 'auto-edge-port',
|
|
'portnetwork' : 'network-port',
|
|
'portbpdufilter' : 'bpdufilter-port',
|
|
'portpathcost' : 'external-port-cost',
|
|
'treeportcost' : 'internal-port-cost'}
|
|
|
|
def __init__(self, *args, **kargs):
|
|
utilsBase.__init__(self, *args, **kargs)
|
|
|
|
self.__batch = []
|
|
self.__batch_mode = False
|
|
|
|
def __add_to_batch(self, cmd):
|
|
self.__batch.append(cmd)
|
|
|
|
def __execute_or_batch(self, cmd):
|
|
if self.__batch_mode:
|
|
self.__add_to_batch(cmd)
|
|
else:
|
|
utils.exec_command("%s %s" % (utils.mstpctl_cmd, cmd))
|
|
|
|
def __execute_or_batch_dry_run(self, cmd):
|
|
"""
|
|
The batch function has it's own dryrun handler so we only handle
|
|
dryrun for non-batch mode. Which will be removed once the "utils"
|
|
module has it's own dryrun handlers
|
|
"""
|
|
if self.__batch_mode:
|
|
self.__add_to_batch(cmd)
|
|
else:
|
|
self.logger.info("DRY-RUN: executing: %s %s" % (utils.mstpctl_cmd, cmd))
|
|
|
|
def batch_start(self):
|
|
if not self.__batch_mode:
|
|
self.__batch_mode = True
|
|
self.__batch = []
|
|
|
|
def batch_commit(self):
|
|
if not self.__batch_mode or not self.__batch:
|
|
return
|
|
try:
|
|
utils.exec_command(
|
|
"%s batch -" % utils.mstpctl_cmd,
|
|
stdin="\n".join(self.__batch)
|
|
)
|
|
except Exception:
|
|
raise
|
|
finally:
|
|
self.__batch_mode = False
|
|
del self.__batch
|
|
self.__batch = None
|
|
|
|
###############################################################################
|
|
###############################################################################
|
|
###############################################################################
|
|
|
|
@classmethod
|
|
def reset(cls):
|
|
cls._cache_fill_done = False
|
|
|
|
def is_mstpd_running(self):
|
|
try:
|
|
utils.exec_command('%s mstpd'%utils.pidof_cmd)
|
|
except Exception:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def _extract_bridge_port_prio(self, portid):
|
|
try:
|
|
return str(int(portid[0], 16) * 16)
|
|
except Exception:
|
|
return mstpctlutil._DEFAULT_PORT_PRIO
|
|
|
|
def _get_bridge_and_port_attrs_from_cache(self, bridgename):
|
|
attrs = MSTPAttrsCache.get(bridgename, None)
|
|
if attrs is not None:
|
|
return attrs
|
|
mstpctl_bridgeport_attrs_dict = {}
|
|
try:
|
|
cmd = [utils.mstpctl_cmd,
|
|
'showportdetail', bridgename, 'json']
|
|
output = utils.exec_commandl(cmd)
|
|
if not output:
|
|
MSTPAttrsCache.set(bridgename, mstpctl_bridgeport_attrs_dict)
|
|
return mstpctl_bridgeport_attrs_dict
|
|
except Exception as e:
|
|
self.logger.info(str(e))
|
|
return mstpctl_bridgeport_attrs_dict
|
|
portname = bridgename # assigning portname to avoid an exception, in the exception handler
|
|
try:
|
|
mstpctl_bridge_cache = json.loads(output.strip("\n"))
|
|
for portname in list(mstpctl_bridge_cache.keys()):
|
|
for portid in list(mstpctl_bridge_cache[portname].keys()):
|
|
mstpctl_bridgeport_attrs_dict[portname] = {}
|
|
mstpctl_bridgeport_attrs_dict[portname]['treeportprio'] = self._extract_bridge_port_prio(portid)
|
|
for jsonAttr in list(mstpctl_bridge_cache[portname][portid].keys()):
|
|
jsonVal = mstpctl_bridge_cache[portname][portid][jsonAttr]
|
|
mstpctl_bridgeport_attrs_dict[portname][jsonAttr] = str(jsonVal)
|
|
MSTPAttrsCache.set(bridgename, mstpctl_bridgeport_attrs_dict)
|
|
except Exception as e:
|
|
self.logger.info('%s: cannot fetch mstpctl bridge port attributes: %s' % (portname, str(e)))
|
|
|
|
mstpctl_bridge_attrs_dict = {}
|
|
try:
|
|
cmd = [utils.mstpctl_cmd,
|
|
'showbridge', 'json', bridgename]
|
|
output = utils.exec_commandl(cmd)
|
|
if not output:
|
|
return mstpctl_bridge_attrs_dict
|
|
except Exception as e:
|
|
self.logger.info(str(e))
|
|
return mstpctl_bridge_attrs_dict
|
|
try:
|
|
mstpctl_bridge_cache = json.loads(output.strip('\n'))
|
|
for jsonAttr in list(mstpctl_bridge_cache[bridgename].keys()):
|
|
mstpctl_bridge_attrs_dict[jsonAttr] = (
|
|
str(mstpctl_bridge_cache[bridgename][jsonAttr]))
|
|
mstpctl_bridge_attrs_dict['treeprio'] = '%d' %(
|
|
int(mstpctl_bridge_attrs_dict.get('bridgeId',
|
|
'').split('.')[0], base=16) * 4096)
|
|
del mstpctl_bridge_attrs_dict['bridgeId']
|
|
MSTPAttrsCache.bridges[bridgename].update(mstpctl_bridge_attrs_dict)
|
|
except Exception as e:
|
|
self.logger.info('%s: cannot fetch mstpctl bridge attributes: %s' % (bridgename, str(e)))
|
|
return MSTPAttrsCache.get(bridgename)
|
|
|
|
def get_bridge_ports_attrs(self, bridgename):
|
|
return self._get_bridge_and_port_attrs_from_cache(bridgename)
|
|
|
|
def get_bridge_port_attr(self, bridgename, portname, attrname):
|
|
attrs = self._get_bridge_and_port_attrs_from_cache(bridgename)
|
|
value = attrs.get(portname, {}).get(attrname, 'no')
|
|
if value == 'True' or value == 'true':
|
|
return 'yes'
|
|
return str(value)
|
|
|
|
def update_bridge_port_cache(self, bridgename, portname, attrname, value):
|
|
attrs = self.get_bridge_ports_attrs(bridgename)
|
|
if not attrs:
|
|
attrs = {}
|
|
if not portname in attrs:
|
|
attrs[portname] = {}
|
|
attrs[portname][attrname] = value
|
|
MSTPAttrsCache.set(bridgename, attrs)
|
|
|
|
def update_bridge_cache(self, bridgename, attrname, value):
|
|
attrs = self.get_bridge_ports_attrs(bridgename)
|
|
if not attrs:
|
|
attrs = {}
|
|
attrs[attrname] = value
|
|
MSTPAttrsCache.set(bridgename, attrs)
|
|
|
|
def set_bridge_port_attr(self, bridgename, portname, attrname, value, json_attr=None):
|
|
cache_value = self.get_bridge_port_attr(bridgename, portname, json_attr)
|
|
if cache_value and cache_value == value:
|
|
return
|
|
if attrname == 'treeportcost' or attrname == 'treeportprio':
|
|
self.__execute_or_batch("set%s %s %s 0 %s" % (attrname, bridgename, portname, value))
|
|
else:
|
|
self.__execute_or_batch("set%s %s %s %s" % (attrname, bridgename, portname, value))
|
|
if json_attr:
|
|
self.update_bridge_port_cache(bridgename, portname, json_attr, value)
|
|
|
|
def get_bridge_attrs(self, bridgename):
|
|
bridgeattrs = {}
|
|
try:
|
|
bridgeattrs = dict((k, self.get_bridge_attr(bridgename, v))
|
|
for k,v in list(self._bridge_jsonAttr_map.items()))
|
|
except Exception as e:
|
|
self.logger.debug(bridgeattrs)
|
|
self.logger.debug(str(e))
|
|
pass
|
|
return bridgeattrs
|
|
|
|
def get_bridge_attr(self, bridgename, attrname):
|
|
if attrname == 'bridgeId':
|
|
attrname = 'treeprio'
|
|
return self._get_bridge_and_port_attrs_from_cache(bridgename).get(attrname)
|
|
|
|
def set_bridge_attr(self, bridgename, attrname, attrvalue, check=True):
|
|
|
|
if check:
|
|
if attrname == 'treeprio':
|
|
attrvalue_curr = self.get_bridge_attr(bridgename, attrname)
|
|
else:
|
|
attrvalue_curr = self.get_bridge_attr(bridgename,
|
|
self._bridge_jsonAttr_map[attrname])
|
|
if attrvalue_curr and attrvalue_curr == attrvalue:
|
|
return
|
|
|
|
if attrname == 'treeprio':
|
|
self.__execute_or_batch("set%s %s 0 %s" % (attrname, bridgename, attrvalue))
|
|
self.update_bridge_cache(bridgename, attrname, str(attrvalue))
|
|
else:
|
|
self.__execute_or_batch("set%s %s %s" % (attrname, bridgename, attrvalue))
|
|
self.update_bridge_cache(bridgename,
|
|
self._bridge_jsonAttr_map[attrname],
|
|
str(attrvalue))
|
|
|
|
def set_bridge_attrs(self, bridgename, attrdict, check=True):
|
|
for k, v in attrdict.items():
|
|
if not v:
|
|
continue
|
|
try:
|
|
self.set_bridge_attr(bridgename, k, v, check)
|
|
except Exception as e:
|
|
self.logger.warning('%s: %s' %(bridgename, str(e)))
|
|
|
|
def get_bridge_treeprio(self, bridgename):
|
|
return self.get_bridge_attr(bridgename, 'treeprio')
|
|
|
|
def set_bridge_treeprio(self, bridgename, attrvalue, check=True):
|
|
if check:
|
|
attrvalue_curr = self.get_bridge_treeprio(bridgename)
|
|
if attrvalue_curr and attrvalue_curr == attrvalue:
|
|
return
|
|
self.__execute_or_batch("settreeprio %s 0 %s" % (bridgename, str(attrvalue)))
|
|
|
|
self.update_bridge_cache(bridgename, 'treeprio', str(attrvalue))
|
|
|
|
def showbridge(self, bridgename=None):
|
|
if bridgename:
|
|
return utils.exec_command('%s showbridge %s' %
|
|
(utils.mstpctl_cmd, bridgename))
|
|
else:
|
|
return utils.exec_command('%s showbridge' %utils.mstpctl_cmd)
|
|
|
|
def showportdetail(self, bridgename):
|
|
return utils.exec_command('%s showportdetail %s' %
|
|
(utils.mstpctl_cmd, bridgename))
|
|
|
|
def mstpbridge_exists(self, bridgename):
|
|
try:
|
|
utils.exec_command('%s showbridge %s' %
|
|
(utils.mstpctl_cmd, bridgename))
|
|
return True
|
|
except Exception:
|
|
return False
|