3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from ifupdown2
.ifupdown
.iface
import *
13 from ifupdown2
.ifupdown
.utils
import utils
14 from ifupdown2
.ifupdown
.netlink
import netlink
16 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
17 import ifupdown2
.ifupdown
.policymanager
as policymanager
19 from ifupdown2
.ifupdownaddons
.LinkUtils
import LinkUtils
20 from ifupdown2
.ifupdownaddons
.modulebase
import moduleBase
21 from ifupdown2
.ifupdownaddons
.mstpctlutil
import mstpctlutil
22 from ifupdown2
.ifupdownaddons
.systemutils
import systemUtils
23 from ifupdown2
.ifupdown
.exceptions
import moduleNotSupported
25 from ifupdown
.iface
import *
26 from ifupdown
.utils
import utils
27 from ifupdown
.netlink
import netlink
29 import ifupdown
.ifupdownflags
as ifupdownflags
30 import ifupdown
.policymanager
as policymanager
32 from ifupdownaddons
.LinkUtils
import LinkUtils
33 from ifupdownaddons
.modulebase
import moduleBase
34 from ifupdownaddons
.mstpctlutil
import mstpctlutil
35 from ifupdownaddons
.systemutils
import systemUtils
36 from ifupdown
.exceptions
import moduleNotSupported
42 class mstpctl(moduleBase
):
43 """ ifupdown2 addon module to configure mstp attributes """
45 _modinfo
= {'mhelp' : 'mstp configuration module for bridges',
48 {'help' : 'mstp ports',
51 'new-attribute': 'bridge-ports'},
53 {'help': 'bridge stp yes/no',
54 'validvals' : ['yes', 'no', 'on', 'off'],
58 'new-attribute': 'bridge-stp'},
60 {'help': 'tree priority',
62 'validvals' : ['0', '4096', '8192', '12288', '16384',
63 '20480', '24576', '28672', '32768',
64 '36864', '40960', '45056', '49152',
65 '53248', '57344', '61440'],
67 'example' : ['mstpctl-treeprio 32768']},
69 {'help': 'ageing time',
70 'validrange' : ['0', '4096'],
73 'jsonAttr': 'ageingTime',
74 'example' : ['mstpctl-ageing 300']},
76 { 'help' : 'max message age',
77 'validrange' : ['0', '255'],
79 'jsonAttr': 'bridgeMaxAge',
81 'example' : ['mstpctl-maxage 20']},
83 { 'help' : 'set forwarding delay',
84 'validrange' : ['0', '255'],
86 'jsonAttr': 'bridgeFwdDelay',
88 'example' : ['mstpctl-fdelay 15']},
90 { 'help' : 'bridge max hops',
91 'validrange' : ['0', '255'],
93 'jsonAttr': 'maxHops',
95 'example' : ['mstpctl-maxhops 15']},
96 'mstpctl-txholdcount' :
97 { 'help' : 'bridge transmit holdcount',
98 'validrange' : ['0', '255'],
100 'jsonAttr': 'txHoldCounter',
102 'example' : ['mstpctl-txholdcount 6']},
103 'mstpctl-forcevers' :
104 { 'help' : 'bridge force stp version',
105 'validvals' : ['rstp', ],
108 'jsonAttr': 'forceProtocolVersion',
109 'example' : ['mstpctl-forcevers rstp']},
110 'mstpctl-portpathcost' :
111 { 'help' : 'bridge port path cost',
112 'validvals': ['<interface-range-list>'],
113 'validrange' : ['0', '65535'],
115 'jsonAttr' : 'adminExtPortCost',
117 'example' : ['under the bridge: mstpctl-portpathcost swp1=0 swp2=1',
118 'under the port (recommended): mstpctl-portpathcost 0']},
120 { 'help' : 'bridge port p2p detection mode',
122 'jsonAttr' : 'adminPointToPoint',
123 'validvals' : ['<interface-yes-no-auto-list>'],
125 'example' : ['under the bridge: mstpctl-portp2p swp1=yes swp2=no',
126 'under the port (recommended): mstpctl-portp2p yes']},
127 'mstpctl-portrestrrole' :
129 'enable/disable port ability to take root role of the port',
131 'jsonAttr' : 'restrictedRole',
132 'validvals' : ['<interface-yes-no-list>'],
134 'example' : ['under the bridge: mstpctl-portrestrrole swp1=yes swp2=no',
135 'under the port (recommended): mstpctl-portrestrrole yes']},
136 'mstpctl-portrestrtcn' :
138 'enable/disable port ability to propagate received topology change notification of the port',
140 'jsonAttr' : 'restrictedTcn',
141 'validvals' : ['<interface-yes-no-list>'],
143 'example' : ['under the bridge: mstpctl-portrestrtcn swp1=yes swp2=no',
144 'under the port (recommended): mstpctl-portrestrtcn yes']},
145 'mstpctl-bpduguard' :
147 'enable/disable bpduguard',
149 'jsonAttr' : 'bpduGuardPort',
150 'validvals' : ['<interface-yes-no-list>'],
152 'example' : ['under the bridge: mstpctl-bpduguard swp1=yes swp2=no',
153 'under the port (recommended): mstpctl-bpduguard yes']},
154 'mstpctl-treeportprio' :
155 { 'help': 'Sets the <port>\'s priority MSTI instance. '
156 'The priority value must be a number between 0 and 240 and a multiple of 16.',
158 'validvals': ['<interface-range-list-multiple-of-16>'],
159 'validrange' : ['0', '240'],
160 'jsonAttr': 'treeportprio',
162 'example' : ['under the bridge: mstpctl-treeportprio swp1=128 swp2=128',
163 'under the port (recommended): mstpctl-treeportprio 128']},
165 { 'help' : 'set hello time',
166 'validrange' : ['0', '255'],
169 'jsonAttr': 'helloTime',
170 'example' : ['mstpctl-hello 2']},
171 'mstpctl-portnetwork' :
172 { 'help' : 'enable/disable bridge assurance capability for a port',
173 'validvals' : ['<interface-yes-no-list>'],
175 'jsonAttr' : 'networkPort',
177 'example' : ['under the bridge: mstpctl-portnetwork swp1=yes swp2=no',
178 'under the port (recommended): mstpctl-portnetwork yes']},
179 'mstpctl-portadminedge' :
180 { 'help' : 'enable/disable initial edge state of the port',
181 'validvals' : ['<interface-yes-no-list>'],
183 'jsonAttr' : 'adminEdgePort',
185 'example' : ['under the bridge: mstpctl-portadminedge swp1=yes swp2=no',
186 'under the port (recommended): mstpctl-portadminedge yes']},
187 'mstpctl-portautoedge' :
188 { 'help' : 'enable/disable auto transition to/from edge state of the port',
189 'validvals' : ['<interface-yes-no-list>'],
191 'jsonAttr' : 'autoEdgePort',
193 'example' : ['under the bridge: mstpctl-portautoedge swp1=yes swp2=no',
194 'under the port (recommended): mstpctl-portautoedge yes']},
195 'mstpctl-treeportcost' :
196 { 'help' : 'port tree cost',
197 'validrange' : ['0', '255'],
199 'jsonAttr': 'extPortCost',
201 'mstpctl-portbpdufilter' :
202 { 'help' : 'enable/disable bpdu filter on a port. ' +
203 'syntax varies when defined under a bridge ' +
205 'validvals' : ['<interface-yes-no-list>'],
206 'jsonAttr' : 'bpduFilterPort',
209 'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
210 'under a port: mstpctl-portbpdufilter yes']},
213 # Maps mstp bridge attribute names to corresponding mstpctl commands
214 # XXX: This can be encoded in the modules dict above
215 _attrs_map
= OrderedDict([('mstpctl-treeprio' , 'treeprio'),
216 ('mstpctl-ageing' , 'ageing'),
217 ('mstpctl-fdelay' , 'fdelay'),
218 ('mstpctl-maxage' , 'maxage'),
219 ('mstpctl-maxhops' , 'maxhops'),
220 ('mstpctl-txholdcount' , 'txholdcount'),
221 ('mstpctl-forcevers', 'forcevers'),
222 ('mstpctl-hello' , 'hello')])
224 # Maps mstp port attribute names to corresponding mstpctl commands
225 # XXX: This can be encoded in the modules dict above
226 _port_attrs_map
= {'mstpctl-portpathcost' : 'portpathcost',
227 'mstpctl-portadminedge' : 'portadminedge',
228 'mstpctl-portautoedge' : 'portautoedge' ,
229 'mstpctl-portp2p' : 'portp2p',
230 'mstpctl-portrestrrole' : 'portrestrrole',
231 'mstpctl-portrestrtcn' : 'portrestrtcn',
232 'mstpctl-bpduguard' : 'bpduguard',
233 'mstpctl-treeportprio' : 'treeportprio',
234 'mstpctl-treeportcost' : 'treeportcost',
235 'mstpctl-portnetwork' : 'portnetwork',
236 'mstpctl-portbpdufilter' : 'portbpdufilter'}
238 def __init__(self
, *args
, **kargs
):
239 moduleBase
.__init
__(self
, *args
, **kargs
)
240 if not os
.path
.exists('/sbin/mstpctl'):
241 raise moduleNotSupported('module init failed: no /sbin/mstpctl found')
243 self
.name
= self
.__class
__.__name
__
245 self
.mstpctlcmd
= None
246 self
.mstpd_running
= (True if systemUtils
.is_process_running('mstpd')
250 # The ask is to make "mstpctl-portadminedge yes" part of the default ifupdown2
251 # policy for all vxlan interfaces. In the absence of this, the mstp work flow
252 # is flawed in the event of vxlan flap.
254 # As of today, for vxlan interfaces "oper edge port" is set to 'yes' and also
255 # "bpdufilter port" is also set to 'yes'. So, in a case where bridge has multiple
256 # vxlan interfaces, if one vxlan interface is flapped, this would trigger mstp
257 # re-evaluation of states on other vxlan interfaces, creating momentary traffic
258 # glitch on those vxlans. Setting "admin edge port" to yes (in addition to the
259 # defaults we already have) prevents this.
261 # We use to only support 'mstpctl-vxlan-always-set-bpdu-params' but introducing a
262 # separate policy attribute doesn't make sense, we should have one single
263 # attribute to handle the whole thing (and deprecate mstpctl-vxlan-always-set-bpdu-params)
264 # mstpctl-set-default-vxlan-bridge-attrs=yes will set
265 # mstpctl-portbpdufilter
267 # mstpctl-portadminedge
269 self
.set_default_mstp_vxlan_bridge_config
= utils
.get_boolean_from_string(
270 policymanager
.policymanager_api
.get_module_globals(
271 module_name
=self
.__class
__.__name
__,
272 attr
='mstpctl-vxlan-always-set-bpdu-params'
274 ) or utils
.get_boolean_from_string(
275 policymanager
.policymanager_api
.get_module_globals(
276 module_name
=self
.__class
__.__name
__,
277 attr
='mstpctl-set-default-vxlan-bridge-attrs'
281 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
):
282 if self
._is
_bridge
(ifaceobj
):
283 if (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
284 and ifaceobj
.get_attr_value_first('mstpctl-portadminedge')):
285 self
.logger
.error('%s: unsupported use of keyword '
286 '\'mstpctl-portadminedge\' when '
287 'bridge-vlan-aware is on'
292 def _is_bridge(self
, ifaceobj
):
293 if (ifaceobj
.get_attr_value_first('mstpctl-ports') or
294 ifaceobj
.get_attr_value_first('bridge-ports')):
298 def _is_bridge_port(self
, ifaceobj
):
299 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
303 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
304 if not self
._is
_bridge
(ifaceobj
):
306 return self
.parse_port_list(ifaceobj
.name
,
307 ifaceobj
.get_attr_value_first(
308 'mstpctl-ports'), ifacenames_all
)
310 def get_dependent_ifacenames_running(self
, ifaceobj
):
311 self
._init
_command
_handlers
()
312 if (self
.brctlcmd
.bridge_exists(ifaceobj
.name
) and
313 not self
.mstpctlcmd
.mstpbridge_exists(ifaceobj
.name
)):
315 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
317 def _get_bridge_port_attr_value(self
, bridgename
, portname
, attr
):
318 json_attr
= self
.get_mod_subattr(attr
, 'jsonAttr')
319 return self
.mstpctlcmd
.get_bridge_port_attr(bridgename
,
323 def _get_bridge_port_list(self
, ifaceobj
):
325 # port list is also available in the previously
326 # parsed dependent list. Use that if available, instead
327 # of parsing port expr again
328 port_list
= ifaceobj
.lowerifaces
331 ports
= ifaceobj
.get_attr_value_first('mstpctl-ports')
333 return self
.parse_port_list(ifaceobj
.name
, ports
)
337 def _ports_enable_disable_ipv6(self
, ports
, enable
='1'):
340 self
.write_file('/proc/sys/net/ipv6/conf/%s' %p
+
341 '/disable_ipv6', enable
)
343 self
.logger
.info(str(e
))
346 def _add_ports(self
, ifaceobj
):
347 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
349 runningbridgeports
= []
350 # Delete active ports not in the new port list
351 if not ifupdownflags
.flags
.PERFMODE
:
352 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
353 if runningbridgeports
:
354 [self
.ipcmd
.link_set(bport
, 'nomaster')
355 for bport
in runningbridgeports
356 if not bridgeports
or bport
not in bridgeports
]
358 runningbridgeports
= []
362 for bridgeport
in Set(bridgeports
).difference(Set(runningbridgeports
)):
364 if (not ifupdownflags
.flags
.DRYRUN
and
365 not self
.ipcmd
.link_exists(bridgeport
)):
366 self
.log_warn('%s: bridge port %s does not exist'
367 %(ifaceobj
.name
, bridgeport
))
370 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
371 self
.ipcmd
.addr_flush(bridgeport
)
373 self
.log_error(str(e
), ifaceobj
)
376 self
.log_error('error configuring bridge (missing ports)')
378 def _apply_bridge_settings(self
, ifaceobj
, ifaceobj_getfunc
):
379 check
= False if ifupdownflags
.flags
.PERFMODE
else True
381 # set bridge attributes
382 for attrname
, dstattrname
in self
._attrs
_map
.items():
383 config_val
= ifaceobj
.get_attr_value_first(attrname
)
384 default_val
= policymanager
.policymanager_api
.get_iface_default(module_name
=self
.__class
__.__name
__, ifname
=ifaceobj
.name
, attr
=attrname
)
386 default_val
= self
.get_mod_subattr(attrname
, 'default')
387 jsonAttr
= self
.get_mod_subattr(attrname
, 'jsonAttr')
389 running_val
= self
.mstpctlcmd
.get_bridge_attr(
390 ifaceobj
.name
, jsonAttr
)
392 self
.logger
.info('%s: could not get running %s value'
393 %(ifaceobj
.name
, attrname
))
395 if (not config_val
and default_val
and (running_val
!= default_val
)):
396 # this happens when users remove an attribute from a port
397 # and expect the default to be restored with ifreload.
398 config_val
= default_val
400 # there is nothing configured and no default to reset
403 if attrname
== 'mstpctl-treeprio':
404 self
.mstpctlcmd
.set_bridge_treeprio(ifaceobj
.name
,
407 self
.mstpctlcmd
.set_bridge_attr(ifaceobj
.name
,
408 dstattrname
, config_val
, check
)
410 self
.logger
.warn('%s' %str
(e
))
413 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
):
415 # set bridge port attributes
416 for attrname
, dstattrname
in self
._port
_attrs
_map
.items():
417 config_val
= ifaceobj
.get_attr_value_first(attrname
)
418 default_val
= self
.get_mod_subattr(attrname
,'default')
420 # nothing configured, we may need to reset all ports to defaults
421 # if the default exists and jsonAttribute conversion exists
423 jsonAttr
= self
.get_mod_subattr(attrname
, 'jsonAttr')
424 if default_val
and jsonAttr
:
425 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
426 for port
in bridgeports
:
427 if not self
.brctlcmd
.is_bridge_port(port
):
430 bport_ifaceobjs
= ifaceobj_getfunc(port
)
432 default_val
= self
._get
_default
_val
(attrname
, bport_ifaceobjs
[0], ifaceobj
)
433 for brport_ifaceobj
in bport_ifaceobjs
or []:
434 attr_value
= brport_ifaceobj
.get_attr_value_first(attrname
)
436 default_val
= attr_value
439 self
.mstpctlcmd
.set_bridge_port_attr(ifaceobj
.name
,
444 except Exception as e
:
445 self
.logger
.debug('%s' % str(e
))
446 self
.logger
.info('%s: not resetting %s config'
447 %(ifaceobj
.name
, attrname
))
448 # leave the loop for this attribute
451 portlist
= self
.parse_port_list(ifaceobj
.name
, config_val
)
453 self
.log_error('%s: error parsing \'%s %s\''
454 %(ifaceobj
.name
, attrname
, config_val
), ifaceobj
)
456 # there was a configured value so we need to parse it
457 # and set the attribute for each port configured
460 (port
, val
) = p
.split('=')
461 # if it is not bridge port, continue
462 if not os
.path
.exists('/sys/class/net/%s/brport' %port
):
464 json_attr
= self
.get_mod_subattr(attrname
, 'jsonAttr')
465 self
.mstpctlcmd
.set_bridge_port_attr(ifaceobj
.name
,
471 self
.log_error('%s: error setting %s (%s)'
472 %(ifaceobj
.name
, attrname
, str(e
)),
473 ifaceobj
, raise_error
=False)
475 self
.log_warn(str(e
))
478 def _get_default_val(self
, attr
, ifaceobj
, bridgeifaceobj
):
479 if (self
.set_default_mstp_vxlan_bridge_config
480 and ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
482 'mstpctl-portbpdufilter',
484 'mstpctl-portadminedge',
488 config_val
= bridgeifaceobj
.get_attr_value_first(attr
)
492 if ifaceobj
.name
not in [v
.split('=')[0] for v
in config_val
.split()]:
495 index
= [v
.split('=')[0] for v
in config_val
.split()].index(ifaceobj
.name
)
496 return [v
.split('=')[1] for v
in config_val
.split()][index
]
500 default_val
= policymanager
.policymanager_api
.get_iface_default(module_name
=self
.__class
__.__name
__, ifname
=ifaceobj
.name
, attr
=attr
)
502 return self
.get_mod_subattr(attr
,'default')
505 def _apply_bridge_port_settings(self
, ifaceobj
, bridgename
=None,
509 check
= False if ifupdownflags
.flags
.PERFMODE
else True
511 if not bridgename
and bridgeifaceobj
:
512 bridgename
= bridgeifaceobj
.name
514 if not stp_running_on
:
515 # stp may get turned on at a later point
516 self
.logger
.info('%s: ignoring config'
518 ' (stp on bridge %s is not on yet)' %bridgename
)
520 bvlan_aware
= self
.ipcmd
.bridge_is_vlan_aware(bridgename
)
521 if (not mstpd_running
or
522 not os
.path
.exists('/sys/class/net/%s/brport' %ifaceobj
.name
) or
524 if (not bvlan_aware
and
525 self
.set_default_mstp_vxlan_bridge_config
and
526 (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
)):
528 'mstpctl-portbpdufilter',
530 'mstpctl-portadminedge'
532 json_attr
= self
.get_mod_subattr(attr
, 'jsonAttr')
533 config_val
= self
._get
_default
_val
(attr
, ifaceobj
,
536 self
.mstpctlcmd
.set_bridge_port_attr(bridgename
,
538 self
._port
_attrs
_map
[attr
],
542 self
.log_warn('%s: error setting %s (%s)'
543 % (ifaceobj
.name
, attr
, str(e
)))
546 # for "traditional" bridges we also want to let the user configure
547 # some attributes (possibly all of them in the future)
548 applied
= self
._apply
_bridge
_port
_settings
_attributes
_list
(
550 ('mstpctl-portrestrrole', 'portrestrrole'),
551 ('mstpctl-portautoedge', 'portautoedge')
559 # set bridge port attributes
560 return self
._apply
_bridge
_port
_settings
_attributes
_list
(
561 self
._port
_attrs
_map
.items(),
568 def _apply_bridge_port_settings_attributes_list(self
, attributes_list
, ifaceobj
, bridgeifaceobj
, bridgename
, applied
):
569 for attrname
, dstattrname
in attributes_list
:
570 config_val
= ifaceobj
.get_attr_value_first(attrname
)
571 default_val
= self
._get
_default
_val
(attrname
, ifaceobj
, bridgeifaceobj
)
572 jsonAttr
= self
.get_mod_subattr(attrname
, 'jsonAttr')
573 # to see the running value, stp would have to be on
574 # so we would have parsed mstpctl showportdetail json output
576 running_val
= self
.mstpctlcmd
.get_bridge_port_attr(bridgename
,
577 ifaceobj
.name
, jsonAttr
)
579 self
.logger
.info('%s %s: could not get running %s value'
580 %(bridgename
, ifaceobj
.name
, attrname
))
582 if (not config_val
and default_val
and (running_val
!= default_val
)):
583 # this happens when users remove an attribute from a port
584 # and expect the default to be restored with ifreload.
585 config_val
= default_val
587 # there is nothing configured and no default to reset
591 self
.mstpctlcmd
.set_bridge_port_attr(bridgename
,
592 ifaceobj
.name
, dstattrname
, config_val
, json_attr
=jsonAttr
)
595 self
.log_error('%s: error setting %s (%s)'
596 %(ifaceobj
.name
, attrname
, str(e
)), ifaceobj
,
600 def _apply_bridge_port_settings_all(self
, ifaceobj
,
601 ifaceobj_getfunc
=None):
602 self
.logger
.info('%s: applying mstp configuration '
603 %ifaceobj
.name
+ 'specific to ports')
604 # Query running bridge ports. and only apply attributes on them
605 bridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
607 self
.logger
.debug('%s: cannot find bridgeports' %ifaceobj
.name
)
609 for bport
in bridgeports
:
610 self
.logger
.info('%s: processing mstp config for port %s'
611 %(ifaceobj
.name
, bport
))
612 if not self
.ipcmd
.link_exists(bport
):
614 if not os
.path
.exists('/sys/class/net/%s/brport' %bport
):
616 bportifaceobjlist
= ifaceobj_getfunc(bport
)
617 if not bportifaceobjlist
:
619 for bportifaceobj
in bportifaceobjlist
:
620 # Dont process bridge port if it already has been processed
621 if (bportifaceobj
.module_flags
.get(self
.name
,0x0) & \
622 mstpctlFlags
.PORT_PROCESSED
):
625 self
._apply
_bridge
_port
_settings
(bportifaceobj
,
626 ifaceobj
.name
, ifaceobj
)
629 self
.log_warn(str(e
))
631 def _is_running_userspace_stp_state_on(self
, bridgename
):
632 stp_state_file
= '/sys/class/net/%s/bridge/stp_state' %bridgename
633 if not stp_state_file
:
635 running_stp_state
= self
.read_file_oneline(stp_state_file
)
636 if running_stp_state
and running_stp_state
== '2':
640 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
641 # Check if bridge port
642 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
644 mstpd_running
= self
.mstpd_running
645 stp_running_on
= self
._is
_running
_userspace
_stp
_state
_on
(bridgename
)
646 applied
= self
._apply
_bridge
_port
_settings
(ifaceobj
, bridgename
,
647 None, stp_running_on
,
650 ifaceobj
.module_flags
[self
.name
] = \
651 ifaceobj
.module_flags
.setdefault(self
.name
,0) | \
652 mstpctlFlags
.PORT_PROCESSED
654 if not self
._is
_bridge
(ifaceobj
):
656 # we are now here because the ifaceobj is a bridge
661 if ifaceobj
.get_attr_value_first('mstpctl-ports'):
662 # If bridge ports specified with mstpctl attr, create the
663 # bridge and also add its ports
664 self
.ipcmd
.batch_start()
665 if not ifupdownflags
.flags
.PERFMODE
:
666 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
667 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
669 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
671 self
._add
_ports
(ifaceobj
)
677 self
.ipcmd
.batch_commit()
678 running_ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
680 # disable ipv6 for ports that were added to bridge
681 self
._ports
_enable
_disable
_ipv
6(running_ports
, '1')
683 stp
= ifaceobj
.get_attr_value_first('mstpctl-stp')
685 self
.set_iface_attr(ifaceobj
, 'mstpctl-stp',
686 self
.brctlcmd
.bridge_set_stp
)
688 stp
= self
.brctlcmd
.bridge_get_stp(ifaceobj
.name
)
689 if (self
.mstpd_running
and
690 (stp
== 'yes' or stp
== 'on')):
691 self
._apply
_bridge
_settings
(ifaceobj
, ifaceobj_getfunc
)
692 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
693 ifaceobj_getfunc
=ifaceobj_getfunc
)
695 self
.log_error(str(e
), ifaceobj
)
697 raise Exception(porterrstr
)
699 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
700 if not self
._is
_bridge
(ifaceobj
):
703 if ifaceobj
.get_attr_value_first('mstpctl-ports'):
704 # If bridge ports specified with mstpctl attr, delete the
706 ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
708 self
._ports
_enable
_disable
_ipv
6(ports
, '0')
709 self
.brctlcmd
.delete_bridge(ifaceobj
.name
)
711 self
.log_error(str(e
), ifaceobj
)
713 def _query_running_attrs(self
, ifaceobjrunning
, bridge_vlan_aware
=False):
716 tmpbridgeattrdict
= self
.mstpctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
717 #self.logger.info('A' + str(tmpbridgeattrdict))
718 if not tmpbridgeattrdict
:
719 return bridgeattrdict
721 for k
,v
in tmpbridgeattrdict
.items():
722 if k
== 'stp' or not v
:
727 attrname
= 'mstpctl-' + k
728 if (v
and v
!= self
.get_mod_subattr(attrname
, 'default')
729 and attrname
!= 'mstpctl-maxhops'):
730 bridgeattrdict
[attrname
] = [v
]
732 ports
= self
.brctlcmd
.get_bridge_ports(ifaceobjrunning
.name
)
733 # Do this only for vlan-UNAWARE-bridge
734 if ports
and not bridge_vlan_aware
:
735 portconfig
= {'mstpctl-portautoedge' : '',
736 'mstpctl-portbpdufilter' : '',
737 'mstpctl-portnetwork' : '',
738 'mstpctl-portpathcost' : '',
739 'mstpctl-portadminedge' : '',
740 'mstpctl-portp2p' : '',
741 'mstpctl-portrestrrole' : '',
742 'mstpctl-portrestrtcn' : '',
743 'mstpctl-bpduguard' : '',
744 'mstpctl-treeportprio' : '',
745 'mstpctl-treeportcost' : ''}
749 for attr
in ['mstpctl-portautoedge',
750 'mstpctl-portbpdufilter',
751 'mstpctl-portnetwork',
752 'mstpctl-portadminedge',
754 'mstpctl-portrestrrole',
755 'mstpctl-portrestrtcn',
758 v
= self
._get
_bridge
_port
_attr
_value
(ifaceobjrunning
.name
,
761 portconfig
[attr
] += ' %s=%s' % (p
, v
)
763 for attr
in ['mstpctl-portpathcost', 'mstpctl-treeportcost']:
764 v
= self
._get
_bridge
_port
_attr
_value
(ifaceobjrunning
.name
,
766 if v
and v
!= self
.get_mod_subattr(attr
, 'default'):
767 portconfig
[attr
] += ' %s=%s' % (p
, v
)
769 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
771 return bridgeattrdict
773 def _get_config_stp(self
, ifaceobj
):
774 stp
= (ifaceobj
.get_attr_value_first('mstpctl-stp') or
775 ifaceobj
.get_attr_value_first('bridge-stp') or
776 policymanager
.policymanager_api
.get_iface_default(module_name
=self
.__class
__.__name
__, ifname
=ifaceobj
.name
, attr
='mstpctl-stp') or
777 # this is a temporary method to access policy default value of bridge-stp
778 policymanager
.policymanager_api
.get_iface_default(module_name
='bridge', ifname
=ifaceobj
.name
, attr
='bridge-stp'))
779 return utils
.get_boolean_from_string(stp
)
781 def _get_running_stp(self
, ifaceobj
):
782 stp
= self
.brctlcmd
.bridge_get_stp(ifaceobj
.name
)
783 return utils
.get_boolean_from_string(stp
)
785 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
786 ifaceobj_getfunc
=None):
787 # list of attributes that are not supported currently
788 blacklistedattrs
= ['mstpctl-portpathcost',
789 'mstpctl-treeportprio', 'mstpctl-treeportcost']
790 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
791 self
.logger
.debug('bridge %s does not exist' %ifaceobj
.name
)
793 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
794 self
.get_mod_attrs())
795 if self
.set_default_mstp_vxlan_bridge_config
:
796 for attr
in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
797 if attr
not in ifaceattrs
:
798 ifaceattrs
.append(attr
)
801 runningattrs
= self
.mstpctlcmd
.get_bridge_attrs(ifaceobj
.name
)
802 #self.logger.info('B' + str(runningattrs))
805 config_stp
= self
._get
_config
_stp
(ifaceobj
)
806 running_stp
= self
._get
_running
_stp
(ifaceobj
)
807 running_port_list
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
809 # for all mstpctl options
810 if k
in blacklistedattrs
:
812 if k
in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
813 #special case, 'ifquery --check --with-defaults' on a VLAN
815 if not running_port_list
:
817 if (not config_stp
or not running_stp
):
819 v
= ifaceobj
.get_attr_value_first(k
)
826 for bportval
in v
.split():
827 config_val
[bportval
.split('=')[0]] = bportval
.split('=')[1]
828 #for bport in bridgeports:
829 for bport
in running_port_list
:
830 bportifaceobjlist
= ifaceobj_getfunc(bport
)
831 if not bportifaceobjlist
:
833 for bportifaceobj
in bportifaceobjlist
:
834 if (bport
not in config_val
):
835 if (bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
):
836 if (not ifupdownflags
.flags
.WITHDEFAULTS
or
837 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
)):
843 if ((bportifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) and
844 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
)):
846 conf
= config_val
[bport
]
847 jsonAttr
= self
.get_mod_subattr(k
, 'jsonAttr')
849 running_val
= self
.mstpctlcmd
.get_bridge_port_attr(ifaceobj
.name
, bport
, jsonAttr
)
851 self
.logger
.info('%s %s: could not get running %s value'
852 %(ifaceobj
.name
, bport
, attr
))
854 if conf
!= running_val
:
856 bridge_ports
.update({bport
: running_val
})
857 for port
, val
in bridge_ports
.items():
858 #running state format
859 #mstpctl-portbpdufilter swp2=yes swp1=yes vx-14567101=yes [pass]
860 #mstpctl-bpduguard swp2=yes swp1=yes vx-14567101=yes [pass]
861 state
+= port
+ '=' + val
+ ' '
863 ifaceobjcurr
.update_config_with_status(k
, state
, result
)
866 # get the corresponding ifaceobj attr
867 v
= ifaceobj
.get_attr_value_first(k
)
871 # Get the running attribute
872 rv
= runningattrs
.get(k
[8:])
873 if k
== 'mstpctl-stp':
874 # special case stp compare because it may
875 # contain more than one valid values
876 stp_on_vals
= ['on', 'yes']
877 stp_off_vals
= ['off']
878 rv
= self
.brctlcmd
.bridge_get_stp(ifaceobj
.name
)
879 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
880 (v
in stp_off_vals
and rv
in stp_off_vals
)):
881 ifaceobjcurr
.update_config_with_status('mstpctl-stp', v
, 0)
883 ifaceobjcurr
.update_config_with_status('mstpctl-stp', v
, 1)
886 if k
== 'mstpctl-ports':
887 # special case ports because it can contain regex or glob
888 # XXX: We get all info from mstputils, which means if
889 # mstpd is down, we will not be returning any bridge bridgeports
890 bridge_port_list
= self
._get
_bridge
_port
_list
(ifaceobj
)
891 if not running_port_list
and not bridge_port_list
:
894 if running_port_list
and bridge_port_list
:
895 difference
= Set(running_port_list
).symmetric_difference(
896 Set(bridge_port_list
))
899 ifaceobjcurr
.update_config_with_status('mstpctl-ports',
900 ' '.join(running_port_list
)
901 if running_port_list
else '', portliststatus
)
902 elif k
[:12] == 'mstpctl-port' or k
== 'mstpctl-bpduguard':
903 # Now, look at port attributes
904 # derive the mstpctlcmd attr name
905 #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
906 mstpctlcmdattrname
= k
[8:]
908 # for port attributes, the attributes are in a list
909 # <portname>=<portattrvalue>
912 vlist
= self
.parse_port_list(ifaceobj
.name
, v
)
915 for vlistitem
in vlist
:
917 (p
, v
) = vlistitem
.split('=')
918 currv
= self
._get
_bridge
_port
_attr
_value
(ifaceobj
.name
, p
, k
)
920 currstr
+= ' %s=%s' %(p
, currv
)
922 currstr
+= ' %s=%s' %(p
, 'None')
926 self
.log_warn(str(e
))
928 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
930 ifaceobjcurr
.update_config_with_status(k
, '', 1)
932 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
934 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
936 def _query_check_bridge_vxlan_port(self
, ifaceobj
, ifaceobjcurr
,
937 ifaceobj_getfunc
=None):
938 masters
= ifaceobj
.upperifaces
941 for bridge
in masters
:
942 bifaceobjlist
= ifaceobj_getfunc(bridge
)
943 for bifaceobj
in bifaceobjlist
:
944 if (self
._is
_bridge
(bifaceobj
) and
945 self
.set_default_mstp_vxlan_bridge_config
and
946 (bifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
)):
947 config_stp
= self
._get
_config
_stp
(bifaceobj
)
948 running_stp
= self
._get
_running
_stp
(bifaceobj
)
949 if (not config_stp
or not running_stp
):
952 'mstpctl-portbpdufilter',
954 'mstpctl-portadminedge'
956 jsonAttr
= self
.get_mod_subattr(attr
, 'jsonAttr')
957 config_val
= bifaceobj
.get_attr_value_first(attr
)
959 if ifaceobj
.name
not in [v
.split('=')[0] for v
in config_val
.split()]:
960 if not ifupdownflags
.flags
.WITHDEFAULTS
:
964 index
= [v
.split('=')[0] for v
in config_val
.split()].index(ifaceobj
.name
)
965 config_val
= [v
.split('=')[1] for v
in config_val
.split()][index
]
967 if not ifupdownflags
.flags
.WITHDEFAULTS
:
971 running_val
= self
.mstpctlcmd
.get_bridge_port_attr(bifaceobj
.name
,
972 ifaceobj
.name
, jsonAttr
)
974 self
.logger
.info('%s %s: could not get running %s value'
975 %(bifaceobj
.name
, ifaceobj
.name
, attr
))
977 ifaceobjcurr
.update_config_with_status(attr
,
979 0 if running_val
== config_val
else 1)
983 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
):
984 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
985 #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
986 ifaceobjcurr
.status
= ifaceStatus
.NOTFOUND
988 # Check if this is a bridge port
989 if not self
._is
_bridge
_port
(ifaceobj
):
990 # mark all the bridge attributes as error
991 ifaceobjcurr
.check_n_update_config_with_status_many(ifaceobj
,
992 self
._port
_attrs
_map
.keys(), 0)
994 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
995 # list of attributes that are not supported currently
996 blacklistedattrs
= ['mstpctl-portpathcost',
997 'mstpctl-treeportprio', 'mstpctl-treeportcost']
998 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
999 self
._port
_attrs
_map
.keys())
1002 runningattrs
= self
.mstpctlcmd
.get_bridge_attrs(ifaceobj
.name
)
1003 #self.logger.info('C' + str(runningattrs))
1004 if not runningattrs
:
1006 for k
in ifaceattrs
:
1007 # for all mstpctl options
1008 # get the corresponding ifaceobj attr
1009 v
= ifaceobj
.get_attr_value_first(k
)
1010 if not v
or k
in blacklistedattrs
:
1011 ifaceobjcurr
.update_config_with_status(k
, v
, -1)
1013 currv
= self
._get
_bridge
_port
_attr
_value
(bridgename
, ifaceobj
.name
, k
)
1016 ifaceobjcurr
.update_config_with_status(k
, currv
, 1)
1018 ifaceobjcurr
.update_config_with_status(k
, currv
, 0)
1020 ifaceobjcurr
.update_config_with_status(k
, None, 1)
1022 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
1023 if self
._is
_bridge
(ifaceobj
):
1024 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
)
1025 elif ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
:
1026 self
._query
_check
_bridge
_vxlan
_port
(ifaceobj
, ifaceobjcurr
,
1029 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
)
1031 def _query_bridge_port_attr(self
, ifaceobjrunning
, bridgename
, attr
, value_cmp
):
1032 v
= self
._get
_bridge
_port
_attr
_value
(bridgename
,
1033 ifaceobjrunning
.name
,
1035 if v
and value_cmp
and v
!= value_cmp
:
1036 ifaceobjrunning
.update_config(attr
, v
)
1037 elif v
and not value_cmp
:
1038 ifaceobjrunning
.update_config(attr
, v
)
1040 def _query_running_bridge_port(self
, ifaceobjrunning
):
1041 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
1042 ifaceobjrunning
.name
)
1044 self
.logger
.warn('%s: unable to determine bridgename'
1045 %ifaceobjrunning
.name
)
1047 if self
.brctlcmd
.bridge_get_stp(bridgename
) == 'no':
1048 # This bridge does not run stp, return
1050 # if userspace stp not set, return
1051 if self
.systcl_get_net_bridge_stp_user_space() != '1':
1054 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1055 'mstpctl-portautoedge',
1056 self
.get_mod_subattr('mstpctl-portautoedge', 'default'))
1058 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1059 'mstpctl-portbpdufilter',
1062 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1063 'mstpctl-portnetwork',
1066 # XXX: Can we really get path cost of a port ???
1067 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
1068 #if v and v != self.get_mod_subattr('mstpctl-pathcost',
1070 # ifaceobjrunning.update_config('mstpctl-network', v)
1072 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1073 'mstpctl-portadminedge',
1076 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1080 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1081 'mstpctl-portrestrrole',
1084 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1085 'mstpctl-portrestrtcn',
1088 self
._query
_bridge
_port
_attr
(ifaceobjrunning
, bridgename
,
1089 'mstpctl-bpduguard',
1092 # XXX: Can we really get path cost of a port ???
1093 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1095 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
1097 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
1099 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1101 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
1103 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
1105 def _query_running_bridge(self
, ifaceobjrunning
):
1106 if self
.brctlcmd
.bridge_get_stp(ifaceobjrunning
.name
) == 'no':
1107 # This bridge does not run stp, return
1109 # if userspace stp not set, return
1110 if self
.systcl_get_net_bridge_stp_user_space() != '1':
1112 # Check if mstp really knows about this bridge
1113 if not self
.mstpctlcmd
.mstpbridge_exists(ifaceobjrunning
.name
):
1115 bridge_vlan_aware
= False
1116 if ifaceobjrunning
.get_attr_value_first('bridge-vlan-aware') == 'yes':
1117 bridge_vlan_aware
= True
1118 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1122 def _query_running(self
, ifaceobjrunning
, **extra_args
):
1123 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
1124 self
._query
_running
_bridge
(ifaceobjrunning
)
1125 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
1126 self
._query
_running
_bridge
_port
(ifaceobjrunning
)
1128 def _query_bridge_port(self
, ifaceobj
, ifaceobj_getfunc
=None):
1142 bridge_ports vxlan1wd vxlan2wd
1143 bridge-vlan-aware yes
1151 $ ifquery --with-defaults vxlan1wd
1155 mstpctl-portbpdufilter yes
1156 mstpctl-bpduguard yes
1158 masters
= ifaceobj
.upperifaces
1162 for bridge
in masters
:
1163 bifaceobj
= ifaceobj_getfunc(bridge
)[0]
1164 if (self
._is
_bridge
(bifaceobj
) and
1165 self
.set_default_mstp_vxlan_bridge_config
and
1166 (bifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_VLAN_AWARE
)):
1167 for attr
in ('mstpctl-portbpdufilter',
1168 'mstpctl-bpduguard',
1169 'mstpctl-portadminedge'):
1170 jsonAttr
= self
.get_mod_subattr(attr
, 'jsonAttr')
1171 config_val
= ifaceobj
.get_attr_value_first(attr
)
1172 if config_val
or not ifupdownflags
.flags
.WITHDEFAULTS
:
1175 ifaceobj
.replace_config(attr
, config_val
)
1177 except Exception, e
:
1178 self
.logger
.info("%s: %s" %(ifaceobj
.name
, str(e
)))
1181 def _query(self
, ifaceobj
, ifaceobj_getfunc
=None, **kwargs
):
1182 """ add default policy attributes supported by the module """
1183 if not self
._is
_bridge
(ifaceobj
):
1184 if (ifaceobj
.module_flags
.get(self
.name
,0x0) &
1185 mstpctlFlags
.PORT_PROCESSED
):
1187 self
._query
_bridge
_port
(ifaceobj
, ifaceobj_getfunc
)
1188 ifaceobj
.module_flags
[self
.name
] = (
1189 ifaceobj
.module_flags
.setdefault(self
.name
,0) |
1190 mstpctlFlags
.PORT_PROCESSED
)
1192 lowerinfs
= ifaceobj
.lowerifaces
1195 if ifaceobj
.get_attr_value_first('bridge-vlan-aware') != 'yes':
1196 for attr
in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1198 config
= ifaceobj
.get_attr_value_first(attr
)
1199 for port
in lowerinfs
:
1200 bportobjlist
= ifaceobj_getfunc(port
)
1201 for bportobj
in bportobjlist
:
1202 if bportobj
.get_attr_value_first('vxlan-id'):
1204 if port
not in [v
.split('=')[0] for v
in config
.split()]:
1205 config
+= ' %s=yes' %port
1207 state
+= '%s=yes ' %port
1208 ifaceobj
.replace_config(attr
, config
if config
else state
)
1210 for attr
in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1212 config
= ifaceobj
.get_attr_value_first(attr
)
1213 for port
in lowerinfs
:
1214 bportobjlist
= ifaceobj_getfunc(port
)
1215 for bportobj
in bportobjlist
:
1216 if (bportobj
.module_flags
.get(self
.name
,0x0) &
1217 mstpctlFlags
.PORT_PROCESSED
):
1219 if bportobj
.get_attr_value_first('vxlan-id'):
1221 if port
not in [v
.split('=')[0] for v
in config
.split()]:
1222 bportobj
.update_config(attr
, 'yes')
1224 index
= [v
.split('=')[0] for v
in config
.split()].index(port
)
1225 state
= [v
.split('=')[1] for v
in config
.split()][index
]
1226 bportobj
.update_config(attr
, '%s' %state
)
1229 config
= ' '.join(v
)
1231 bportobj
.replace_config(attr
, 'yes')
1232 bportobj
.module_flags
[self
.name
] = (
1233 bportobj
.module_flags
.setdefault(self
.name
,0) |
1234 mstpctlFlags
.PORT_PROCESSED
)
1236 ifaceobj
.replace_config(attr
, config
)
1240 _run_ops
= {'pre-up' : _up
,
1241 'post-down' : _down
,
1242 'query-checkcurr' : _query_check
,
1243 'query-running' : _query_running
,
1247 """ returns list of ops supported by this module """
1248 return self
._run
_ops
.keys()
1250 def _init_command_handlers(self
):
1252 self
.ipcmd
= self
.brctlcmd
= LinkUtils()
1253 if not self
.mstpctlcmd
:
1254 self
.mstpctlcmd
= mstpctlutil()
1256 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
1257 ifaceobj_getfunc
=None, **extra_args
):
1258 """ run mstp configuration on the interface object passed as argument
1261 **ifaceobj** (object): iface object
1263 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1266 **query_ifaceobj** (object): query check ifaceobject. This is only
1267 valid when op is 'query-checkcurr'. It is an object same as
1268 ifaceobj, but contains running attribute values and its config
1269 status. The modules can use it to return queried running state
1270 of interfaces. status is success if the running state is same
1271 as user required state in ifaceobj. error otherwise.
1273 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
1275 op_handler
= self
._run
_ops
.get(operation
)
1278 self
._init
_command
_handlers
()
1279 if operation
== 'query-checkcurr':
1280 op_handler(self
, ifaceobj
, query_ifaceobj
,
1281 ifaceobj_getfunc
=ifaceobj_getfunc
)
1283 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)