]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/mstpctl.py
ifupdownmain: missing return statement and fixing 'network down' error checking
[mirror_ifupdown2.git] / addons / mstpctl.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
42a9d193 7import os
15ef32ea
RP
8from sets import Set
9from ifupdown.iface import *
8252491e 10from ifupdown.utils import utils
15ef32ea
RP
11from ifupdownaddons.modulebase import moduleBase
12from ifupdownaddons.bridgeutils import brctl
13from ifupdownaddons.iproute2 import iproute2
14from ifupdownaddons.mstpctlutil import mstpctlutil
5f8c03e7 15from ifupdownaddons.systemutils import systemUtils
fc5e1735 16import ifupdown.ifupdownflags as ifupdownflags
2e4dc724 17import ifupdown.policymanager as policymanager
15ef32ea 18
4c773918
ST
19class mstpctlFlags:
20 PORT_PROCESSED = 0x1
21
15ef32ea
RP
22class mstpctl(moduleBase):
23 """ ifupdown2 addon module to configure mstp attributes """
24
25 _modinfo = {'mhelp' : 'mstp configuration module for bridges',
26 'attrs' : {
27 'mstpctl-ports' :
28 {'help' : 'mstp ports',
48689b55
RP
29 'compat' : True,
30 'deprecated': True,
31 'new-attribute': 'bridge-ports'},
15ef32ea
RP
32 'mstpctl-stp' :
33 {'help': 'bridge stp yes/no',
482b2fab 34 'validvals' : ['yes', 'no', 'on', 'off'],
15ef32ea 35 'compat' : True,
4bdf2d1c
JF
36 'default' : 'no',
37 'deprecated': True,
38 'new-attribute': 'bridge-stp'},
15ef32ea
RP
39 'mstpctl-treeprio' :
40 {'help': 'tree priority',
41 'default' : '32768',
42 'validrange' : ['0', '65535'],
43 'required' : False,
44 'example' : ['mstpctl-treeprio 32768']},
45 'mstpctl-ageing' :
46 {'help': 'ageing time',
c6370b56 47 'validrange' : ['0', '4096'],
15ef32ea
RP
48 'default' : '300',
49 'required' : False,
9d3f53c6 50 'jsonAttr': 'ageingTime',
15ef32ea
RP
51 'example' : ['mstpctl-ageing 300']},
52 'mstpctl-maxage' :
53 { 'help' : 'max message age',
c6370b56 54 'validrange' : ['0', '255'],
15ef32ea 55 'default' : '20',
9d3f53c6 56 'jsonAttr': 'maxAge',
15ef32ea
RP
57 'required' : False,
58 'example' : ['mstpctl-maxage 20']},
59 'mstpctl-fdelay' :
60 { 'help' : 'set forwarding delay',
c6370b56 61 'validrange' : ['0', '255'],
15ef32ea 62 'default' : '15',
9d3f53c6 63 'jsonAttr': 'fwdDelay',
15ef32ea
RP
64 'required' : False,
65 'example' : ['mstpctl-fdelay 15']},
66 'mstpctl-maxhops' :
67 { 'help' : 'bridge max hops',
c6370b56 68 'validrange' : ['0', '255'],
15ef32ea 69 'default' : '15',
9d3f53c6 70 'jsonAttr': 'maxHops',
15ef32ea
RP
71 'required' : False,
72 'example' : ['mstpctl-maxhops 15']},
73 'mstpctl-txholdcount' :
74 { 'help' : 'bridge transmit holdcount',
c6370b56 75 'validrange' : ['0', '255'],
15ef32ea 76 'default' : '6',
9d3f53c6 77 'jsonAttr': 'txHoldCounter',
15ef32ea
RP
78 'required' : False,
79 'example' : ['mstpctl-txholdcount 6']},
80 'mstpctl-forcevers' :
81 { 'help' : 'bridge force stp version',
c6370b56 82 'validvals' : ['rstp', ],
15ef32ea
RP
83 'default' : 'rstp',
84 'required' : False,
9d3f53c6 85 'jsonAttr': 'forceProtocolVersion',
15ef32ea
RP
86 'example' : ['mstpctl-forcevers rstp']},
87 'mstpctl-portpathcost' :
88 { 'help' : 'bridge port path cost',
482b2fab 89 'validvals': ['<interface-range-list>'],
c6370b56 90 'validrange' : ['0', '65535'],
15ef32ea 91 'default' : '0',
b97687bc 92 'jsonAttr' : 'adminExtPortCost',
15ef32ea 93 'required' : False,
c6370b56
DW
94 'example' : ['under the bridge: mstpctl-portpathcost swp1=0 swp2=1',
95 'under the port (recommended): mstpctl-portpathcost 0']},
15ef32ea
RP
96 'mstpctl-portp2p' :
97 { 'help' : 'bridge port p2p detection mode',
e759a20a 98 'default' : 'auto',
b97687bc 99 'jsonAttr' : 'adminPointToPoint',
482b2fab 100 'validvals' : ['<interface-yes-no-auto-list>'],
15ef32ea 101 'required' : False,
c6370b56
DW
102 'example' : ['under the bridge: mstpctl-portp2p swp1=yes swp2=no',
103 'under the port (recommended): mstpctl-portp2p yes']},
15ef32ea
RP
104 'mstpctl-portrestrrole' :
105 { 'help' :
106 'enable/disable port ability to take root role of the port',
107 'default' : 'no',
b97687bc 108 'jsonAttr' : 'restrictedRole',
482b2fab 109 'validvals' : ['<interface-yes-no-list>'],
15ef32ea 110 'required' : False,
c6370b56
DW
111 'example' : ['under the bridge: mstpctl-portrestrrole swp1=yes swp2=no',
112 'under the port (recommended): mstpctl-portrestrrole yes']},
15ef32ea
RP
113 'mstpctl-portrestrtcn' :
114 { 'help' :
115 'enable/disable port ability to propagate received topology change notification of the port',
116 'default' : 'no',
b97687bc 117 'jsonAttr' : 'restrictedTcn',
482b2fab 118 'validvals' : ['<interface-yes-no-list>'],
15ef32ea 119 'required' : False,
c6370b56
DW
120 'example' : ['under the bridge: mstpctl-portrestrtcn swp1=yes swp2=no',
121 'under the port (recommended): mstpctl-portrestrtcn yes']},
15ef32ea
RP
122 'mstpctl-bpduguard' :
123 { 'help' :
124 'enable/disable bpduguard',
125 'default' : 'no',
b97687bc 126 'jsonAttr' : 'bpduGuardPort',
482b2fab 127 'validvals' : ['<interface-yes-no-list>'],
15ef32ea 128 'required' : False,
c6370b56
DW
129 'example' : ['under the bridge: mstpctl-bpduguard swp1=yes swp2=no',
130 'under the port (recommended): mstpctl-bpduguard yes']},
15ef32ea
RP
131 'mstpctl-treeportprio' :
132 { 'help' :
133 'port priority for MSTI instance',
134 'default' : '128',
482b2fab 135 'validvals': ['<interface-range-list>'],
15ef32ea 136 'validrange' : ['0', '240'],
9d3f53c6 137 'jsonAttr': 'treeportprio',
15ef32ea 138 'required' : False,
c6370b56
DW
139 'example' : ['under the bridge: mstpctl-treeportprio swp1=128 swp2=128',
140 'under the port (recommended): mstpctl-treeportprio 128']},
15ef32ea
RP
141 'mstpctl-hello' :
142 { 'help' : 'set hello time',
c6370b56 143 'validrange' : ['0', '255'],
15ef32ea
RP
144 'default' : '2',
145 'required' : False,
9d3f53c6 146 'jsonAttr': 'portHelloTime',
15ef32ea
RP
147 'example' : ['mstpctl-hello 2']},
148 'mstpctl-portnetwork' :
149 { 'help' : 'enable/disable bridge assurance capability for a port',
482b2fab 150 'validvals' : ['<interface-yes-no-list>'],
15ef32ea 151 'default' : 'no',
b97687bc 152 'jsonAttr' : 'networkPort',
15ef32ea 153 'required' : False,
c6370b56
DW
154 'example' : ['under the bridge: mstpctl-portnetwork swp1=yes swp2=no',
155 'under the port (recommended): mstpctl-portnetwork yes']},
15ef32ea
RP
156 'mstpctl-portadminedge' :
157 { 'help' : 'enable/disable initial edge state of the port',
482b2fab 158 'validvals' : ['<interface-yes-no-list>'],
15ef32ea 159 'default' : 'no',
b97687bc 160 'jsonAttr' : 'adminEdgePort',
15ef32ea 161 'required' : False,
c6370b56
DW
162 'example' : ['under the bridge: mstpctl-portadminedge swp1=yes swp2=no',
163 'under the port (recommended): mstpctl-portadminedge yes']},
15ef32ea
RP
164 'mstpctl-portautoedge' :
165 { 'help' : 'enable/disable auto transition to/from edge state of the port',
482b2fab 166 'validvals' : ['<interface-yes-no-list>'],
be1faada 167 'default' : 'yes',
b97687bc 168 'jsonAttr' : 'autoEdgePort',
15ef32ea 169 'required' : False,
c6370b56
DW
170 'example' : ['under the bridge: mstpctl-portautoedge swp1=yes swp2=no',
171 'under the port (recommended): mstpctl-portautoedge yes']},
15ef32ea
RP
172 'mstpctl-treeportcost' :
173 { 'help' : 'port tree cost',
c6370b56 174 'validrange' : ['0', '255'],
9d3f53c6
JF
175 'required' : False,
176 'jsonAttr': 'extPortCost',
177 },
15ef32ea 178 'mstpctl-portbpdufilter' :
9e012f9e
RP
179 { 'help' : 'enable/disable bpdu filter on a port. ' +
180 'syntax varies when defined under a bridge ' +
181 'vs under a port',
482b2fab 182 'validvals' : ['<interface-yes-no-list>'],
b97687bc 183 'jsonAttr' : 'bpduFilterPort',
15ef32ea
RP
184 'default' : 'no',
185 'required' : False,
9e012f9e
RP
186 'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
187 'under a port: mstpctl-portbpdufilter yes']},
15ef32ea
RP
188 }}
189
4c39c7b8
RP
190 # Maps mstp bridge attribute names to corresponding mstpctl commands
191 # XXX: This can be encoded in the modules dict above
192 _attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
193 ('mstpctl-ageing' , 'ageing'),
4c39c7b8 194 ('mstpctl-fdelay' , 'fdelay'),
caa23e5f 195 ('mstpctl-maxage' , 'maxage'),
4c39c7b8
RP
196 ('mstpctl-maxhops' , 'maxhops'),
197 ('mstpctl-txholdcount' , 'txholdcount'),
198 ('mstpctl-forcevers', 'forcevers'),
199 ('mstpctl-hello' , 'hello')])
200
201 # Maps mstp port attribute names to corresponding mstpctl commands
202 # XXX: This can be encoded in the modules dict above
e1601369
RP
203 _port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
204 'mstpctl-portadminedge' : 'portadminedge',
d8e3554d 205 'mstpctl-portautoedge' : 'portautoedge' ,
e1601369
RP
206 'mstpctl-portp2p' : 'portp2p',
207 'mstpctl-portrestrrole' : 'portrestrrole',
208 'mstpctl-portrestrtcn' : 'portrestrtcn',
15ef32ea 209 'mstpctl-bpduguard' : 'bpduguard',
e1601369
RP
210 'mstpctl-treeportprio' : 'treeportprio',
211 'mstpctl-treeportcost' : 'treeportcost',
212 'mstpctl-portnetwork' : 'portnetwork',
213 'mstpctl-portbpdufilter' : 'portbpdufilter'}
15ef32ea
RP
214
215 def __init__(self, *args, **kargs):
216 moduleBase.__init__(self, *args, **kargs)
217 self.ipcmd = None
4c773918 218 self.name = self.__class__.__name__
15ef32ea
RP
219 self.brctlcmd = None
220 self.mstpctlcmd = None
5f8c03e7
RP
221 self.mstpd_running = (True if systemUtils.is_process_running('mstpd')
222 else False)
2e4dc724
N
223 self.default_vxlan_ports_set_bpduparams = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='mstpctl-vxlan-always-set-bpdu-params')
224 if self.default_vxlan_ports_set_bpduparams == 'yes':
225 self.default_vxlan_ports_set_bpduparams = True
226 else:
227 self.default_vxlan_ports_set_bpduparams = False
15ef32ea 228
8252491e
JF
229 def syntax_check(self, ifaceobj):
230 if self._is_bridge(ifaceobj):
231 if (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE
232 and ifaceobj.get_attr_value_first('mstpctl-portadminedge')):
233 self.logger.error('%s: unsupported use of keyword '
234 '\'mstpctl-portadminedge\' when '
235 'bridge-vlan-aware is on'
236 % ifaceobj.name)
237 return False
238 return True
239
15ef32ea
RP
240 def _is_bridge(self, ifaceobj):
241 if (ifaceobj.get_attr_value_first('mstpctl-ports') or
84ca006f
RP
242 ifaceobj.get_attr_value_first('bridge-ports')):
243 return True
244 return False
245
246 def _is_bridge_port(self, ifaceobj):
247 if self.brctlcmd.is_bridge_port(ifaceobj.name):
15ef32ea
RP
248 return True
249 return False
250
251 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
252 if not self._is_bridge(ifaceobj):
253 return None
0c8332bc
RP
254 return self.parse_port_list(ifaceobj.name,
255 ifaceobj.get_attr_value_first(
15ef32ea
RP
256 'mstpctl-ports'), ifacenames_all)
257
258 def get_dependent_ifacenames_running(self, ifaceobj):
259 self._init_command_handlers()
260 if (self.brctlcmd.bridge_exists(ifaceobj.name) and
261 not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
262 return None
263 return self.brctlcmd.get_bridge_ports(ifaceobj.name)
264
9d3f53c6
JF
265 def _get_bridge_port_attr_value(self, bridgename, portname, attr):
266 json_attr = self.get_mod_subattr(attr, 'jsonAttr')
267 return self.mstpctlcmd.get_bridge_port_attr(bridgename,
268 portname,
269 json_attr)
270
15ef32ea
RP
271 def _get_bridge_port_list(self, ifaceobj):
272
273 # port list is also available in the previously
274 # parsed dependent list. Use that if available, instead
275 # of parsing port expr again
276 port_list = ifaceobj.lowerifaces
277 if port_list:
278 return port_list
279 ports = ifaceobj.get_attr_value_first('mstpctl-ports')
280 if ports:
0c8332bc 281 return self.parse_port_list(ifaceobj.name, ports)
15ef32ea
RP
282 else:
283 return None
284
404cc695
RP
285 def _ports_enable_disable_ipv6(self, ports, enable='1'):
286 for p in ports:
287 try:
288 self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
289 '/disable_ipv6', enable)
290 except Exception, e:
291 self.logger.info(str(e))
292 pass
293
15ef32ea
RP
294 def _add_ports(self, ifaceobj):
295 bridgeports = self._get_bridge_port_list(ifaceobj)
296
297 runningbridgeports = []
298 # Delete active ports not in the new port list
fc5e1735 299 if not ifupdownflags.flags.PERFMODE:
15ef32ea
RP
300 runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
301 if runningbridgeports:
302 [self.ipcmd.link_set(bport, 'nomaster')
303 for bport in runningbridgeports
304 if not bridgeports or bport not in bridgeports]
305 else:
306 runningbridgeports = []
307 if not bridgeports:
308 return
309 err = 0
310 for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
311 try:
fc5e1735
RP
312 if (not ifupdownflags.flags.DRYRUN and
313 not self.ipcmd.link_exists(bridgeport)):
15ef32ea
RP
314 self.log_warn('%s: bridge port %s does not exist'
315 %(ifaceobj.name, bridgeport))
316 err += 1
317 continue
318 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
15ef32ea
RP
319 self.ipcmd.addr_flush(bridgeport)
320 except Exception, e:
bf3eda91 321 self.log_error(str(e), ifaceobj)
404cc695 322
15ef32ea
RP
323 if err:
324 self.log_error('error configuring bridge (missing ports)')
325
326 def _apply_bridge_settings(self, ifaceobj):
fc5e1735 327 check = False if ifupdownflags.flags.PERFMODE else True
15ef32ea 328 try:
4c39c7b8
RP
329 # set bridge attributes
330 for attrname, dstattrname in self._attrs_map.items():
331 try:
332 v = ifaceobj.get_attr_value_first(attrname)
2722bb19
ST
333 if not v:
334 continue
4c39c7b8
RP
335 if attrname == 'mstpctl-treeprio':
336 self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
337 v, check)
338 else:
339 self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
340 dstattrname, v, check)
341 except Exception, e:
342 self.logger.warn('%s' %str(e))
343 pass
15ef32ea 344
bb70f923
N
345 if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
346 return
15ef32ea 347 # set bridge port attributes
4c39c7b8 348 for attrname, dstattrname in self._port_attrs_map.items():
b97687bc
ST
349 config_val = ifaceobj.get_attr_value_first(attrname)
350 default_val = self.get_mod_subattr(attrname,'default')
351 if not config_val:
352 # nothing configured, we may need to reset all ports to defaults
353 # if the default exists and jsonAttribute conversion exists
354 try:
355 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
356 if default_val and jsonAttr:
357 bridgeports = self._get_bridge_port_list(ifaceobj)
358 for port in bridgeports:
bf3eda91
RP
359 if not self.brctlcmd.is_bridge_port(port):
360 continue
9d3f53c6
JF
361 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
362 port,
363 dstattrname,
364 default_val,
365 json_attr=jsonAttr)
b97687bc
ST
366 except:
367 self.logger.info('%s: not resetting %s config'
368 %(ifaceobj.name, attrname))
369 # leave the loop for this attribute
15ef32ea 370 continue
b97687bc
ST
371
372 portlist = self.parse_port_list(ifaceobj.name, config_val)
15ef32ea 373 if not portlist:
bf3eda91
RP
374 self.log_error('%s: error parsing \'%s %s\''
375 %(ifaceobj.name, attrname, config_val), ifaceobj)
15ef32ea 376 continue
b97687bc
ST
377 # there was a configured value so we need to parse it
378 # and set the attribute for each port configured
15ef32ea
RP
379 for p in portlist:
380 try:
381 (port, val) = p.split('=')
42a9d193
RP
382 # if it is not bridge port, continue
383 if not os.path.exists('/sys/class/net/%s/brport' %port):
384 continue
9d3f53c6
JF
385 json_attr = self.get_mod_subattr(attrname, 'jsonAttr')
386 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
387 port,
388 dstattrname,
389 val,
390 json_attr=json_attr)
15ef32ea 391 except Exception, e:
bf3eda91
RP
392 self.log_error('%s: error setting %s (%s)'
393 %(ifaceobj.name, attrname, str(e)),
394 ifaceobj, raise_error=False)
15ef32ea
RP
395 except Exception, e:
396 self.log_warn(str(e))
397 pass
398
2e4dc724
N
399 def _get_default_val(self, attr, ifaceobj, bridgeifaceobj):
400 if ((attr == 'mstpctl-portbpdufilter' or
401 attr == 'mstpctl-bpduguard') and
402 self.default_vxlan_ports_set_bpduparams and
403 (ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
404 try:
405 config_val = bridgeifaceobj.get_attr_value_first(attr)
406 except Exception, e:
407 config_val = None
408 if config_val:
409 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
410 return 'yes'
411 else:
412 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
413 return [v.split('=')[1] for v in config_val.split()][index]
414 else:
415 return 'yes'
416 else:
417 return self.get_mod_subattr(attr,'default')
418
84ca006f 419 def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
641cbd1e
RP
420 bridgeifaceobj=None,
421 stp_running_on=True,
d8e3554d 422 mstpd_running=True):
fc5e1735 423 check = False if ifupdownflags.flags.PERFMODE else True
641cbd1e 424 applied = False
84ca006f
RP
425 if not bridgename and bridgeifaceobj:
426 bridgename = bridgeifaceobj.name
b97687bc
ST
427
428 if not stp_running_on:
429 # stp may get turned on at a later point
430 self.logger.info('%s: ignoring config'
431 %(ifaceobj.name) +
432 ' (stp on bridge %s is not on yet)' %bridgename)
433 return applied
2e4dc724 434 bvlan_aware = self.ipcmd.bridge_is_vlan_aware(bridgename)
b97687bc
ST
435 if (not mstpd_running or
436 not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or
2e4dc724
N
437 not bvlan_aware):
438 if (not bvlan_aware and
439 self.default_vxlan_ports_set_bpduparams and
440 (ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
441 for attr in ['mstpctl-portbpdufilter',
442 'mstpctl-bpduguard']:
9d3f53c6
JF
443 json_attr = self.get_mod_subattr(attr, 'jsonAttr')
444 config_val = self._get_default_val(attr, ifaceobj,
445 bridgeifaceobj)
2e4dc724 446 try:
9d3f53c6
JF
447 self.mstpctlcmd.set_bridge_port_attr(bridgename,
448 ifaceobj.name,
449 self._port_attrs_map[attr],
450 config_val,
451 json_attr=json_attr)
2e4dc724
N
452 except Exception, e:
453 self.log_warn('%s: error setting %s (%s)'
9d3f53c6 454 % (ifaceobj.name, attr, str(e)))
2e4dc724 455 return applied
84ca006f
RP
456 # set bridge port attributes
457 for attrname, dstattrname in self._port_attrs_map.items():
458 attrval = ifaceobj.get_attr_value_first(attrname)
b97687bc 459 config_val = ifaceobj.get_attr_value_first(attrname)
2e4dc724 460 default_val = self._get_default_val(attrname, ifaceobj, bridgeifaceobj)
b97687bc
ST
461 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
462 # to see the running value, stp would have to be on
463 # so we would have parsed mstpctl showportdetail json output
464 try:
9d3f53c6 465 running_val = self.mstpctlcmd.get_bridge_port_attr(bridgename,
b97687bc
ST
466 ifaceobj.name, jsonAttr)
467 except:
468 self.logger.info('%s %s: could not get running %s value'
469 %(bridgename, ifaceobj.name, attrname))
470 running_val = None
471 if (not config_val and default_val and (running_val != default_val)):
472 # this happens when users remove an attribute from a port
473 # and expect the default to be restored with ifreload.
474 config_val = default_val
475 elif not config_val:
476 # there is nothing configured and no default to reset
42a9d193 477 continue
b97687bc 478
84ca006f 479 try:
9d3f53c6
JF
480 self.mstpctlcmd.set_bridge_port_attr(bridgename,
481 ifaceobj.name, dstattrname, config_val, json_attr=jsonAttr)
641cbd1e 482 applied = True
84ca006f 483 except Exception, e:
bf3eda91
RP
484 self.log_error('%s: error setting %s (%s)'
485 %(ifaceobj.name, attrname, str(e)), ifaceobj,
486 raise_error=False)
641cbd1e 487 return applied
84ca006f
RP
488
489 def _apply_bridge_port_settings_all(self, ifaceobj,
490 ifaceobj_getfunc=None):
98b5ee73 491 self.logger.info('%s: applying mstp configuration '
84ca006f 492 %ifaceobj.name + 'specific to ports')
f6a0fa15
RP
493 # Query running bridge ports. and only apply attributes on them
494 bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
4c39c7b8
RP
495 if not bridgeports:
496 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
497 return
84ca006f 498 for bport in bridgeports:
98b5ee73 499 self.logger.info('%s: processing mstp config for port %s'
84ca006f 500 %(ifaceobj.name, bport))
3e6ea735 501 if not self.ipcmd.link_exists(bport):
3e6ea735 502 continue
42a9d193
RP
503 if not os.path.exists('/sys/class/net/%s/brport' %bport):
504 continue
84ca006f
RP
505 bportifaceobjlist = ifaceobj_getfunc(bport)
506 if not bportifaceobjlist:
507 continue
508 for bportifaceobj in bportifaceobjlist:
98b5ee73 509 # Dont process bridge port if it already has been processed
4c773918
ST
510 if (bportifaceobj.module_flags.get(self.name,0x0) & \
511 mstpctlFlags.PORT_PROCESSED):
98b5ee73 512 continue
15ef32ea 513 try:
2e4dc724 514 self._apply_bridge_port_settings(bportifaceobj,
84ca006f 515 ifaceobj.name, ifaceobj)
15ef32ea 516 except Exception, e:
2e4dc724 517 pass
84ca006f 518 self.log_warn(str(e))
15ef32ea 519
641cbd1e
RP
520 def _is_running_userspace_stp_state_on(self, bridgename):
521 stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
522 if not stp_state_file:
523 return False
524 running_stp_state = self.read_file_oneline(stp_state_file)
525 if running_stp_state and running_stp_state == '2':
526 return True
527 return False
528
84ca006f 529 def _up(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 530 # Check if bridge port
98b5ee73
RP
531 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
532 if bridgename:
5f8c03e7 533 mstpd_running = self.mstpd_running
641cbd1e
RP
534 stp_running_on = self._is_running_userspace_stp_state_on(bridgename)
535 applied = self._apply_bridge_port_settings(ifaceobj, bridgename,
536 None, stp_running_on,
537 mstpd_running)
538 if applied:
539 ifaceobj.module_flags[self.name] = \
540 ifaceobj.module_flags.setdefault(self.name,0) | \
541 mstpctlFlags.PORT_PROCESSED
15ef32ea 542 return
39804250
RP
543 if not self._is_bridge(ifaceobj):
544 return
b97687bc 545 # we are now here because the ifaceobj is a bridge
15ef32ea
RP
546 stp = None
547 try:
548 porterr = False
549 porterrstr = ''
550 if ifaceobj.get_attr_value_first('mstpctl-ports'):
551 # If bridge ports specified with mstpctl attr, create the
552 # bridge and also add its ports
553 self.ipcmd.batch_start()
fc5e1735 554 if not ifupdownflags.flags.PERFMODE:
15ef32ea
RP
555 if not self.ipcmd.link_exists(ifaceobj.name):
556 self.ipcmd.link_create(ifaceobj.name, 'bridge')
557 else:
558 self.ipcmd.link_create(ifaceobj.name, 'bridge')
559 try:
560 self._add_ports(ifaceobj)
561 except Exception, e:
562 porterr = True
563 porterrstr = str(e)
564 pass
565 finally:
566 self.ipcmd.batch_commit()
d5c0f703
RP
567 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
568 if running_ports:
569 # disable ipv6 for ports that were added to bridge
570 self._ports_enable_disable_ipv6(running_ports, '1')
404cc695 571
15ef32ea
RP
572 stp = ifaceobj.get_attr_value_first('mstpctl-stp')
573 if stp:
574 self.set_iface_attr(ifaceobj, 'mstpctl-stp',
575 self.brctlcmd.set_stp)
576 else:
577 stp = self.brctlcmd.get_stp(ifaceobj.name)
5f8c03e7 578 if (self.mstpd_running and
15ef32ea
RP
579 (stp == 'yes' or stp == 'on')):
580 self._apply_bridge_settings(ifaceobj)
84ca006f
RP
581 self._apply_bridge_port_settings_all(ifaceobj,
582 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 583 except Exception, e:
bf3eda91 584 self.log_error(str(e), ifaceobj)
15ef32ea
RP
585 if porterr:
586 raise Exception(porterrstr)
587
84ca006f
RP
588 def _down(self, ifaceobj, ifaceobj_getfunc=None):
589 if not self._is_bridge(ifaceobj):
590 return
15ef32ea
RP
591 try:
592 if ifaceobj.get_attr_value_first('mstpctl-ports'):
593 # If bridge ports specified with mstpctl attr, delete the
594 # bridge
595 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
596 if ports:
404cc695 597 self._ports_enable_disable_ipv6(ports, '0')
15ef32ea
RP
598 self.brctlcmd.delete_bridge(ifaceobj.name)
599 except Exception, e:
bf3eda91 600 self.log_error(str(e), ifaceobj)
15ef32ea 601
0dd2f0d1 602 def _query_running_attrs(self, ifaceobjrunning, bridge_vlan_aware=False):
15ef32ea
RP
603 bridgeattrdict = {}
604
605 tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
9d3f53c6 606 #self.logger.info('A' + str(tmpbridgeattrdict))
15ef32ea
RP
607 if not tmpbridgeattrdict:
608 return bridgeattrdict
609
610 for k,v in tmpbridgeattrdict.items():
611 if k == 'stp' or not v:
612 continue
613 if k == 'ports':
614 ports = v.keys()
615 continue
616 attrname = 'mstpctl-' + k
0dd2f0d1
N
617 if (v and v != self.get_mod_subattr(attrname, 'default')
618 and attrname != 'mstpctl-maxhops'):
15ef32ea
RP
619 bridgeattrdict[attrname] = [v]
620
621 ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
0dd2f0d1
N
622 # Do this only for vlan-UNAWARE-bridge
623 if ports and not bridge_vlan_aware:
22945dd6
N
624 portconfig = {'mstpctl-portautoedge' : '',
625 'mstpctl-portbpdufilter' : '',
626 'mstpctl-portnetwork' : '',
15ef32ea
RP
627 'mstpctl-portpathcost' : '',
628 'mstpctl-portadminedge' : '',
15ef32ea
RP
629 'mstpctl-portp2p' : '',
630 'mstpctl-portrestrrole' : '',
631 'mstpctl-portrestrtcn' : '',
632 'mstpctl-bpduguard' : '',
633 'mstpctl-treeportprio' : '',
634 'mstpctl-treeportcost' : ''}
635
636 for p in ports:
9d3f53c6
JF
637
638 for attr in ['mstpctl-portautoedge',
639 'mstpctl-portbpdufilter',
640 'mstpctl-portnetwork',
641 'mstpctl-portadminedge',
642 'mstpctl-portp2p',
643 'mstpctl-portrestrrole',
644 'mstpctl-portrestrtcn',
645 'mstpctl-bpduguard',
646 '']:
647 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
648 p, attr)
649 if v and v != 'no':
650 portconfig[attr] += ' %s=%s' % (p, v)
651
652 for attr in ['mstpctl-portpathcost', 'mstpctl-treeportcost']:
653 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
654 p, attr)
655 if v and v != self.get_mod_subattr(attr, 'default'):
656 portconfig[attr] += ' %s=%s' % (p, v)
15ef32ea
RP
657
658 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
659 if v})
15ef32ea
RP
660 return bridgeattrdict
661
2e4dc724
N
662 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
663 ifaceobj_getfunc=None):
15ef32ea
RP
664 # list of attributes that are not supported currently
665 blacklistedattrs = ['mstpctl-portpathcost',
666 'mstpctl-treeportprio', 'mstpctl-treeportcost']
667 if not self.brctlcmd.bridge_exists(ifaceobj.name):
668 self.logger.debug('bridge %s does not exist' %ifaceobj.name)
15ef32ea
RP
669 return
670 ifaceattrs = self.dict_key_subset(ifaceobj.config,
671 self.get_mod_attrs())
2e4dc724
N
672 if self.default_vxlan_ports_set_bpduparams:
673 for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
674 if attr not in ifaceattrs:
675 ifaceattrs.append(attr)
15ef32ea
RP
676 if not ifaceattrs:
677 return
678 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
9d3f53c6 679 #self.logger.info('B' + str(runningattrs))
15ef32ea
RP
680 if not runningattrs:
681 runningattrs = {}
2e4dc724 682 running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
15ef32ea
RP
683 for k in ifaceattrs:
684 # for all mstpctl options
685 if k in blacklistedattrs:
686 continue
2e4dc724
N
687 if ((k == 'mstpctl-portbpdufilter' or
688 k == 'mstpctl-bpduguard')):
689 #special case, 'ifquery --check --with-defaults' on a VLAN
690 #unaware bridge
691 if not running_port_list:
692 continue
693 v = ifaceobj.get_attr_value_first(k)
694 config_val = {}
695 running_val = {}
696 result = 0
697 bridge_ports = {}
698 state = ''
699 if v:
700 for bportval in v.split():
701 config_val[bportval.split('=')[0]] = bportval.split('=')[1]
702 #for bport in bridgeports:
703 for bport in running_port_list:
704 bportifaceobjlist = ifaceobj_getfunc(bport)
705 if not bportifaceobjlist:
706 continue
707 for bportifaceobj in bportifaceobjlist:
708 if (bport not in config_val):
709 if (bportifaceobj.link_kind & ifaceLinkKind.VXLAN):
710 if (not ifupdownflags.flags.WITHDEFAULTS or
711 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
712 continue
713 conf = 'yes'
714 else:
715 continue
716 else:
717 if ((bportifaceobj.link_kind & ifaceLinkKind.VXLAN) and
718 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
719 continue
720 conf = config_val[bport]
721 jsonAttr = self.get_mod_subattr(k, 'jsonAttr')
722 try:
9d3f53c6 723 running_val = self.mstpctlcmd.get_bridge_port_attr(ifaceobj.name, bport, jsonAttr)
2e4dc724
N
724 except:
725 self.logger.info('%s %s: could not get running %s value'
726 %(ifaceobj.name, bport, attr))
727 running_val = None
728 if conf != running_val:
729 result = 1
730 bridge_ports.update({bport : running_val})
731 for port, val in bridge_ports.items():
732 #running state format
733 #mstpctl-portbpdufilter swp2=yes swp1=yes vx-14567101=yes [pass]
734 #mstpctl-bpduguard swp2=yes swp1=yes vx-14567101=yes [pass]
735 state += port + '=' + val + ' '
736 if state:
737 ifaceobjcurr.update_config_with_status(k, state, result)
738 continue
739
15ef32ea
RP
740 # get the corresponding ifaceobj attr
741 v = ifaceobj.get_attr_value_first(k)
742 if not v:
743 continue
744
745 # Get the running attribute
746 rv = runningattrs.get(k[8:])
747 if k == 'mstpctl-stp':
748 # special case stp compare because it may
749 # contain more than one valid values
750 stp_on_vals = ['on', 'yes']
751 stp_off_vals = ['off']
752 rv = self.brctlcmd.get_stp(ifaceobj.name)
753 if ((v in stp_on_vals and rv in stp_on_vals) or
754 (v in stp_off_vals and rv in stp_off_vals)):
755 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
756 else:
757 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
758 continue
759
760 if k == 'mstpctl-ports':
761 # special case ports because it can contain regex or glob
762 # XXX: We get all info from mstputils, which means if
763 # mstpd is down, we will not be returning any bridge bridgeports
15ef32ea
RP
764 bridge_port_list = self._get_bridge_port_list(ifaceobj)
765 if not running_port_list and not bridge_port_list:
766 continue
767 portliststatus = 1
768 if running_port_list and bridge_port_list:
769 difference = Set(running_port_list).symmetric_difference(
770 Set(bridge_port_list))
771 if not difference:
772 portliststatus = 0
773 ifaceobjcurr.update_config_with_status('mstpctl-ports',
774 ' '.join(running_port_list)
775 if running_port_list else '', portliststatus)
776 elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
777 # Now, look at port attributes
778 # derive the mstpctlcmd attr name
779 #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
780 mstpctlcmdattrname = k[8:]
781
782 # for port attributes, the attributes are in a list
783 # <portname>=<portattrvalue>
784 status = 0
785 currstr = ''
0c8332bc 786 vlist = self.parse_port_list(ifaceobj.name, v)
15ef32ea
RP
787 if not vlist:
788 continue
789 for vlistitem in vlist:
790 try:
791 (p, v) = vlistitem.split('=')
9d3f53c6 792 currv = self._get_bridge_port_attr_value(ifaceobj.name, p, k)
15ef32ea
RP
793 if currv:
794 currstr += ' %s=%s' %(p, currv)
795 else:
796 currstr += ' %s=%s' %(p, 'None')
797 if currv != v:
798 status = 1
799 except Exception, e:
800 self.log_warn(str(e))
801 pass
802 ifaceobjcurr.update_config_with_status(k, currstr, status)
803 elif not rv:
804 ifaceobjcurr.update_config_with_status(k, '', 1)
805 elif v != rv:
806 ifaceobjcurr.update_config_with_status(k, rv, 1)
807 else:
808 ifaceobjcurr.update_config_with_status(k, rv, 0)
809
2e4dc724
N
810 def _query_check_bridge_vxlan_port(self, ifaceobj, ifaceobjcurr,
811 ifaceobj_getfunc=None):
812 masters = ifaceobj.upperifaces
813 if not masters:
814 return
815 for bridge in masters:
816 bifaceobjlist = ifaceobj_getfunc(bridge)
817 for bifaceobj in bifaceobjlist:
818 if (self._is_bridge(bifaceobj) and
819 self.default_vxlan_ports_set_bpduparams and
820 (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
821 for attr in ['mstpctl-portbpdufilter',
822 'mstpctl-bpduguard']:
823 jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
824 config_val = bifaceobj.get_attr_value_first(attr)
825 if config_val:
826 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
827 if not ifupdownflags.flags.WITHDEFAULTS:
828 continue
829 config_val = 'yes'
830 else:
831 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
832 config_val = [v.split('=')[1] for v in config_val.split()][index]
833 else:
834 if not ifupdownflags.flags.WITHDEFAULTS:
835 continue
836 config_val = 'yes'
837 try:
9d3f53c6 838 running_val = self.mstpctlcmd.get_bridge_port_attr(bifaceobj.name,
2e4dc724
N
839 ifaceobj.name, jsonAttr)
840 except:
841 self.logger.info('%s %s: could not get running %s value'
842 %(bifaceobj.name, ifaceobj.name, attr))
843 running_val = None
844 ifaceobjcurr.update_config_with_status(attr,
845 running_val,
846 0 if running_val == config_val else 1)
847 return
848
849
84ca006f 850 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
19f90a91 851 if not self.ipcmd.link_exists(ifaceobj.name):
3e6ea735 852 #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
15ef32ea
RP
853 ifaceobjcurr.status = ifaceStatus.NOTFOUND
854 return
e1601369 855 # Check if this is a bridge port
19f90a91 856 if not self._is_bridge_port(ifaceobj):
e1601369 857 # mark all the bridge attributes as error
a070c90e 858 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
e1601369
RP
859 self._port_attrs_map.keys(), 0)
860 return
98b5ee73 861 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
e1601369 862 # list of attributes that are not supported currently
16d854b4
RP
863 blacklistedattrs = ['mstpctl-portpathcost',
864 'mstpctl-treeportprio', 'mstpctl-treeportcost']
15ef32ea
RP
865 ifaceattrs = self.dict_key_subset(ifaceobj.config,
866 self._port_attrs_map.keys())
867 if not ifaceattrs:
868 return
869 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
9d3f53c6 870 #self.logger.info('C' + str(runningattrs))
15ef32ea
RP
871 if not runningattrs:
872 runningattrs = {}
873 for k in ifaceattrs:
874 # for all mstpctl options
15ef32ea
RP
875 # get the corresponding ifaceobj attr
876 v = ifaceobj.get_attr_value_first(k)
16d854b4 877 if not v or k in blacklistedattrs:
e1601369 878 ifaceobjcurr.update_config_with_status(k, v, -1)
15ef32ea 879 continue
9d3f53c6 880 currv = self._get_bridge_port_attr_value(bridgename, ifaceobj.name, k)
15ef32ea
RP
881 if currv:
882 if currv != v:
883 ifaceobjcurr.update_config_with_status(k, currv, 1)
884 else:
885 ifaceobjcurr.update_config_with_status(k, currv, 0)
886 else:
887 ifaceobjcurr.update_config_with_status(k, None, 1)
888
84ca006f 889 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
e1601369 890 if self._is_bridge(ifaceobj):
2e4dc724
N
891 self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
892 elif ifaceobj.link_kind & ifaceLinkKind.VXLAN:
893 self._query_check_bridge_vxlan_port(ifaceobj, ifaceobjcurr,
894 ifaceobj_getfunc)
e1601369
RP
895 else:
896 self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
15ef32ea 897
9d3f53c6
JF
898 def _query_bridge_port_attr(self, ifaceobjrunning, bridgename, attr, value_cmp):
899 v = self._get_bridge_port_attr_value(bridgename,
900 ifaceobjrunning.name,
901 attr)
902 if v and value_cmp and v != value_cmp:
903 ifaceobjrunning.update_config(attr, v)
904 elif v and not value_cmp:
905 ifaceobjrunning.update_config(attr, v)
906
e1601369
RP
907 def _query_running_bridge_port(self, ifaceobjrunning):
908 bridgename = self.ipcmd.bridge_port_get_bridge_name(
909 ifaceobjrunning.name)
910 if not bridgename:
911 self.logger.warn('%s: unable to determine bridgename'
912 %ifaceobjrunning.name)
15ef32ea 913 return
e1601369
RP
914 if self.brctlcmd.get_stp(bridgename) == 'no':
915 # This bridge does not run stp, return
916 return
15ef32ea 917 # if userspace stp not set, return
9d3f53c6
JF
918 if self.systcl_get_net_bridge_stp_user_space() != '1':
919 return
920
921 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
922 'mstpctl-portautoedge',
923 self.get_mod_subattr('mstpctl-portautoedge', 'default'))
924
925 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
926 'mstpctl-portbpdufilter',
927 'no')
22945dd6 928
9d3f53c6
JF
929 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
930 'mstpctl-portnetwork',
931 'no')
e1601369
RP
932
933 # XXX: Can we really get path cost of a port ???
934 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
935 #if v and v != self.get_mod_subattr('mstpctl-pathcost',
936 # 'default'):
937 # ifaceobjrunning.update_config('mstpctl-network', v)
938
9d3f53c6
JF
939 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
940 'mstpctl-portadminedge',
941 'no')
e1601369 942
9d3f53c6
JF
943 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
944 'mstpctl-portp2p',
945 'auto')
e1601369 946
9d3f53c6
JF
947 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
948 'mstpctl-portrestrrole',
949 'no')
e1601369 950
9d3f53c6
JF
951 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
952 'mstpctl-portrestrtcn',
953 'no')
e1601369 954
9d3f53c6
JF
955 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
956 'mstpctl-bpduguard',
957 'no')
e1601369
RP
958
959 # XXX: Can we really get path cost of a port ???
960 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
961 # p, 'treeprio')
962 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
963 # 'default'):
964 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
965
966 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
967 # p, 'treecost')
968 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
969 # 'default'):
970 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
971
972 def _query_running_bridge(self, ifaceobjrunning):
973 if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
974 # This bridge does not run stp, return
975 return
976 # if userspace stp not set, return
9d3f53c6
JF
977 if self.systcl_get_net_bridge_stp_user_space() != '1':
978 return
15ef32ea
RP
979 # Check if mstp really knows about this bridge
980 if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
981 return
0dd2f0d1
N
982 bridge_vlan_aware = False
983 if ifaceobjrunning.get_attr_value_first('bridge-vlan-aware') == 'yes':
984 bridge_vlan_aware = True
15ef32ea 985 ifaceobjrunning.update_config_dict(self._query_running_attrs(
0dd2f0d1
N
986 ifaceobjrunning,
987 bridge_vlan_aware))
15ef32ea 988
e1601369
RP
989 def _query_running(self, ifaceobjrunning, **extra_args):
990 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
991 self._query_running_bridge(ifaceobjrunning)
992 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
993 self._query_running_bridge_port(ifaceobjrunning)
994
2e4dc724
N
995 def _query(self, ifaceobj, ifaceobj_getfunc=None, **kwargs):
996 """ add default policy attributes supported by the module """
997 if not self._is_bridge(ifaceobj):
998 return
999 lowerinfs = ifaceobj.lowerifaces
1000 if not lowerinfs:
1001 return
1002 if ifaceobj.get_attr_value_first('bridge-vlan-aware') != 'yes':
1003 for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
1004 state = ''
1005 config = ifaceobj.get_attr_value_first(attr)
1006 for port in lowerinfs:
1007 bportobjlist = ifaceobj_getfunc(port)
1008 for bportobj in bportobjlist:
1009 if bportobj.get_attr_value_first('vxlan-id'):
1010 if config:
1011 if port not in [v.split('=')[0] for v in config.split()]:
1012 config += ' %s=yes' %port
1013 else:
1014 state += '%s=yes ' %port
1015 ifaceobj.replace_config(attr, config if config else state)
1016 else:
1017 for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
1018 state = ''
1019 config = ifaceobj.get_attr_value_first(attr)
1020 for port in lowerinfs:
1021 bportobjlist = ifaceobj_getfunc(port)
1022 for bportobj in bportobjlist:
1023 if bportobj.get_attr_value_first('vxlan-id'):
1024 if config:
1025 if port not in [v.split('=')[0] for v in config.split()]:
1026 bportobj.update_config(attr, 'yes')
1027 else:
1028 index = [v.split('=')[0] for v in config.split()].index(port)
1029 state = [v.split('=')[1] for v in config.split()][index]
1030 bportobj.update_config(attr, '%s' %state)
1031 v = config.split()
1032 del v[index]
1033 config = ' '.join(v)
1034 else:
1035 bportobj.update_config(attr, 'yes')
1036 if config:
1037 ifaceobj.replace_config(attr, config)
1038 else:
1039 ifaceobj.replace_config(attr, '')
1040
1041
1042
15ef32ea
RP
1043 _run_ops = {'pre-up' : _up,
1044 'post-down' : _down,
1045 'query-checkcurr' : _query_check,
2e4dc724
N
1046 'query-running' : _query_running,
1047 'query' : _query}
15ef32ea
RP
1048
1049 def get_ops(self):
1050 """ returns list of ops supported by this module """
1051 return self._run_ops.keys()
1052
1053 def _init_command_handlers(self):
15ef32ea 1054 if not self.ipcmd:
fc5e1735 1055 self.ipcmd = iproute2()
15ef32ea 1056 if not self.brctlcmd:
fc5e1735 1057 self.brctlcmd = brctl()
15ef32ea 1058 if not self.mstpctlcmd:
fc5e1735 1059 self.mstpctlcmd = mstpctlutil()
15ef32ea 1060
84ca006f
RP
1061 def run(self, ifaceobj, operation, query_ifaceobj=None,
1062 ifaceobj_getfunc=None, **extra_args):
15ef32ea
RP
1063 """ run mstp configuration on the interface object passed as argument
1064
1065 Args:
1066 **ifaceobj** (object): iface object
1067
1068 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1069 'query-running'
1070 Kwargs:
1071 **query_ifaceobj** (object): query check ifaceobject. This is only
1072 valid when op is 'query-checkcurr'. It is an object same as
1073 ifaceobj, but contains running attribute values and its config
1074 status. The modules can use it to return queried running state
1075 of interfaces. status is success if the running state is same
1076 as user required state in ifaceobj. error otherwise.
1077 """
3e6ea735
RP
1078 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1079 return
15ef32ea
RP
1080 op_handler = self._run_ops.get(operation)
1081 if not op_handler:
1082 return
15ef32ea
RP
1083 self._init_command_handlers()
1084 if operation == 'query-checkcurr':
84ca006f
RP
1085 op_handler(self, ifaceobj, query_ifaceobj,
1086 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 1087 else:
84ca006f 1088 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)