mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Ticket: CM-7756 Reviewed By: roopa Testing Done: built powerpc and tested ifupdown2 as well as new tests Once mstpctl-portbpdufilter or mstpctl-bpduguard is enabled for an interface, removing the configuration in /etc/network/interfaces does not toggle the mstpctl state back to no. The root cause of this problem is that "ifreload" does not check default settings for MSTP configuration for bridge ports and use a default when that setting is removed from the configuration. This patch adds a check in the existing loop on attribute values. If there is no configured value, we check to see if a default exists. self._modinfo['attrs'][attrname]['default'] exists. If it exists and it is different then the currently running value we reset the attribute to its default. This is what a customer would expect if they removed a configured value. (also added test in cl-tests to check this functionality) (cherry picked from commit 63d0f7082d44fedabe002aebbb658751dc655a46)
213 lines
8.5 KiB
Python
213 lines
8.5 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
#
|
|
|
|
from utilsbase import *
|
|
from ifupdown.iface import *
|
|
from cache import *
|
|
import re
|
|
import json
|
|
|
|
class mstpctlutil(utilsBase):
|
|
""" This class contains helper methods to interact with mstpd using
|
|
mstputils commands """
|
|
|
|
_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'}
|
|
|
|
def __init__(self, *args, **kargs):
|
|
utilsBase.__init__(self, *args, **kargs)
|
|
|
|
def is_mstpd_running(self):
|
|
try:
|
|
self.exec_command('/bin/pidof mstpd')
|
|
except:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def get_bridgeport_attr(self, bridgename, portname, attrname):
|
|
try:
|
|
return self.subprocess_check_output(['/sbin/mstpctl',
|
|
'showportdetail', '%s' %bridgename, '%s' %portname,
|
|
self._bridgeportattrmap[attrname]]).strip('\n')
|
|
except Exception, e:
|
|
pass
|
|
return None
|
|
|
|
def get_bridgeport_attrs(self, bridgename, portname):
|
|
bridgeattrs = {}
|
|
try:
|
|
bridgeattrs = dict((k, self.get_bridgeport_attr(bridgename, v))
|
|
for k, v in self._bridgeattrmap.items())
|
|
bridgeattrs['treeprio'] = int(bridgeattrs.get('bridgeid',
|
|
'').split('.')[0], base=16) * 4096
|
|
except Exception, e:
|
|
self.logger.warn(str(e))
|
|
pass
|
|
return bridgeattrs
|
|
|
|
def cache_bridgeport_attrs(self,bridgename):
|
|
'''
|
|
This method grab output of a mstpctl showportdetail json and caches
|
|
it this should save on the overhead of checking each attribute
|
|
for every port in the bridge.
|
|
'''
|
|
self.mstpctl_bridgeport_attrs_dict = {}
|
|
self.mstpctl_bridgeport_attrs_dict[bridgename] = {}
|
|
showall_output = self.subprocess_check_output(['/sbin/mstpctl',
|
|
'showportdetail', bridgename, 'json']).strip('\n')
|
|
if showall_output == None or showall_output == '':
|
|
return
|
|
mstpctl_bridge_cache = json.loads(showall_output)
|
|
for portname in mstpctl_bridge_cache.keys():
|
|
# we will ignore the portid for now and just index
|
|
# by bridgename, portname, and json attribute
|
|
for portid in mstpctl_bridge_cache[portname].keys():
|
|
self.mstpctl_bridgeport_attrs_dict[bridgename][portname] = {}
|
|
for jsonAttr in mstpctl_bridge_cache[portname][portid].keys():
|
|
jsonVal = mstpctl_bridge_cache[portname][portid][jsonAttr]
|
|
self.mstpctl_bridgeport_attrs_dict[bridgename][portname]\
|
|
[jsonAttr] = str(jsonVal)
|
|
|
|
def get_mstpctl_bridgeport_attr(self,bridgename=None, portname=None,
|
|
jsonAttr=None):
|
|
'''
|
|
Just return the JSON attribute we cached earlier making
|
|
sure to convert integers to strings for later comparison.
|
|
'''
|
|
if not bridgename or not portname or not jsonAttr:
|
|
return
|
|
# just return the value or None if there is no JSON attr defined the
|
|
# output will not show anything if the value is no so we default to no
|
|
val = self.mstpctl_bridgeport_attrs_dict.get(bridgename,{}).get(portname,{}).\
|
|
get(jsonAttr,'no')
|
|
if val == 'True':
|
|
val = 'yes'
|
|
# some values are integers so we need to return only strings
|
|
return str(val)
|
|
|
|
def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict,
|
|
check=True):
|
|
for k, v in attrdict.iteritems():
|
|
if not v:
|
|
continue
|
|
try:
|
|
self.set_bridgeport_attr(self, bridgename, bridgeportname,
|
|
k, v, check)
|
|
except Exception, e:
|
|
self.logger.warn(str(e))
|
|
|
|
def set_bridgeport_attr(self, bridgename, bridgeportname, attrname,
|
|
attrvalue, check=True):
|
|
if check:
|
|
attrvalue_curr = self.get_bridgeport_attr(bridgename,
|
|
bridgeportname, attrname)
|
|
if attrvalue_curr and attrvalue_curr == attrvalue:
|
|
return
|
|
if attrname == 'treeportcost' or attrname == 'treeportprio':
|
|
self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
|
|
'%s' %bridgename, '%s' %bridgeportname, '0', '%s' %attrvalue])
|
|
else:
|
|
self.subprocess_check_output(['/sbin/mstpctl', 'set%s' %attrname,
|
|
'%s' %bridgename, '%s' %bridgeportname, '%s' %attrvalue])
|
|
|
|
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:
|
|
return self.subprocess_check_output(['/sbin/mstpctl',
|
|
'showbridge', '%s' %bridgename,
|
|
self._bridgeattrmap[attrname]]).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':
|
|
self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
|
|
'%s' %bridgename, '0', '%s' %attrvalue])
|
|
else:
|
|
self.subprocess_check_call(['/sbin/mstpctl', 'set%s' %attrname,
|
|
'%s' %bridgename, '%s' %attrvalue])
|
|
|
|
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)))
|
|
pass
|
|
|
|
def get_bridge_treeprio(self, bridgename):
|
|
try:
|
|
bridgeid = subprocess.check_output(['/sbin/mstpctl',
|
|
'showbridge', '%s' %bridgename,
|
|
self._bridgeattrmap['bridgeid']]).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
|
|
self.subprocess_check_output(['/sbin/mstpctl', 'settreeprio',
|
|
'%s' %bridgename, '0', '%s' %attrvalue])
|
|
|
|
def showbridge(self, bridgename=None):
|
|
if bridgename:
|
|
return self.exec_command('/sbin/mstpctl showbridge %s' %bridgename)
|
|
else:
|
|
return self.exec_command('/sbin/mstpctl showbridge')
|
|
|
|
def showportdetail(self, bridgename):
|
|
return self.exec_command('/sbin/mstpctl showportdetail %s' %bridgename)
|
|
|
|
def mstpbridge_exists(self, bridgename):
|
|
try:
|
|
subprocess.check_call('mstpctl showbridge %s' %bridgename)
|
|
return True
|
|
except:
|
|
return False
|