#!/usr/bin/python # # Copyright 2014 Cumulus Networks, Inc. All rights reserved. # Author: Roopa Prabhu, roopa@cumulusnetworks.com # from cache import MSTPAttrsCache from utilsbase import * from ifupdown.iface import * from ifupdown.utils import utils from cache import * import json 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'} _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) def is_mstpd_running(self): try: utils.exec_command('/bin/pidof mstpd') except: return False else: return True def _extract_bridge_port_prio(self, portid): try: return str(int(portid[0], 16) * 16) except: return mstpctlutil._DEFAULT_PORT_PRIO def _get_bridge_port_attrs_from_cache(self, bridgename): attrs = MSTPAttrsCache.get(bridgename) if attrs: return attrs mstpctl_bridgeport_attrs_dict = {} try: cmd = ['/sbin/mstpctl', 'showportdetail', bridgename, 'json'] output = utils.exec_commandl(cmd) if not output: return mstpctl_bridgeport_attrs_dict except Exception as e: self.logger.info(str(e)) return mstpctl_bridgeport_attrs_dict try: mstpctl_bridge_cache = json.loads(output.strip('\n')) for portname in mstpctl_bridge_cache.keys(): for portid in 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 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' % str(e)) return mstpctl_bridgeport_attrs_dict def get_bridge_ports_attrs(self, bridgename): return self._get_bridge_port_attrs_from_cache(bridgename) def get_bridge_port_attr(self, bridgename, portname, attrname): attrs = self._get_bridge_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_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 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': utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, bridgename, portname, '0', value]) else: utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, bridgename, portname, value]) if json_attr: self.update_cache(bridgename, portname, json_attr, value) def get_bridge_attrs(self, bridgename): bridgeattrs = {} try: bridgeattrs = dict((k, self.get_bridge_attr(bridgename, k)) for k in self._bridgeattrmap.keys()) bridgeattrs['treeprio'] = '%d' %(int(bridgeattrs.get('bridgeid', '').split('.')[0], base=16) * 4096) del bridgeattrs['bridgeid'] except Exception, e: self.logger.debug(bridgeattrs) self.logger.debug(str(e)) pass return bridgeattrs def get_bridge_attr(self, bridgename, attrname): try: cmdl = ['/sbin/mstpctl', 'showbridge', bridgename, self._bridgeattrmap[attrname]] return utils.exec_commandl(cmdl).strip('\n') except Exception, e: pass return None def set_bridge_attr(self, bridgename, attrname, attrvalue, check=True): if check: attrvalue_curr = self.get_bridge_attr(bridgename, attrname) if attrvalue_curr and attrvalue_curr == attrvalue: return if attrname == 'treeprio': utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, '%s' % bridgename, '0', '%s' % attrvalue], stdout=False, stderr=None) else: utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, '%s' % bridgename, '%s' % attrvalue], stdout=False, stderr=None) def set_bridge_attrs(self, bridgename, attrdict, check=True): for k, v in attrdict.iteritems(): if not v: continue try: self.set_bridge_attr(bridgename, k, v, check) except Exception, e: self.logger.warn('%s: %s' %(bridgename, str(e))) def get_bridge_treeprio(self, bridgename): try: cmdl = ['/sbin/mstpctl', 'showbridge', bridgename, self._bridgeattrmap['bridgeid']] bridgeid = utils.exec_commandl(cmdl).strip('\n') return '%d' %(int(bridgeid.split('.')[0], base=16) * 4096) except: pass return None 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 utils.exec_commandl(['/sbin/mstpctl', 'settreeprio', bridgename, '0', str(attrvalue)]) def showbridge(self, bridgename=None): if bridgename: return utils.exec_command('/sbin/mstpctl showbridge %s' % bridgename) else: return utils.exec_command('/sbin/mstpctl showbridge') def showportdetail(self, bridgename): return utils.exec_command('/sbin/mstpctl showportdetail %s' % bridgename) def mstpbridge_exists(self, bridgename): try: utils.exec_command('mstpctl showbridge %s' % bridgename, stdout=False) return True except: return False