2014-10-09 16:02:46 -07:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
|
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
|
|
#
|
|
|
|
|
2015-09-09 11:43:19 -07:00
|
|
|
import os
|
2014-10-09 16:02:46 -07:00
|
|
|
from sets import Set
|
|
|
|
from ifupdown.iface import *
|
|
|
|
from ifupdownaddons.modulebase import moduleBase
|
|
|
|
from ifupdownaddons.bridgeutils import brctl
|
|
|
|
from ifupdownaddons.iproute2 import iproute2
|
|
|
|
from ifupdownaddons.mstpctlutil import mstpctlutil
|
|
|
|
import traceback
|
|
|
|
|
2015-04-23 20:19:22 -04:00
|
|
|
class mstpctlFlags:
|
|
|
|
PORT_PROCESSED = 0x1
|
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
class mstpctl(moduleBase):
|
|
|
|
""" ifupdown2 addon module to configure mstp attributes """
|
|
|
|
|
|
|
|
_modinfo = {'mhelp' : 'mstp configuration module for bridges',
|
|
|
|
'attrs' : {
|
|
|
|
'mstpctl-ports' :
|
|
|
|
{'help' : 'mstp ports',
|
|
|
|
'compat' : True},
|
|
|
|
'mstpctl-stp' :
|
|
|
|
{'help': 'bridge stp yes/no',
|
|
|
|
'compat' : True,
|
|
|
|
'default' : 'no'},
|
|
|
|
'mstpctl-treeprio' :
|
|
|
|
{'help': 'tree priority',
|
|
|
|
'default' : '32768',
|
|
|
|
'validrange' : ['0', '65535'],
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-treeprio 32768']},
|
|
|
|
'mstpctl-ageing' :
|
|
|
|
{'help': 'ageing time',
|
|
|
|
'default' : '300',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-ageing 300']},
|
|
|
|
'mstpctl-maxage' :
|
|
|
|
{ 'help' : 'max message age',
|
|
|
|
'default' : '20',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-maxage 20']},
|
|
|
|
'mstpctl-fdelay' :
|
|
|
|
{ 'help' : 'set forwarding delay',
|
|
|
|
'default' : '15',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-fdelay 15']},
|
|
|
|
'mstpctl-maxhops' :
|
|
|
|
{ 'help' : 'bridge max hops',
|
|
|
|
'default' : '15',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-maxhops 15']},
|
|
|
|
'mstpctl-txholdcount' :
|
|
|
|
{ 'help' : 'bridge transmit holdcount',
|
|
|
|
'default' : '6',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-txholdcount 6']},
|
|
|
|
'mstpctl-forcevers' :
|
|
|
|
{ 'help' : 'bridge force stp version',
|
|
|
|
'default' : 'rstp',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-forcevers rstp']},
|
|
|
|
'mstpctl-portpathcost' :
|
|
|
|
{ 'help' : 'bridge port path cost',
|
|
|
|
'default' : '0',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portpathcost swp1=0 swp2=1']},
|
|
|
|
'mstpctl-portp2p' :
|
|
|
|
{ 'help' : 'bridge port p2p detection mode',
|
2014-11-08 06:14:56 -08:00
|
|
|
'default' : 'auto',
|
|
|
|
'validvals' : ['yes', 'no', 'auto'],
|
2014-10-09 16:02:46 -07:00
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portp2p swp1=no swp2=no']},
|
|
|
|
'mstpctl-portrestrrole' :
|
|
|
|
{ 'help' :
|
|
|
|
'enable/disable port ability to take root role of the port',
|
|
|
|
'default' : 'no',
|
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portrestrrole swp1=no swp2=no']},
|
|
|
|
'mstpctl-portrestrtcn' :
|
|
|
|
{ 'help' :
|
|
|
|
'enable/disable port ability to propagate received topology change notification of the port',
|
|
|
|
'default' : 'no',
|
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portrestrtcn swp1=no swp2=no']},
|
|
|
|
'mstpctl-bpduguard' :
|
|
|
|
{ 'help' :
|
|
|
|
'enable/disable bpduguard',
|
|
|
|
'default' : 'no',
|
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-bpduguard swp1=no swp2=no']},
|
|
|
|
'mstpctl-treeportprio' :
|
|
|
|
{ 'help' :
|
|
|
|
'port priority for MSTI instance',
|
|
|
|
'default' : '128',
|
|
|
|
'validrange' : ['0', '240'],
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-treeportprio swp1=128 swp2=128']},
|
|
|
|
'mstpctl-hello' :
|
|
|
|
{ 'help' : 'set hello time',
|
|
|
|
'default' : '2',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-hello 2']},
|
|
|
|
'mstpctl-portnetwork' :
|
|
|
|
{ 'help' : 'enable/disable bridge assurance capability for a port',
|
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'default' : 'no',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portnetwork swp1=no swp2=no']},
|
|
|
|
'mstpctl-portadminedge' :
|
|
|
|
{ 'help' : 'enable/disable initial edge state of the port',
|
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'default' : 'no',
|
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portadminedge swp1=no swp2=no']},
|
|
|
|
'mstpctl-portautoedge' :
|
|
|
|
{ 'help' : 'enable/disable auto transition to/from edge state of the port',
|
|
|
|
'validvals' : ['yes', 'no'],
|
2015-04-27 15:38:07 -07:00
|
|
|
'default' : 'yes',
|
2014-10-09 16:02:46 -07:00
|
|
|
'required' : False,
|
|
|
|
'example' : ['mstpctl-portautoedge swp1=yes swp2=yes']},
|
|
|
|
'mstpctl-treeportcost' :
|
|
|
|
{ 'help' : 'port tree cost',
|
|
|
|
'required' : False},
|
|
|
|
'mstpctl-portbpdufilter' :
|
2014-10-31 11:28:07 -07:00
|
|
|
{ 'help' : 'enable/disable bpdu filter on a port. ' +
|
|
|
|
'syntax varies when defined under a bridge ' +
|
|
|
|
'vs under a port',
|
2014-10-09 16:02:46 -07:00
|
|
|
'validvals' : ['yes', 'no'],
|
|
|
|
'default' : 'no',
|
|
|
|
'required' : False,
|
2014-10-31 11:28:07 -07:00
|
|
|
'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
|
|
|
|
'under a port: mstpctl-portbpdufilter yes']},
|
2014-10-09 16:02:46 -07:00
|
|
|
}}
|
|
|
|
|
2014-11-19 14:42:14 -08:00
|
|
|
# Maps mstp bridge attribute names to corresponding mstpctl commands
|
|
|
|
# XXX: This can be encoded in the modules dict above
|
|
|
|
_attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
|
|
|
|
('mstpctl-ageing' , 'ageing'),
|
|
|
|
('mstpctl-maxage' , 'maxage'),
|
|
|
|
('mstpctl-fdelay' , 'fdelay'),
|
|
|
|
('mstpctl-maxhops' , 'maxhops'),
|
|
|
|
('mstpctl-txholdcount' , 'txholdcount'),
|
|
|
|
('mstpctl-forcevers', 'forcevers'),
|
|
|
|
('mstpctl-hello' , 'hello')])
|
|
|
|
|
|
|
|
# Maps mstp port attribute names to corresponding mstpctl commands
|
|
|
|
# XXX: This can be encoded in the modules dict above
|
2014-10-28 16:10:00 -07:00
|
|
|
_port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
|
|
|
|
'mstpctl-portadminedge' : 'portadminedge',
|
2014-11-15 15:42:52 -08:00
|
|
|
'mstpctl-portautoedge' : 'portautoedge' ,
|
2014-10-28 16:10:00 -07:00
|
|
|
'mstpctl-portp2p' : 'portp2p',
|
|
|
|
'mstpctl-portrestrrole' : 'portrestrrole',
|
|
|
|
'mstpctl-portrestrtcn' : 'portrestrtcn',
|
2014-10-09 16:02:46 -07:00
|
|
|
'mstpctl-bpduguard' : 'bpduguard',
|
2014-10-28 16:10:00 -07:00
|
|
|
'mstpctl-treeportprio' : 'treeportprio',
|
|
|
|
'mstpctl-treeportcost' : 'treeportcost',
|
|
|
|
'mstpctl-portnetwork' : 'portnetwork',
|
|
|
|
'mstpctl-portbpdufilter' : 'portbpdufilter'}
|
2014-10-09 16:02:46 -07:00
|
|
|
|
|
|
|
def __init__(self, *args, **kargs):
|
|
|
|
moduleBase.__init__(self, *args, **kargs)
|
|
|
|
self.ipcmd = None
|
2015-04-23 20:19:22 -04:00
|
|
|
self.name = self.__class__.__name__
|
2014-10-09 16:02:46 -07:00
|
|
|
self.brctlcmd = None
|
|
|
|
self.mstpctlcmd = None
|
|
|
|
|
|
|
|
def _is_bridge(self, ifaceobj):
|
|
|
|
if (ifaceobj.get_attr_value_first('mstpctl-ports') or
|
2014-10-24 10:11:07 -07:00
|
|
|
ifaceobj.get_attr_value_first('bridge-ports')):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _is_bridge_port(self, ifaceobj):
|
|
|
|
if self.brctlcmd.is_bridge_port(ifaceobj.name):
|
2014-10-09 16:02:46 -07:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
|
|
|
|
if not self._is_bridge(ifaceobj):
|
|
|
|
return None
|
|
|
|
return self.parse_port_list(ifaceobj.get_attr_value_first(
|
|
|
|
'mstpctl-ports'), ifacenames_all)
|
|
|
|
|
|
|
|
def get_dependent_ifacenames_running(self, ifaceobj):
|
|
|
|
self._init_command_handlers()
|
|
|
|
if (self.brctlcmd.bridge_exists(ifaceobj.name) and
|
|
|
|
not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
|
|
|
|
return None
|
|
|
|
return self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
|
|
|
|
|
|
|
def _get_bridge_port_list(self, ifaceobj):
|
|
|
|
|
|
|
|
# port list is also available in the previously
|
|
|
|
# parsed dependent list. Use that if available, instead
|
|
|
|
# of parsing port expr again
|
|
|
|
port_list = ifaceobj.lowerifaces
|
|
|
|
if port_list:
|
|
|
|
return port_list
|
|
|
|
ports = ifaceobj.get_attr_value_first('mstpctl-ports')
|
|
|
|
if ports:
|
|
|
|
return self.parse_port_list(ports)
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
2015-01-03 22:35:45 -08:00
|
|
|
def _ports_enable_disable_ipv6(self, ports, enable='1'):
|
|
|
|
for p in ports:
|
|
|
|
try:
|
|
|
|
self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
|
|
|
|
'/disable_ipv6', enable)
|
|
|
|
except Exception, e:
|
|
|
|
self.logger.info(str(e))
|
|
|
|
pass
|
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
def _add_ports(self, ifaceobj):
|
|
|
|
bridgeports = self._get_bridge_port_list(ifaceobj)
|
|
|
|
|
|
|
|
runningbridgeports = []
|
|
|
|
# Delete active ports not in the new port list
|
|
|
|
if not self.PERFMODE:
|
|
|
|
runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
|
|
|
if runningbridgeports:
|
|
|
|
[self.ipcmd.link_set(bport, 'nomaster')
|
|
|
|
for bport in runningbridgeports
|
|
|
|
if not bridgeports or bport not in bridgeports]
|
|
|
|
else:
|
|
|
|
runningbridgeports = []
|
|
|
|
if not bridgeports:
|
|
|
|
return
|
|
|
|
err = 0
|
|
|
|
for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
|
|
|
|
try:
|
|
|
|
if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
|
|
|
|
self.log_warn('%s: bridge port %s does not exist'
|
|
|
|
%(ifaceobj.name, bridgeport))
|
|
|
|
err += 1
|
|
|
|
continue
|
|
|
|
self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
|
|
|
|
self.ipcmd.addr_flush(bridgeport)
|
|
|
|
except Exception, e:
|
|
|
|
self.log_error(str(e))
|
2015-01-03 22:35:45 -08:00
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
if err:
|
|
|
|
self.log_error('error configuring bridge (missing ports)')
|
|
|
|
|
|
|
|
def _apply_bridge_settings(self, ifaceobj):
|
|
|
|
check = False if self.PERFMODE else True
|
|
|
|
try:
|
2014-11-19 14:42:14 -08:00
|
|
|
# set bridge attributes
|
|
|
|
for attrname, dstattrname in self._attrs_map.items():
|
|
|
|
try:
|
|
|
|
v = ifaceobj.get_attr_value_first(attrname)
|
|
|
|
if not v:
|
|
|
|
continue
|
|
|
|
if attrname == 'mstpctl-treeprio':
|
|
|
|
self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
|
|
|
|
v, check)
|
|
|
|
else:
|
|
|
|
self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
|
|
|
|
dstattrname, v, check)
|
|
|
|
except Exception, e:
|
|
|
|
self.logger.warn('%s' %str(e))
|
|
|
|
pass
|
2014-10-09 16:02:46 -07:00
|
|
|
|
|
|
|
# set bridge port attributes
|
2014-11-19 14:42:14 -08:00
|
|
|
for attrname, dstattrname in self._port_attrs_map.items():
|
2014-10-09 16:02:46 -07:00
|
|
|
attrval = ifaceobj.get_attr_value_first(attrname)
|
|
|
|
if not attrval:
|
|
|
|
continue
|
|
|
|
portlist = self.parse_port_list(attrval)
|
|
|
|
if not portlist:
|
|
|
|
self.log_warn('%s: error parsing \'%s %s\''
|
|
|
|
%(ifaceobj.name, attrname, attrval))
|
|
|
|
continue
|
|
|
|
for p in portlist:
|
|
|
|
try:
|
|
|
|
(port, val) = p.split('=')
|
2015-09-09 11:43:19 -07:00
|
|
|
# if it is not bridge port, continue
|
|
|
|
if not os.path.exists('/sys/class/net/%s/brport' %port):
|
|
|
|
continue
|
2014-10-09 16:02:46 -07:00
|
|
|
self.mstpctlcmd.set_bridgeport_attr(ifaceobj.name,
|
|
|
|
port, dstattrname, val, check)
|
|
|
|
except Exception, e:
|
|
|
|
self.log_warn('%s: error setting %s (%s)'
|
|
|
|
%(ifaceobj.name, attrname, str(e)))
|
|
|
|
except Exception, e:
|
|
|
|
self.log_warn(str(e))
|
|
|
|
pass
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
|
2014-11-15 15:42:52 -08:00
|
|
|
bridgeifaceobj=None, stp_on=True,
|
|
|
|
mstpd_running=True):
|
2014-10-09 16:02:46 -07:00
|
|
|
check = False if self.PERFMODE else True
|
2014-10-24 10:11:07 -07:00
|
|
|
if not bridgename and bridgeifaceobj:
|
|
|
|
bridgename = bridgeifaceobj.name
|
|
|
|
# set bridge port attributes
|
|
|
|
for attrname, dstattrname in self._port_attrs_map.items():
|
|
|
|
attrval = ifaceobj.get_attr_value_first(attrname)
|
|
|
|
if not attrval:
|
2014-10-24 14:21:54 -07:00
|
|
|
#if bridgeifaceobj:
|
|
|
|
# # If bridge object available, check if the bridge
|
|
|
|
# # has the attribute set, in which case,
|
|
|
|
# # inherit it from the bridge
|
|
|
|
# attrval = bridgeifaceobj.get_attr_value_first(attrname)
|
|
|
|
# if not attrval:
|
|
|
|
# continue
|
|
|
|
#else:
|
|
|
|
continue
|
2014-11-15 15:42:52 -08:00
|
|
|
if not stp_on:
|
|
|
|
self.logger.warn('%s: cannot set %s (stp on bridge %s not on)\n'
|
|
|
|
%(ifaceobj.name, attrname, bridgename))
|
|
|
|
continue
|
|
|
|
if not mstpd_running:
|
|
|
|
continue
|
2015-09-09 11:43:19 -07:00
|
|
|
# if its not a bridge port, continue
|
|
|
|
if not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name):
|
|
|
|
continue
|
2014-10-24 10:11:07 -07:00
|
|
|
try:
|
|
|
|
self.mstpctlcmd.set_bridgeport_attr(bridgename,
|
|
|
|
ifaceobj.name, dstattrname, attrval, check)
|
|
|
|
except Exception, e:
|
|
|
|
self.log_warn('%s: error setting %s (%s)'
|
|
|
|
%(ifaceobj.name, attrname, str(e)))
|
|
|
|
|
|
|
|
def _apply_bridge_port_settings_all(self, ifaceobj,
|
|
|
|
ifaceobj_getfunc=None):
|
2014-10-29 12:51:21 -07:00
|
|
|
self.logger.info('%s: applying mstp configuration '
|
2014-10-24 10:11:07 -07:00
|
|
|
%ifaceobj.name + 'specific to ports')
|
2014-12-27 20:29:44 -08:00
|
|
|
# Query running bridge ports. and only apply attributes on them
|
|
|
|
bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
2014-11-19 14:42:14 -08:00
|
|
|
if not bridgeports:
|
|
|
|
self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
|
|
|
|
return
|
2014-10-24 10:11:07 -07:00
|
|
|
for bport in bridgeports:
|
2014-10-29 12:51:21 -07:00
|
|
|
self.logger.info('%s: processing mstp config for port %s'
|
2014-10-24 10:11:07 -07:00
|
|
|
%(ifaceobj.name, bport))
|
2014-12-01 14:54:12 -08:00
|
|
|
if not self.ipcmd.link_exists(bport):
|
|
|
|
continue
|
2015-09-09 11:43:19 -07:00
|
|
|
if not os.path.exists('/sys/class/net/%s/brport' %bport):
|
|
|
|
continue
|
2014-10-24 10:11:07 -07:00
|
|
|
bportifaceobjlist = ifaceobj_getfunc(bport)
|
|
|
|
if not bportifaceobjlist:
|
|
|
|
continue
|
|
|
|
for bportifaceobj in bportifaceobjlist:
|
2014-10-29 12:51:21 -07:00
|
|
|
# Dont process bridge port if it already has been processed
|
2015-04-23 20:19:22 -04:00
|
|
|
if (bportifaceobj.module_flags.get(self.name,0x0) & \
|
|
|
|
mstpctlFlags.PORT_PROCESSED):
|
2014-10-29 12:51:21 -07:00
|
|
|
continue
|
2014-10-09 16:02:46 -07:00
|
|
|
try:
|
2014-10-24 10:11:07 -07:00
|
|
|
self._apply_bridge_port_settings(bportifaceobj,
|
|
|
|
ifaceobj.name, ifaceobj)
|
2014-10-09 16:02:46 -07:00
|
|
|
except Exception, e:
|
2014-10-24 10:11:07 -07:00
|
|
|
self.log_warn(str(e))
|
2014-10-09 16:02:46 -07:00
|
|
|
|
Fix mstp settings ordering issues when bridge stp is toggled on and off
(when mstp settings are specified under the port)
Ticket: CM-6626
Reviewed By: CCR-3599
Testing Done: Tested the problem case mentioned in the bug (Plan to
re-work the fix a bit for 2.5.5)
problem:
mstp parameters can be specified under the port or under the bridge
When they are specified under the bridge, there should be no problem
(When you process the bridge, all things on the bridge port are set in
order)
When they are specified under the port:
we check if the bridge is up, if yes, and stp is already configured,
we process mstpctl settings
This check today only checks running stp_state
We should also check the user configured stp state for the bridge
Note that the problem exists only if the bridge and ports are
already up and user executes ifup again and when we need to re-evaluate
the bridge port settings
solution:
When the bridge port is being checked for mstp settings, not only
check running stp state, but also check user specified stp state and
correct bridge stp state before proceeding with mstp configuration
Few things to note with this patch:
- If user changed stp state on bridge to 'on', and did `ifup
<bridge_port>'`,
though the user has not ifup'ed the bridge yet, the bridge stp state
will be applied (very few people will run into this and practically this
should not be a problem atall. But from correctness POV it is
a voilation. ).
- To avoid this, the other solution would have been to let the bridge
port code be as is, but handle this during bringing up the bridge,
but, this can confuse the user, because when processing the
bridge_port, you will still throw warnings even if the port stp config
is later reapplied when the bridge comes up
- note that the patch only handles the case when stp state is not on and
somebody turned it on. For the case where stp state was on and somebody
turned it off, this patch wont throw warnings for the mstpctl config. But
it will not cause any issues because once stp is off things will be ok
everywhere. I want to keep any changes here out of this patch. I will
document this in the bug...and see if i can handle this in 2.5.5
2015-09-29 10:12:07 -07:00
|
|
|
def _is_stp_on(self, ifaceobj, bridgename, ifaceobj_getfunc=None):
|
|
|
|
# Check if running stp state is on
|
|
|
|
running_stp_state = (True if self.read_file_oneline(
|
|
|
|
'/sys/class/net/%s/bridge/stp_state'
|
|
|
|
%bridgename) == '2' else False)
|
|
|
|
if not running_stp_state:
|
|
|
|
# If running stp is not on, and bridge has stp configured
|
|
|
|
# set stp on bridge
|
|
|
|
if ifaceobj_getfunc:
|
|
|
|
bridgeifaceobjlist = ifaceobj_getfunc(bridgename)
|
|
|
|
if not bridgeifaceobjlist:
|
|
|
|
return running_stp_state
|
|
|
|
for b in bridgeifaceobjlist:
|
|
|
|
stp_attrval = b.get_attr_value_first('bridge-stp')
|
|
|
|
if stp_attrval and (stp_attrval == 'on' or
|
|
|
|
stp_attrval == 'yes'):
|
|
|
|
# set stp on bridge and return True
|
|
|
|
self.brctlcmd.set_stp(bridgename, stp_attrval)
|
|
|
|
return True
|
|
|
|
return running_stp_state
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def _up(self, ifaceobj, ifaceobj_getfunc=None):
|
2014-10-09 16:02:46 -07:00
|
|
|
# Check if bridge port
|
2014-10-29 12:51:21 -07:00
|
|
|
bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
|
|
|
|
if bridgename:
|
2014-11-15 15:42:52 -08:00
|
|
|
mstpd_running = (True if self.mstpctlcmd.is_mstpd_running()
|
|
|
|
else False)
|
Fix mstp settings ordering issues when bridge stp is toggled on and off
(when mstp settings are specified under the port)
Ticket: CM-6626
Reviewed By: CCR-3599
Testing Done: Tested the problem case mentioned in the bug (Plan to
re-work the fix a bit for 2.5.5)
problem:
mstp parameters can be specified under the port or under the bridge
When they are specified under the bridge, there should be no problem
(When you process the bridge, all things on the bridge port are set in
order)
When they are specified under the port:
we check if the bridge is up, if yes, and stp is already configured,
we process mstpctl settings
This check today only checks running stp_state
We should also check the user configured stp state for the bridge
Note that the problem exists only if the bridge and ports are
already up and user executes ifup again and when we need to re-evaluate
the bridge port settings
solution:
When the bridge port is being checked for mstp settings, not only
check running stp state, but also check user specified stp state and
correct bridge stp state before proceeding with mstp configuration
Few things to note with this patch:
- If user changed stp state on bridge to 'on', and did `ifup
<bridge_port>'`,
though the user has not ifup'ed the bridge yet, the bridge stp state
will be applied (very few people will run into this and practically this
should not be a problem atall. But from correctness POV it is
a voilation. ).
- To avoid this, the other solution would have been to let the bridge
port code be as is, but handle this during bringing up the bridge,
but, this can confuse the user, because when processing the
bridge_port, you will still throw warnings even if the port stp config
is later reapplied when the bridge comes up
- note that the patch only handles the case when stp state is not on and
somebody turned it on. For the case where stp state was on and somebody
turned it off, this patch wont throw warnings for the mstpctl config. But
it will not cause any issues because once stp is off things will be ok
everywhere. I want to keep any changes here out of this patch. I will
document this in the bug...and see if i can handle this in 2.5.5
2015-09-29 10:12:07 -07:00
|
|
|
stp_on = self._is_stp_on(ifaceobj, bridgename, ifaceobj_getfunc)
|
2014-11-15 15:42:52 -08:00
|
|
|
self._apply_bridge_port_settings(ifaceobj, bridgename, None,
|
|
|
|
stp_on, mstpd_running)
|
2015-04-23 20:19:22 -04:00
|
|
|
ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \
|
|
|
|
mstpctlFlags.PORT_PROCESSED
|
2014-10-09 16:02:46 -07:00
|
|
|
return
|
2014-10-09 19:10:20 -07:00
|
|
|
if not self._is_bridge(ifaceobj):
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
stp = None
|
|
|
|
try:
|
|
|
|
porterr = False
|
|
|
|
porterrstr = ''
|
|
|
|
if ifaceobj.get_attr_value_first('mstpctl-ports'):
|
|
|
|
# If bridge ports specified with mstpctl attr, create the
|
|
|
|
# bridge and also add its ports
|
|
|
|
self.ipcmd.batch_start()
|
|
|
|
if not self.PERFMODE:
|
|
|
|
if not self.ipcmd.link_exists(ifaceobj.name):
|
|
|
|
self.ipcmd.link_create(ifaceobj.name, 'bridge')
|
|
|
|
else:
|
|
|
|
self.ipcmd.link_create(ifaceobj.name, 'bridge')
|
|
|
|
try:
|
|
|
|
self._add_ports(ifaceobj)
|
|
|
|
except Exception, e:
|
|
|
|
porterr = True
|
|
|
|
porterrstr = str(e)
|
|
|
|
pass
|
|
|
|
finally:
|
|
|
|
self.ipcmd.batch_commit()
|
2015-01-03 22:35:45 -08:00
|
|
|
running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
|
|
|
if running_ports:
|
|
|
|
# disable ipv6 for ports that were added to bridge
|
|
|
|
self._ports_enable_disable_ipv6(running_ports, '1')
|
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
stp = ifaceobj.get_attr_value_first('mstpctl-stp')
|
|
|
|
if stp:
|
|
|
|
self.set_iface_attr(ifaceobj, 'mstpctl-stp',
|
|
|
|
self.brctlcmd.set_stp)
|
|
|
|
else:
|
|
|
|
stp = self.brctlcmd.get_stp(ifaceobj.name)
|
|
|
|
if (self.mstpctlcmd.is_mstpd_running() and
|
|
|
|
(stp == 'yes' or stp == 'on')):
|
|
|
|
self._apply_bridge_settings(ifaceobj)
|
2014-10-24 10:11:07 -07:00
|
|
|
self._apply_bridge_port_settings_all(ifaceobj,
|
|
|
|
ifaceobj_getfunc=ifaceobj_getfunc)
|
2014-10-09 16:02:46 -07:00
|
|
|
except Exception, e:
|
|
|
|
self.log_error(str(e))
|
|
|
|
if porterr:
|
|
|
|
raise Exception(porterrstr)
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def _down(self, ifaceobj, ifaceobj_getfunc=None):
|
|
|
|
if not self._is_bridge(ifaceobj):
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
try:
|
|
|
|
if ifaceobj.get_attr_value_first('mstpctl-ports'):
|
|
|
|
# If bridge ports specified with mstpctl attr, delete the
|
|
|
|
# bridge
|
|
|
|
ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
|
|
|
if ports:
|
2015-01-03 22:35:45 -08:00
|
|
|
self._ports_enable_disable_ipv6(ports, '0')
|
2014-10-09 16:02:46 -07:00
|
|
|
self.brctlcmd.delete_bridge(ifaceobj.name)
|
|
|
|
except Exception, e:
|
|
|
|
self.log_error(str(e))
|
|
|
|
|
|
|
|
def _query_running_attrs(self, ifaceobjrunning):
|
|
|
|
bridgeattrdict = {}
|
|
|
|
|
|
|
|
tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
|
|
|
|
if not tmpbridgeattrdict:
|
|
|
|
return bridgeattrdict
|
|
|
|
|
|
|
|
for k,v in tmpbridgeattrdict.items():
|
|
|
|
if k == 'stp' or not v:
|
|
|
|
continue
|
|
|
|
if k == 'ports':
|
|
|
|
ports = v.keys()
|
|
|
|
continue
|
|
|
|
attrname = 'mstpctl-' + k
|
|
|
|
if v and v != self.get_mod_subattr(attrname, 'default'):
|
|
|
|
bridgeattrdict[attrname] = [v]
|
|
|
|
|
|
|
|
ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
|
|
|
|
if ports:
|
|
|
|
portconfig = {'mstpctl-portnetwork' : '',
|
|
|
|
'mstpctl-portpathcost' : '',
|
|
|
|
'mstpctl-portadminedge' : '',
|
|
|
|
'mstpctl-portautoedge' : '',
|
|
|
|
'mstpctl-portp2p' : '',
|
|
|
|
'mstpctl-portrestrrole' : '',
|
|
|
|
'mstpctl-portrestrtcn' : '',
|
|
|
|
'mstpctl-bpduguard' : '',
|
|
|
|
'mstpctl-treeportprio' : '',
|
|
|
|
'mstpctl-treeportcost' : ''}
|
|
|
|
|
|
|
|
for p in ports:
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'portnetwork')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-portnetwork'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
# XXX: Can we really get path cost of a port ???
|
|
|
|
#v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-portpathcost',
|
|
|
|
# 'default'):
|
|
|
|
# portconfig['mstpctl-portpathcost'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'portadminedge')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-portadminedge'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'portp2p')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-portp2p'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'portrestrrole')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-portrestrrole'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'portrestrtcn')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-portrestrtcn'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
p, 'bpduguard')
|
|
|
|
if v and v != 'no':
|
|
|
|
portconfig['mstpctl-bpduguard'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
# XXX: Can we really get path cost of a port ???
|
|
|
|
#v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
# p, 'treeprio')
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-treeportprio',
|
|
|
|
# 'default'):
|
|
|
|
# portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
#v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
# p, 'treecost')
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-treeportcost',
|
|
|
|
# 'default'):
|
|
|
|
# portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
bridgeattrdict.update({k : [v] for k, v in portconfig.items()
|
|
|
|
if v})
|
|
|
|
return bridgeattrdict
|
|
|
|
|
|
|
|
def _query_check_bridge(self, ifaceobj, ifaceobjcurr):
|
|
|
|
# list of attributes that are not supported currently
|
|
|
|
blacklistedattrs = ['mstpctl-portpathcost',
|
|
|
|
'mstpctl-treeportprio', 'mstpctl-treeportcost']
|
|
|
|
if not self.brctlcmd.bridge_exists(ifaceobj.name):
|
|
|
|
self.logger.debug('bridge %s does not exist' %ifaceobj.name)
|
|
|
|
return
|
|
|
|
ifaceattrs = self.dict_key_subset(ifaceobj.config,
|
|
|
|
self.get_mod_attrs())
|
|
|
|
if not ifaceattrs:
|
|
|
|
return
|
|
|
|
runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
|
|
|
|
if not runningattrs:
|
|
|
|
runningattrs = {}
|
|
|
|
for k in ifaceattrs:
|
|
|
|
# for all mstpctl options
|
|
|
|
if k in blacklistedattrs:
|
|
|
|
continue
|
|
|
|
# get the corresponding ifaceobj attr
|
|
|
|
v = ifaceobj.get_attr_value_first(k)
|
|
|
|
if not v:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Get the running attribute
|
|
|
|
rv = runningattrs.get(k[8:])
|
|
|
|
if k == 'mstpctl-stp':
|
|
|
|
# special case stp compare because it may
|
|
|
|
# contain more than one valid values
|
|
|
|
stp_on_vals = ['on', 'yes']
|
|
|
|
stp_off_vals = ['off']
|
|
|
|
rv = self.brctlcmd.get_stp(ifaceobj.name)
|
|
|
|
if ((v in stp_on_vals and rv in stp_on_vals) or
|
|
|
|
(v in stp_off_vals and rv in stp_off_vals)):
|
|
|
|
ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if k == 'mstpctl-ports':
|
|
|
|
# special case ports because it can contain regex or glob
|
|
|
|
# XXX: We get all info from mstputils, which means if
|
|
|
|
# mstpd is down, we will not be returning any bridge bridgeports
|
|
|
|
running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
|
|
|
bridge_port_list = self._get_bridge_port_list(ifaceobj)
|
|
|
|
if not running_port_list and not bridge_port_list:
|
|
|
|
continue
|
|
|
|
portliststatus = 1
|
|
|
|
if running_port_list and bridge_port_list:
|
|
|
|
difference = Set(running_port_list).symmetric_difference(
|
|
|
|
Set(bridge_port_list))
|
|
|
|
if not difference:
|
|
|
|
portliststatus = 0
|
|
|
|
ifaceobjcurr.update_config_with_status('mstpctl-ports',
|
|
|
|
' '.join(running_port_list)
|
|
|
|
if running_port_list else '', portliststatus)
|
|
|
|
elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
|
|
|
|
# Now, look at port attributes
|
|
|
|
# derive the mstpctlcmd attr name
|
|
|
|
#mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
|
|
|
|
mstpctlcmdattrname = k[8:]
|
|
|
|
|
|
|
|
# for port attributes, the attributes are in a list
|
|
|
|
# <portname>=<portattrvalue>
|
|
|
|
status = 0
|
|
|
|
currstr = ''
|
|
|
|
vlist = self.parse_port_list(v)
|
|
|
|
if not vlist:
|
|
|
|
continue
|
|
|
|
for vlistitem in vlist:
|
|
|
|
try:
|
|
|
|
(p, v) = vlistitem.split('=')
|
|
|
|
currv = self.mstpctlcmd.get_bridgeport_attr(
|
|
|
|
ifaceobj.name, p, mstpctlcmdattrname)
|
|
|
|
if currv:
|
|
|
|
currstr += ' %s=%s' %(p, currv)
|
|
|
|
else:
|
|
|
|
currstr += ' %s=%s' %(p, 'None')
|
|
|
|
if currv != v:
|
|
|
|
status = 1
|
|
|
|
except Exception, e:
|
|
|
|
self.log_warn(str(e))
|
|
|
|
pass
|
|
|
|
ifaceobjcurr.update_config_with_status(k, currstr, status)
|
|
|
|
elif not rv:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, '', 1)
|
|
|
|
elif v != rv:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, rv, 1)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, rv, 0)
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
|
2014-11-04 11:31:30 -08:00
|
|
|
if not self.ipcmd.link_exists(ifaceobj.name):
|
2014-12-01 14:54:12 -08:00
|
|
|
#self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
|
2014-10-09 16:02:46 -07:00
|
|
|
ifaceobjcurr.status = ifaceStatus.NOTFOUND
|
|
|
|
return
|
2014-10-28 16:10:00 -07:00
|
|
|
# Check if this is a bridge port
|
2014-11-04 11:31:30 -08:00
|
|
|
if not self._is_bridge_port(ifaceobj):
|
2014-10-28 16:10:00 -07:00
|
|
|
# mark all the bridge attributes as error
|
2014-12-17 12:39:38 -08:00
|
|
|
ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
|
2014-10-28 16:10:00 -07:00
|
|
|
self._port_attrs_map.keys(), 0)
|
|
|
|
return
|
2014-10-29 12:51:21 -07:00
|
|
|
bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
|
2014-10-28 16:10:00 -07:00
|
|
|
# list of attributes that are not supported currently
|
2014-11-19 17:25:26 -08:00
|
|
|
blacklistedattrs = ['mstpctl-portpathcost',
|
|
|
|
'mstpctl-treeportprio', 'mstpctl-treeportcost']
|
2014-10-09 16:02:46 -07:00
|
|
|
ifaceattrs = self.dict_key_subset(ifaceobj.config,
|
|
|
|
self._port_attrs_map.keys())
|
|
|
|
if not ifaceattrs:
|
|
|
|
return
|
|
|
|
runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
|
|
|
|
if not runningattrs:
|
|
|
|
runningattrs = {}
|
|
|
|
for k in ifaceattrs:
|
|
|
|
# for all mstpctl options
|
|
|
|
# get the corresponding ifaceobj attr
|
|
|
|
v = ifaceobj.get_attr_value_first(k)
|
2014-11-19 17:25:26 -08:00
|
|
|
if not v or k in blacklistedattrs:
|
2014-10-28 16:10:00 -07:00
|
|
|
ifaceobjcurr.update_config_with_status(k, v, -1)
|
2014-10-09 16:02:46 -07:00
|
|
|
continue
|
2014-10-28 16:10:00 -07:00
|
|
|
currv = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
2014-10-09 16:02:46 -07:00
|
|
|
ifaceobj.name, self._port_attrs_map.get(k))
|
|
|
|
if currv:
|
|
|
|
if currv != v:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, currv, 1)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, currv, 0)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status(k, None, 1)
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
|
2014-10-28 16:10:00 -07:00
|
|
|
if self._is_bridge(ifaceobj):
|
2014-10-24 10:11:07 -07:00
|
|
|
self._query_check_bridge(ifaceobj, ifaceobjcurr)
|
2014-10-28 16:10:00 -07:00
|
|
|
else:
|
|
|
|
self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
|
2014-10-09 16:02:46 -07:00
|
|
|
|
2014-10-28 16:10:00 -07:00
|
|
|
def _query_running_bridge_port(self, ifaceobjrunning):
|
|
|
|
bridgename = self.ipcmd.bridge_port_get_bridge_name(
|
|
|
|
ifaceobjrunning.name)
|
|
|
|
if not bridgename:
|
|
|
|
self.logger.warn('%s: unable to determine bridgename'
|
|
|
|
%ifaceobjrunning.name)
|
2014-10-09 16:02:46 -07:00
|
|
|
return
|
2014-10-28 16:10:00 -07:00
|
|
|
if self.brctlcmd.get_stp(bridgename) == 'no':
|
|
|
|
# This bridge does not run stp, return
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
# if userspace stp not set, return
|
|
|
|
if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
|
2014-10-28 16:10:00 -07:00
|
|
|
return
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name,
|
|
|
|
'portnetwork')
|
|
|
|
if v and v != 'no':
|
|
|
|
ifaceobjrunning.update_config('mstpctl-network', v)
|
|
|
|
|
|
|
|
# XXX: Can we really get path cost of a port ???
|
|
|
|
#v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-pathcost',
|
|
|
|
# 'default'):
|
|
|
|
# ifaceobjrunning.update_config('mstpctl-network', v)
|
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name, 'portadminedge')
|
|
|
|
if v and v != 'no':
|
2014-11-06 16:10:21 -08:00
|
|
|
ifaceobjrunning.update_config('mstpctl-portadminedge', v)
|
2014-10-28 16:10:00 -07:00
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name,'portp2p')
|
2014-11-08 06:14:56 -08:00
|
|
|
if v and v != 'auto':
|
2014-11-06 16:10:21 -08:00
|
|
|
ifaceobjrunning.update_config('mstpctl-portp2p', v)
|
2014-10-28 16:10:00 -07:00
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name, 'portrestrrole')
|
|
|
|
if v and v != 'no':
|
2014-11-06 16:10:21 -08:00
|
|
|
ifaceobjrunning.update_config('mstpctl-portrestrrole', v)
|
2014-10-28 16:10:00 -07:00
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name, 'restrtcn')
|
|
|
|
if v and v != 'no':
|
2014-11-06 16:10:21 -08:00
|
|
|
ifaceobjrunning.update_config('mstpctl-portrestrtcn', v)
|
2014-10-28 16:10:00 -07:00
|
|
|
|
|
|
|
v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
|
|
|
|
ifaceobjrunning.name, 'bpduguard')
|
|
|
|
if v and v != 'no':
|
|
|
|
ifaceobjrunning.update_config('mstpctl-bpduguard', v)
|
|
|
|
|
|
|
|
# XXX: Can we really get path cost of a port ???
|
|
|
|
#v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
# p, 'treeprio')
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-treeportprio',
|
|
|
|
# 'default'):
|
|
|
|
# portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
#v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
|
|
|
|
# p, 'treecost')
|
|
|
|
#if v and v != self.get_mod_subattr('mstpctl-treeportcost',
|
|
|
|
# 'default'):
|
|
|
|
# portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
|
|
|
|
|
|
|
|
def _query_running_bridge(self, ifaceobjrunning):
|
|
|
|
if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
|
|
|
|
# This bridge does not run stp, return
|
|
|
|
return
|
|
|
|
# if userspace stp not set, return
|
|
|
|
if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
# Check if mstp really knows about this bridge
|
|
|
|
if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
|
|
|
|
return
|
|
|
|
ifaceobjrunning.update_config_dict(self._query_running_attrs(
|
|
|
|
ifaceobjrunning))
|
|
|
|
|
2014-10-28 16:10:00 -07:00
|
|
|
def _query_running(self, ifaceobjrunning, **extra_args):
|
|
|
|
if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
|
|
|
|
self._query_running_bridge(ifaceobjrunning)
|
|
|
|
elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
|
|
|
|
self._query_running_bridge_port(ifaceobjrunning)
|
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
_run_ops = {'pre-up' : _up,
|
|
|
|
'post-down' : _down,
|
|
|
|
'query-checkcurr' : _query_check,
|
|
|
|
'query-running' : _query_running}
|
|
|
|
|
|
|
|
def get_ops(self):
|
|
|
|
""" returns list of ops supported by this module """
|
|
|
|
return self._run_ops.keys()
|
|
|
|
|
|
|
|
def _init_command_handlers(self):
|
|
|
|
flags = self.get_flags()
|
|
|
|
if not self.ipcmd:
|
|
|
|
self.ipcmd = iproute2(**flags)
|
|
|
|
if not self.brctlcmd:
|
|
|
|
self.brctlcmd = brctl(**flags)
|
|
|
|
if not self.mstpctlcmd:
|
|
|
|
self.mstpctlcmd = mstpctlutil(**flags)
|
|
|
|
|
2014-10-24 10:11:07 -07:00
|
|
|
def run(self, ifaceobj, operation, query_ifaceobj=None,
|
|
|
|
ifaceobj_getfunc=None, **extra_args):
|
2014-10-09 16:02:46 -07:00
|
|
|
""" run mstp configuration on the interface object passed as argument
|
|
|
|
|
|
|
|
Args:
|
|
|
|
**ifaceobj** (object): iface object
|
|
|
|
|
|
|
|
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
|
|
|
|
'query-running'
|
|
|
|
Kwargs:
|
|
|
|
**query_ifaceobj** (object): query check ifaceobject. This is only
|
|
|
|
valid when op is 'query-checkcurr'. It is an object same as
|
|
|
|
ifaceobj, but contains running attribute values and its config
|
|
|
|
status. The modules can use it to return queried running state
|
|
|
|
of interfaces. status is success if the running state is same
|
|
|
|
as user required state in ifaceobj. error otherwise.
|
|
|
|
"""
|
2014-12-01 14:54:12 -08:00
|
|
|
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
op_handler = self._run_ops.get(operation)
|
|
|
|
if not op_handler:
|
|
|
|
return
|
|
|
|
self._init_command_handlers()
|
|
|
|
if operation == 'query-checkcurr':
|
2014-10-24 10:11:07 -07:00
|
|
|
op_handler(self, ifaceobj, query_ifaceobj,
|
|
|
|
ifaceobj_getfunc=ifaceobj_getfunc)
|
2014-10-09 16:02:46 -07:00
|
|
|
else:
|
2014-10-24 10:11:07 -07:00
|
|
|
op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
|