1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

249 lines
10 KiB
Python
Raw Normal View History

#!/usr/bin/python
#
# 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:
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 """
ifupdownaddons: mstpctl: treeportprio value is cached. It prevents ifupdown2 from executing mstpctl settreeportprio commands when the running value is the same as the one previously cached Ticket: CM-11773 Reviewed By: Roopa, Nikhil G Testing Done: smoke + hand testings : $ cat /etc/network/interfaces auto br2 iface br2 bridge-vlan-aware yes bridge-vids 100 bridge-pvid 1 bridge-ports swp1 swp4 swp5 bridge-stp on $ ifreload -a -v [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: executing /sbin/mstpctl showportdetail br2 json info: executing /sbin/mstpctl settreeportprio br2 swp1 0 128 info: br2: processing mstp config for port swp4 info: executing /sbin/mstpctl settreeportprio br2 swp4 0 128 info: br2: processing mstp config for port swp5 info: executing /sbin/mstpctl settreeportprio br2 swp5 0 128 info: netlink: set link br2 up [...] $ /sbin/mstpctl settreeportprio br2 swpX 0 128 is executed for every port. ifupdown2 tries to set this attr to 128 (the default value). This is a problem at scale. We shouldn't try to set this value if the running value is already 128. With the attached patch: $ ifreload -a [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: executing /sbin/mstpctl showportdetail br2 json info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: br2: processing mstp config for port swp4 info: br2: processing mstp config for port swp5 info: netlink: set link br2 up [...] $ Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
2016-08-01 09:49:08 +02:00
_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',
addons: mstpctl: complete ifquery -r support Ticket: CM-7841 Reviewed By: roopa, julien Testing Done: tested all the bridge attributes added 'ifquery -r' support for 'mstpctl-portpathcost', 'mstpctl-treeportcost', 'mstpctl-portautoedge', 'mstpctl-portbpdufilter', 'mstpctl-portnetwork' Below is the sample configuration and output root@dell-s3000-02:~# ifquery -a auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp auto br0 iface br0 bridge-vlan-aware yes bridge-ports swp42 swp43 mstpctl-fdelay 14 mstpctl-txholdcount 5 mstpctl-forcevers rstp mstpctl-maxhops 14 mstpctl-treeprio 32768 mstpctl-maxage 19 mstpctl-hello 3 mstpctl-ageing 200 auto swp42 iface swp42 mstpctl-portadminedge yes mstpctl-portbpdufilter yes mstpctl-portnetwork yes mstpctl-portautoedge yes mstpctl-treeportprio 127 mstpctl-portpathcost 10 mstpctl-portrestrtcn yes mstpctl-portrestrrole yes mstpctl-bpduguard yes mstpctl-treeportcost 100 mstpctl-portp2p yes auto swp43 iface swp43 mstpctl-portadminedge yes mstpctl-portbpdufilter yes mstpctl-portnetwork yes mstpctl-portautoedge yes mstpctl-treeportprio 127 mstpctl-portpathcost 10 mstpctl-portrestrtcn yes mstpctl-portrestrrole yes mstpctl-bpduguard yes mstpctl-treeportcost 100 mstpctl-portp2p yes root@dell-s3000-02:~# ifquery -ra auto swp42 iface swp42 mstpctl-portautoedge yes mstpctl-portbpdufilter yes mstpctl-portpathcost 10 mstpctl-treeportcost 100 mstpctl-portnetwork yes mstpctl-portadminedge yes mstpctl-portp2p yes mstpctl-portrestrrole yes mstpctl-portrestrtcn yes mstpctl-bpduguard yes link-speed 0 link-duplex half link-autoneg off auto swp43 iface swp43 mstpctl-portautoedge yes mstpctl-portbpdufilter yes mstpctl-portpathcost 10 mstpctl-treeportcost 100 mstpctl-portnetwork yes mstpctl-portadminedge yes mstpctl-portp2p yes mstpctl-portrestrrole yes mstpctl-portrestrtcn yes mstpctl-bpduguard yes link-speed 0 link-duplex half link-autoneg off auto br0 iface br0 vxlan-ageing 300 bridge-vlan-aware yes bridge-mcqifaddr 0 bridge-mcquerier 0 bridge-mcsnoop 1 bridge-mcrouter 1 bridge-stp yes bridge-ports swp43 swp42 mstpctl-portadminedge swp42=yes swp43=yes mstpctl-fdelay 14 mstpctl-portnetwork swp42=yes swp43=yes mstpctl-txholdcount 5 mstpctl-maxage 19 mstpctl-portbpdufilter swp42=yes swp43=yes mstpctl-maxhops 14 mstpctl-portrestrtcn swp42=yes swp43=yes mstpctl-portpathcost swp42=10 swp43=10 mstpctl-portautoedge swp42=yes swp43=yes mstpctl-hello 3 mstpctl-portrestrrole swp42=yes swp43=yes mstpctl-bpduguard swp42=yes swp43=yes mstpctl-ageing 200 mstpctl-treeportcost swp42=100 swp43=100 mstpctl-portp2p swp42=yes swp43=yes Signed-off-by: Nikhil <nikhil@cumulusnetworks.com>
2016-06-30 16:10:04 -07:00
'portbpdufilter' : 'bpdufilter-port',
'portpathcost' : 'external-port-cost',
'treeportcost' : 'internal-port-cost'}
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
@classmethod
def reset(cls):
cls._cache_fill_done = False
def is_mstpd_running(self):
try:
utils.exec_command('%s mstpd'%utils.pidof_cmd)
except:
return False
else:
return True
ifupdownaddons: mstpctl: treeportprio value is cached. It prevents ifupdown2 from executing mstpctl settreeportprio commands when the running value is the same as the one previously cached Ticket: CM-11773 Reviewed By: Roopa, Nikhil G Testing Done: smoke + hand testings : $ cat /etc/network/interfaces auto br2 iface br2 bridge-vlan-aware yes bridge-vids 100 bridge-pvid 1 bridge-ports swp1 swp4 swp5 bridge-stp on $ ifreload -a -v [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: executing /sbin/mstpctl showportdetail br2 json info: executing /sbin/mstpctl settreeportprio br2 swp1 0 128 info: br2: processing mstp config for port swp4 info: executing /sbin/mstpctl settreeportprio br2 swp4 0 128 info: br2: processing mstp config for port swp5 info: executing /sbin/mstpctl settreeportprio br2 swp5 0 128 info: netlink: set link br2 up [...] $ /sbin/mstpctl settreeportprio br2 swpX 0 128 is executed for every port. ifupdown2 tries to set this attr to 128 (the default value). This is a problem at scale. We shouldn't try to set this value if the running value is already 128. With the attached patch: $ ifreload -a [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: executing /sbin/mstpctl showportdetail br2 json info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: br2: processing mstp config for port swp4 info: br2: processing mstp config for port swp5 info: netlink: set link br2 up [...] $ Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
2016-08-01 09:49:08 +02:00
def _extract_bridge_port_prio(self, portid):
try:
return str(int(portid[0], 16) * 16)
except:
return mstpctlutil._DEFAULT_PORT_PRIO
ifupdownaddons: mstpctl: treeportprio value is cached. It prevents ifupdown2 from executing mstpctl settreeportprio commands when the running value is the same as the one previously cached Ticket: CM-11773 Reviewed By: Roopa, Nikhil G Testing Done: smoke + hand testings : $ cat /etc/network/interfaces auto br2 iface br2 bridge-vlan-aware yes bridge-vids 100 bridge-pvid 1 bridge-ports swp1 swp4 swp5 bridge-stp on $ ifreload -a -v [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: executing /sbin/mstpctl showportdetail br2 json info: executing /sbin/mstpctl settreeportprio br2 swp1 0 128 info: br2: processing mstp config for port swp4 info: executing /sbin/mstpctl settreeportprio br2 swp4 0 128 info: br2: processing mstp config for port swp5 info: executing /sbin/mstpctl settreeportprio br2 swp5 0 128 info: netlink: set link br2 up [...] $ /sbin/mstpctl settreeportprio br2 swpX 0 128 is executed for every port. ifupdown2 tries to set this attr to 128 (the default value). This is a problem at scale. We shouldn't try to set this value if the running value is already 128. With the attached patch: $ ifreload -a [...] info: netlink: set link swp1 up info: netlink: set link swp4 up info: netlink: set link swp5 up info: executing /sbin/mstpctl showportdetail br2 json info: br2: applying mstp configuration specific to ports info: br2: processing mstp config for port swp1 info: br2: processing mstp config for port swp4 info: br2: processing mstp config for port swp5 info: netlink: set link br2 up [...] $ Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
2016-08-01 09:49:08 +02:00
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
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))
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 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' % 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':
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
bridgename, portname, '0', value])
else:
utils.exec_commandl([utils.mstpctl_cmd, 'set%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 self._bridge_jsonAttr_map.items())
except Exception, 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':
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
'%s' % bridgename, '0', '%s' % attrvalue], stderr=None)
self.update_bridge_cache(bridgename, attrname, str(attrvalue))
else:
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
'%s' % bridgename, '%s' % attrvalue], stderr=None)
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.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):
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
utils.exec_commandl([utils.mstpctl_cmd,
'settreeprio', bridgename, '0',
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:
return False