]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/mstpctl.py
Revert "ifupdown not restoring mstpctl attributes (e.g. bpdufilter, bpduguard) in...
[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 *
10from ifupdownaddons.modulebase import moduleBase
11from ifupdownaddons.bridgeutils import brctl
12from ifupdownaddons.iproute2 import iproute2
13from ifupdownaddons.mstpctlutil import mstpctlutil
14import traceback
15
4c773918
ST
16class mstpctlFlags:
17 PORT_PROCESSED = 0x1
18
15ef32ea
RP
19class mstpctl(moduleBase):
20 """ ifupdown2 addon module to configure mstp attributes """
21
22 _modinfo = {'mhelp' : 'mstp configuration module for bridges',
23 'attrs' : {
24 'mstpctl-ports' :
25 {'help' : 'mstp ports',
26 'compat' : True},
27 'mstpctl-stp' :
28 {'help': 'bridge stp yes/no',
29 'compat' : True,
30 'default' : 'no'},
31 'mstpctl-treeprio' :
32 {'help': 'tree priority',
33 'default' : '32768',
34 'validrange' : ['0', '65535'],
35 'required' : False,
36 'example' : ['mstpctl-treeprio 32768']},
37 'mstpctl-ageing' :
38 {'help': 'ageing time',
39 'default' : '300',
40 'required' : False,
41 'example' : ['mstpctl-ageing 300']},
42 'mstpctl-maxage' :
43 { 'help' : 'max message age',
44 'default' : '20',
45 'required' : False,
46 'example' : ['mstpctl-maxage 20']},
47 'mstpctl-fdelay' :
48 { 'help' : 'set forwarding delay',
49 'default' : '15',
50 'required' : False,
51 'example' : ['mstpctl-fdelay 15']},
52 'mstpctl-maxhops' :
53 { 'help' : 'bridge max hops',
54 'default' : '15',
55 'required' : False,
56 'example' : ['mstpctl-maxhops 15']},
57 'mstpctl-txholdcount' :
58 { 'help' : 'bridge transmit holdcount',
59 'default' : '6',
60 'required' : False,
61 'example' : ['mstpctl-txholdcount 6']},
62 'mstpctl-forcevers' :
63 { 'help' : 'bridge force stp version',
64 'default' : 'rstp',
65 'required' : False,
66 'example' : ['mstpctl-forcevers rstp']},
67 'mstpctl-portpathcost' :
68 { 'help' : 'bridge port path cost',
69 'default' : '0',
70 'required' : False,
71 'example' : ['mstpctl-portpathcost swp1=0 swp2=1']},
15ef32ea
RP
72 'mstpctl-portp2p' :
73 { 'help' : 'bridge port p2p detection mode',
e759a20a
RP
74 'default' : 'auto',
75 'validvals' : ['yes', 'no', 'auto'],
15ef32ea
RP
76 'required' : False,
77 'example' : ['mstpctl-portp2p swp1=no swp2=no']},
78 'mstpctl-portrestrrole' :
79 { 'help' :
80 'enable/disable port ability to take root role of the port',
81 'default' : 'no',
82 'validvals' : ['yes', 'no'],
83 'required' : False,
84 'example' : ['mstpctl-portrestrrole swp1=no swp2=no']},
85 'mstpctl-portrestrtcn' :
86 { 'help' :
87 'enable/disable port ability to propagate received topology change notification of the port',
88 'default' : 'no',
89 'validvals' : ['yes', 'no'],
90 'required' : False,
91 'example' : ['mstpctl-portrestrtcn swp1=no swp2=no']},
92 'mstpctl-bpduguard' :
93 { 'help' :
94 'enable/disable bpduguard',
95 'default' : 'no',
96 'validvals' : ['yes', 'no'],
97 'required' : False,
98 'example' : ['mstpctl-bpduguard swp1=no swp2=no']},
99 'mstpctl-treeportprio' :
100 { 'help' :
101 'port priority for MSTI instance',
102 'default' : '128',
103 'validrange' : ['0', '240'],
104 'required' : False,
105 'example' : ['mstpctl-treeportprio swp1=128 swp2=128']},
106 'mstpctl-hello' :
107 { 'help' : 'set hello time',
108 'default' : '2',
109 'required' : False,
110 'example' : ['mstpctl-hello 2']},
111 'mstpctl-portnetwork' :
112 { 'help' : 'enable/disable bridge assurance capability for a port',
113 'validvals' : ['yes', 'no'],
114 'default' : 'no',
115 'required' : False,
116 'example' : ['mstpctl-portnetwork swp1=no swp2=no']},
117 'mstpctl-portadminedge' :
118 { 'help' : 'enable/disable initial edge state of the port',
119 'validvals' : ['yes', 'no'],
120 'default' : 'no',
121 'required' : False,
122 'example' : ['mstpctl-portadminedge swp1=no swp2=no']},
123 'mstpctl-portautoedge' :
124 { 'help' : 'enable/disable auto transition to/from edge state of the port',
125 'validvals' : ['yes', 'no'],
be1faada 126 'default' : 'yes',
15ef32ea
RP
127 'required' : False,
128 'example' : ['mstpctl-portautoedge swp1=yes swp2=yes']},
129 'mstpctl-treeportcost' :
130 { 'help' : 'port tree cost',
131 'required' : False},
132 'mstpctl-portbpdufilter' :
9e012f9e
RP
133 { 'help' : 'enable/disable bpdu filter on a port. ' +
134 'syntax varies when defined under a bridge ' +
135 'vs under a port',
15ef32ea
RP
136 'validvals' : ['yes', 'no'],
137 'default' : 'no',
138 'required' : False,
9e012f9e
RP
139 'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
140 'under a port: mstpctl-portbpdufilter yes']},
15ef32ea
RP
141 }}
142
4c39c7b8
RP
143 # Maps mstp bridge attribute names to corresponding mstpctl commands
144 # XXX: This can be encoded in the modules dict above
145 _attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
146 ('mstpctl-ageing' , 'ageing'),
147 ('mstpctl-maxage' , 'maxage'),
148 ('mstpctl-fdelay' , 'fdelay'),
149 ('mstpctl-maxhops' , 'maxhops'),
150 ('mstpctl-txholdcount' , 'txholdcount'),
151 ('mstpctl-forcevers', 'forcevers'),
152 ('mstpctl-hello' , 'hello')])
153
154 # Maps mstp port attribute names to corresponding mstpctl commands
155 # XXX: This can be encoded in the modules dict above
e1601369
RP
156 _port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
157 'mstpctl-portadminedge' : 'portadminedge',
d8e3554d 158 'mstpctl-portautoedge' : 'portautoedge' ,
e1601369
RP
159 'mstpctl-portp2p' : 'portp2p',
160 'mstpctl-portrestrrole' : 'portrestrrole',
161 'mstpctl-portrestrtcn' : 'portrestrtcn',
15ef32ea 162 'mstpctl-bpduguard' : 'bpduguard',
e1601369
RP
163 'mstpctl-treeportprio' : 'treeportprio',
164 'mstpctl-treeportcost' : 'treeportcost',
165 'mstpctl-portnetwork' : 'portnetwork',
166 'mstpctl-portbpdufilter' : 'portbpdufilter'}
15ef32ea
RP
167
168 def __init__(self, *args, **kargs):
169 moduleBase.__init__(self, *args, **kargs)
170 self.ipcmd = None
4c773918 171 self.name = self.__class__.__name__
15ef32ea
RP
172 self.brctlcmd = None
173 self.mstpctlcmd = None
174
175 def _is_bridge(self, ifaceobj):
176 if (ifaceobj.get_attr_value_first('mstpctl-ports') or
84ca006f
RP
177 ifaceobj.get_attr_value_first('bridge-ports')):
178 return True
179 return False
180
181 def _is_bridge_port(self, ifaceobj):
182 if self.brctlcmd.is_bridge_port(ifaceobj.name):
15ef32ea
RP
183 return True
184 return False
185
186 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
187 if not self._is_bridge(ifaceobj):
188 return None
189 return self.parse_port_list(ifaceobj.get_attr_value_first(
190 'mstpctl-ports'), ifacenames_all)
191
192 def get_dependent_ifacenames_running(self, ifaceobj):
193 self._init_command_handlers()
194 if (self.brctlcmd.bridge_exists(ifaceobj.name) and
195 not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
196 return None
197 return self.brctlcmd.get_bridge_ports(ifaceobj.name)
198
199 def _get_bridge_port_list(self, ifaceobj):
200
201 # port list is also available in the previously
202 # parsed dependent list. Use that if available, instead
203 # of parsing port expr again
204 port_list = ifaceobj.lowerifaces
205 if port_list:
206 return port_list
207 ports = ifaceobj.get_attr_value_first('mstpctl-ports')
208 if ports:
209 return self.parse_port_list(ports)
210 else:
211 return None
212
404cc695
RP
213 def _ports_enable_disable_ipv6(self, ports, enable='1'):
214 for p in ports:
215 try:
216 self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
217 '/disable_ipv6', enable)
218 except Exception, e:
219 self.logger.info(str(e))
220 pass
221
15ef32ea
RP
222 def _add_ports(self, ifaceobj):
223 bridgeports = self._get_bridge_port_list(ifaceobj)
224
225 runningbridgeports = []
226 # Delete active ports not in the new port list
227 if not self.PERFMODE:
228 runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
229 if runningbridgeports:
230 [self.ipcmd.link_set(bport, 'nomaster')
231 for bport in runningbridgeports
232 if not bridgeports or bport not in bridgeports]
233 else:
234 runningbridgeports = []
235 if not bridgeports:
236 return
237 err = 0
238 for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
239 try:
240 if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
241 self.log_warn('%s: bridge port %s does not exist'
242 %(ifaceobj.name, bridgeport))
243 err += 1
244 continue
245 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
15ef32ea
RP
246 self.ipcmd.addr_flush(bridgeport)
247 except Exception, e:
248 self.log_error(str(e))
404cc695 249
15ef32ea
RP
250 if err:
251 self.log_error('error configuring bridge (missing ports)')
252
253 def _apply_bridge_settings(self, ifaceobj):
254 check = False if self.PERFMODE else True
255 try:
4c39c7b8
RP
256 # set bridge attributes
257 for attrname, dstattrname in self._attrs_map.items():
258 try:
259 v = ifaceobj.get_attr_value_first(attrname)
2722bb19
ST
260 if not v:
261 continue
4c39c7b8
RP
262 if attrname == 'mstpctl-treeprio':
263 self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
264 v, check)
265 else:
266 self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
267 dstattrname, v, check)
268 except Exception, e:
269 self.logger.warn('%s' %str(e))
270 pass
15ef32ea
RP
271
272 # set bridge port attributes
4c39c7b8 273 for attrname, dstattrname in self._port_attrs_map.items():
15ef32ea
RP
274 attrval = ifaceobj.get_attr_value_first(attrname)
275 if not attrval:
276 continue
15ef32ea
RP
277 portlist = self.parse_port_list(attrval)
278 if not portlist:
279 self.log_warn('%s: error parsing \'%s %s\''
280 %(ifaceobj.name, attrname, attrval))
281 continue
282 for p in portlist:
283 try:
284 (port, val) = p.split('=')
42a9d193
RP
285 # if it is not bridge port, continue
286 if not os.path.exists('/sys/class/net/%s/brport' %port):
287 continue
15ef32ea
RP
288 self.mstpctlcmd.set_bridgeport_attr(ifaceobj.name,
289 port, dstattrname, val, check)
290 except Exception, e:
291 self.log_warn('%s: error setting %s (%s)'
292 %(ifaceobj.name, attrname, str(e)))
293 except Exception, e:
294 self.log_warn(str(e))
295 pass
296
84ca006f 297 def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
641cbd1e
RP
298 bridgeifaceobj=None,
299 stp_running_on=True,
d8e3554d 300 mstpd_running=True):
15ef32ea 301 check = False if self.PERFMODE else True
641cbd1e 302 applied = False
84ca006f
RP
303 if not bridgename and bridgeifaceobj:
304 bridgename = bridgeifaceobj.name
305 # set bridge port attributes
306 for attrname, dstattrname in self._port_attrs_map.items():
307 attrval = ifaceobj.get_attr_value_first(attrname)
2722bb19
ST
308 if not attrval:
309 continue
641cbd1e
RP
310 if not stp_running_on:
311 # stp may get turned on at a later point
312 self.logger.info('%s: ignoring %s config'
313 %(ifaceobj.name, attrname) +
314 ' (stp on bridge %s is not on yet)' %bridgename)
d8e3554d
RP
315 continue
316 if not mstpd_running:
317 continue
42a9d193
RP
318 # if its not a bridge port, continue
319 if not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name):
320 continue
84ca006f
RP
321 try:
322 self.mstpctlcmd.set_bridgeport_attr(bridgename,
323 ifaceobj.name, dstattrname, attrval, check)
641cbd1e 324 applied = True
84ca006f
RP
325 except Exception, e:
326 self.log_warn('%s: error setting %s (%s)'
327 %(ifaceobj.name, attrname, str(e)))
641cbd1e 328 return applied
84ca006f
RP
329
330 def _apply_bridge_port_settings_all(self, ifaceobj,
331 ifaceobj_getfunc=None):
98b5ee73 332 self.logger.info('%s: applying mstp configuration '
84ca006f 333 %ifaceobj.name + 'specific to ports')
f6a0fa15
RP
334 # Query running bridge ports. and only apply attributes on them
335 bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
4c39c7b8
RP
336 if not bridgeports:
337 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
338 return
84ca006f 339 for bport in bridgeports:
98b5ee73 340 self.logger.info('%s: processing mstp config for port %s'
84ca006f 341 %(ifaceobj.name, bport))
3e6ea735 342 if not self.ipcmd.link_exists(bport):
3e6ea735 343 continue
42a9d193
RP
344 if not os.path.exists('/sys/class/net/%s/brport' %bport):
345 continue
84ca006f
RP
346 bportifaceobjlist = ifaceobj_getfunc(bport)
347 if not bportifaceobjlist:
348 continue
349 for bportifaceobj in bportifaceobjlist:
98b5ee73 350 # Dont process bridge port if it already has been processed
4c773918
ST
351 if (bportifaceobj.module_flags.get(self.name,0x0) & \
352 mstpctlFlags.PORT_PROCESSED):
98b5ee73 353 continue
15ef32ea 354 try:
84ca006f
RP
355 self._apply_bridge_port_settings(bportifaceobj,
356 ifaceobj.name, ifaceobj)
15ef32ea 357 except Exception, e:
84ca006f 358 self.log_warn(str(e))
15ef32ea 359
641cbd1e
RP
360 def _is_running_userspace_stp_state_on(self, bridgename):
361 stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
362 if not stp_state_file:
363 return False
364 running_stp_state = self.read_file_oneline(stp_state_file)
365 if running_stp_state and running_stp_state == '2':
366 return True
367 return False
368
84ca006f 369 def _up(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 370 # Check if bridge port
98b5ee73
RP
371 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
372 if bridgename:
d8e3554d
RP
373 mstpd_running = (True if self.mstpctlcmd.is_mstpd_running()
374 else False)
641cbd1e
RP
375 stp_running_on = self._is_running_userspace_stp_state_on(bridgename)
376 applied = self._apply_bridge_port_settings(ifaceobj, bridgename,
377 None, stp_running_on,
378 mstpd_running)
379 if applied:
380 ifaceobj.module_flags[self.name] = \
381 ifaceobj.module_flags.setdefault(self.name,0) | \
382 mstpctlFlags.PORT_PROCESSED
15ef32ea 383 return
39804250
RP
384 if not self._is_bridge(ifaceobj):
385 return
15ef32ea
RP
386 stp = None
387 try:
388 porterr = False
389 porterrstr = ''
390 if ifaceobj.get_attr_value_first('mstpctl-ports'):
391 # If bridge ports specified with mstpctl attr, create the
392 # bridge and also add its ports
393 self.ipcmd.batch_start()
394 if not self.PERFMODE:
395 if not self.ipcmd.link_exists(ifaceobj.name):
396 self.ipcmd.link_create(ifaceobj.name, 'bridge')
397 else:
398 self.ipcmd.link_create(ifaceobj.name, 'bridge')
399 try:
400 self._add_ports(ifaceobj)
401 except Exception, e:
402 porterr = True
403 porterrstr = str(e)
404 pass
405 finally:
406 self.ipcmd.batch_commit()
404cc695
RP
407 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
408 if running_ports:
409 # disable ipv6 for ports that were added to bridge
410 self._ports_enable_disable_ipv6(running_ports, '1')
411
15ef32ea
RP
412 stp = ifaceobj.get_attr_value_first('mstpctl-stp')
413 if stp:
414 self.set_iface_attr(ifaceobj, 'mstpctl-stp',
415 self.brctlcmd.set_stp)
416 else:
417 stp = self.brctlcmd.get_stp(ifaceobj.name)
418 if (self.mstpctlcmd.is_mstpd_running() and
419 (stp == 'yes' or stp == 'on')):
420 self._apply_bridge_settings(ifaceobj)
84ca006f
RP
421 self._apply_bridge_port_settings_all(ifaceobj,
422 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea
RP
423 except Exception, e:
424 self.log_error(str(e))
425 if porterr:
426 raise Exception(porterrstr)
427
84ca006f
RP
428 def _down(self, ifaceobj, ifaceobj_getfunc=None):
429 if not self._is_bridge(ifaceobj):
430 return
15ef32ea
RP
431 try:
432 if ifaceobj.get_attr_value_first('mstpctl-ports'):
433 # If bridge ports specified with mstpctl attr, delete the
434 # bridge
435 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
436 if ports:
404cc695 437 self._ports_enable_disable_ipv6(ports, '0')
15ef32ea
RP
438 self.brctlcmd.delete_bridge(ifaceobj.name)
439 except Exception, e:
440 self.log_error(str(e))
441
442 def _query_running_attrs(self, ifaceobjrunning):
443 bridgeattrdict = {}
444
445 tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
446 if not tmpbridgeattrdict:
447 return bridgeattrdict
448
449 for k,v in tmpbridgeattrdict.items():
450 if k == 'stp' or not v:
451 continue
452 if k == 'ports':
453 ports = v.keys()
454 continue
455 attrname = 'mstpctl-' + k
456 if v and v != self.get_mod_subattr(attrname, 'default'):
457 bridgeattrdict[attrname] = [v]
458
459 ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
460 if ports:
461 portconfig = {'mstpctl-portnetwork' : '',
462 'mstpctl-portpathcost' : '',
463 'mstpctl-portadminedge' : '',
464 'mstpctl-portautoedge' : '',
465 'mstpctl-portp2p' : '',
466 'mstpctl-portrestrrole' : '',
467 'mstpctl-portrestrtcn' : '',
468 'mstpctl-bpduguard' : '',
469 'mstpctl-treeportprio' : '',
470 'mstpctl-treeportcost' : ''}
471
472 for p in ports:
473 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
474 p, 'portnetwork')
475 if v and v != 'no':
476 portconfig['mstpctl-portnetwork'] += ' %s=%s' %(p, v)
477
478 # XXX: Can we really get path cost of a port ???
479 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
480 #if v and v != self.get_mod_subattr('mstpctl-portpathcost',
481 # 'default'):
482 # portconfig['mstpctl-portpathcost'] += ' %s=%s' %(p, v)
483
484 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
485 p, 'portadminedge')
486 if v and v != 'no':
487 portconfig['mstpctl-portadminedge'] += ' %s=%s' %(p, v)
488
489 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
490 p, 'portp2p')
491 if v and v != 'no':
492 portconfig['mstpctl-portp2p'] += ' %s=%s' %(p, v)
493
494 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
495 p, 'portrestrrole')
496 if v and v != 'no':
497 portconfig['mstpctl-portrestrrole'] += ' %s=%s' %(p, v)
498
499 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
500 p, 'portrestrtcn')
501 if v and v != 'no':
502 portconfig['mstpctl-portrestrtcn'] += ' %s=%s' %(p, v)
503
504 v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
505 p, 'bpduguard')
506 if v and v != 'no':
507 portconfig['mstpctl-bpduguard'] += ' %s=%s' %(p, v)
508
509 # XXX: Can we really get path cost of a port ???
510 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
511 # p, 'treeprio')
512 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
513 # 'default'):
514 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
515
516 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
517 # p, 'treecost')
518 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
519 # 'default'):
520 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
521
522 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
523 if v})
15ef32ea
RP
524 return bridgeattrdict
525
526 def _query_check_bridge(self, ifaceobj, ifaceobjcurr):
527 # list of attributes that are not supported currently
528 blacklistedattrs = ['mstpctl-portpathcost',
529 'mstpctl-treeportprio', 'mstpctl-treeportcost']
530 if not self.brctlcmd.bridge_exists(ifaceobj.name):
531 self.logger.debug('bridge %s does not exist' %ifaceobj.name)
15ef32ea
RP
532 return
533 ifaceattrs = self.dict_key_subset(ifaceobj.config,
534 self.get_mod_attrs())
535 if not ifaceattrs:
536 return
537 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
538 if not runningattrs:
539 runningattrs = {}
540 for k in ifaceattrs:
541 # for all mstpctl options
542 if k in blacklistedattrs:
543 continue
544 # get the corresponding ifaceobj attr
545 v = ifaceobj.get_attr_value_first(k)
546 if not v:
547 continue
548
549 # Get the running attribute
550 rv = runningattrs.get(k[8:])
551 if k == 'mstpctl-stp':
552 # special case stp compare because it may
553 # contain more than one valid values
554 stp_on_vals = ['on', 'yes']
555 stp_off_vals = ['off']
556 rv = self.brctlcmd.get_stp(ifaceobj.name)
557 if ((v in stp_on_vals and rv in stp_on_vals) or
558 (v in stp_off_vals and rv in stp_off_vals)):
559 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
560 else:
561 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
562 continue
563
564 if k == 'mstpctl-ports':
565 # special case ports because it can contain regex or glob
566 # XXX: We get all info from mstputils, which means if
567 # mstpd is down, we will not be returning any bridge bridgeports
568 running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
569 bridge_port_list = self._get_bridge_port_list(ifaceobj)
570 if not running_port_list and not bridge_port_list:
571 continue
572 portliststatus = 1
573 if running_port_list and bridge_port_list:
574 difference = Set(running_port_list).symmetric_difference(
575 Set(bridge_port_list))
576 if not difference:
577 portliststatus = 0
578 ifaceobjcurr.update_config_with_status('mstpctl-ports',
579 ' '.join(running_port_list)
580 if running_port_list else '', portliststatus)
581 elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
582 # Now, look at port attributes
583 # derive the mstpctlcmd attr name
584 #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
585 mstpctlcmdattrname = k[8:]
586
587 # for port attributes, the attributes are in a list
588 # <portname>=<portattrvalue>
589 status = 0
590 currstr = ''
591 vlist = self.parse_port_list(v)
592 if not vlist:
593 continue
594 for vlistitem in vlist:
595 try:
596 (p, v) = vlistitem.split('=')
597 currv = self.mstpctlcmd.get_bridgeport_attr(
598 ifaceobj.name, p, mstpctlcmdattrname)
599 if currv:
600 currstr += ' %s=%s' %(p, currv)
601 else:
602 currstr += ' %s=%s' %(p, 'None')
603 if currv != v:
604 status = 1
605 except Exception, e:
606 self.log_warn(str(e))
607 pass
608 ifaceobjcurr.update_config_with_status(k, currstr, status)
609 elif not rv:
610 ifaceobjcurr.update_config_with_status(k, '', 1)
611 elif v != rv:
612 ifaceobjcurr.update_config_with_status(k, rv, 1)
613 else:
614 ifaceobjcurr.update_config_with_status(k, rv, 0)
615
84ca006f 616 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
19f90a91 617 if not self.ipcmd.link_exists(ifaceobj.name):
3e6ea735 618 #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
15ef32ea
RP
619 ifaceobjcurr.status = ifaceStatus.NOTFOUND
620 return
e1601369 621 # Check if this is a bridge port
19f90a91 622 if not self._is_bridge_port(ifaceobj):
e1601369 623 # mark all the bridge attributes as error
a070c90e 624 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
e1601369
RP
625 self._port_attrs_map.keys(), 0)
626 return
98b5ee73 627 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
e1601369 628 # list of attributes that are not supported currently
16d854b4
RP
629 blacklistedattrs = ['mstpctl-portpathcost',
630 'mstpctl-treeportprio', 'mstpctl-treeportcost']
15ef32ea
RP
631 ifaceattrs = self.dict_key_subset(ifaceobj.config,
632 self._port_attrs_map.keys())
633 if not ifaceattrs:
634 return
635 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
636 if not runningattrs:
637 runningattrs = {}
638 for k in ifaceattrs:
639 # for all mstpctl options
15ef32ea
RP
640 # get the corresponding ifaceobj attr
641 v = ifaceobj.get_attr_value_first(k)
16d854b4 642 if not v or k in blacklistedattrs:
e1601369 643 ifaceobjcurr.update_config_with_status(k, v, -1)
15ef32ea 644 continue
e1601369 645 currv = self.mstpctlcmd.get_bridgeport_attr(bridgename,
15ef32ea
RP
646 ifaceobj.name, self._port_attrs_map.get(k))
647 if currv:
648 if currv != v:
649 ifaceobjcurr.update_config_with_status(k, currv, 1)
650 else:
651 ifaceobjcurr.update_config_with_status(k, currv, 0)
652 else:
653 ifaceobjcurr.update_config_with_status(k, None, 1)
654
84ca006f 655 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
e1601369 656 if self._is_bridge(ifaceobj):
84ca006f 657 self._query_check_bridge(ifaceobj, ifaceobjcurr)
e1601369
RP
658 else:
659 self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
15ef32ea 660
e1601369
RP
661 def _query_running_bridge_port(self, ifaceobjrunning):
662 bridgename = self.ipcmd.bridge_port_get_bridge_name(
663 ifaceobjrunning.name)
664 if not bridgename:
665 self.logger.warn('%s: unable to determine bridgename'
666 %ifaceobjrunning.name)
15ef32ea 667 return
e1601369
RP
668 if self.brctlcmd.get_stp(bridgename) == 'no':
669 # This bridge does not run stp, return
670 return
15ef32ea
RP
671 # if userspace stp not set, return
672 if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
e1601369
RP
673 return
674 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
675 ifaceobjrunning.name,
676 'portnetwork')
677 if v and v != 'no':
678 ifaceobjrunning.update_config('mstpctl-network', v)
679
680 # XXX: Can we really get path cost of a port ???
681 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
682 #if v and v != self.get_mod_subattr('mstpctl-pathcost',
683 # 'default'):
684 # ifaceobjrunning.update_config('mstpctl-network', v)
685
686 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
687 ifaceobjrunning.name, 'portadminedge')
688 if v and v != 'no':
7adb4b77 689 ifaceobjrunning.update_config('mstpctl-portadminedge', v)
e1601369
RP
690
691 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
692 ifaceobjrunning.name,'portp2p')
e759a20a 693 if v and v != 'auto':
7adb4b77 694 ifaceobjrunning.update_config('mstpctl-portp2p', v)
e1601369
RP
695
696 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
697 ifaceobjrunning.name, 'portrestrrole')
698 if v and v != 'no':
7adb4b77 699 ifaceobjrunning.update_config('mstpctl-portrestrrole', v)
e1601369
RP
700
701 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
702 ifaceobjrunning.name, 'restrtcn')
703 if v and v != 'no':
7adb4b77 704 ifaceobjrunning.update_config('mstpctl-portrestrtcn', v)
e1601369
RP
705
706 v = self.mstpctlcmd.get_bridgeport_attr(bridgename,
707 ifaceobjrunning.name, 'bpduguard')
708 if v and v != 'no':
709 ifaceobjrunning.update_config('mstpctl-bpduguard', v)
710
711 # XXX: Can we really get path cost of a port ???
712 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
713 # p, 'treeprio')
714 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
715 # 'default'):
716 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
717
718 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
719 # p, 'treecost')
720 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
721 # 'default'):
722 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
723
724 def _query_running_bridge(self, ifaceobjrunning):
725 if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
726 # This bridge does not run stp, return
727 return
728 # if userspace stp not set, return
729 if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1':
730 return
15ef32ea
RP
731 # Check if mstp really knows about this bridge
732 if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
733 return
734 ifaceobjrunning.update_config_dict(self._query_running_attrs(
735 ifaceobjrunning))
736
e1601369
RP
737 def _query_running(self, ifaceobjrunning, **extra_args):
738 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
739 self._query_running_bridge(ifaceobjrunning)
740 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
741 self._query_running_bridge_port(ifaceobjrunning)
742
15ef32ea
RP
743 _run_ops = {'pre-up' : _up,
744 'post-down' : _down,
745 'query-checkcurr' : _query_check,
746 'query-running' : _query_running}
747
748 def get_ops(self):
749 """ returns list of ops supported by this module """
750 return self._run_ops.keys()
751
752 def _init_command_handlers(self):
753 flags = self.get_flags()
754 if not self.ipcmd:
755 self.ipcmd = iproute2(**flags)
756 if not self.brctlcmd:
757 self.brctlcmd = brctl(**flags)
758 if not self.mstpctlcmd:
759 self.mstpctlcmd = mstpctlutil(**flags)
760
84ca006f
RP
761 def run(self, ifaceobj, operation, query_ifaceobj=None,
762 ifaceobj_getfunc=None, **extra_args):
15ef32ea
RP
763 """ run mstp configuration on the interface object passed as argument
764
765 Args:
766 **ifaceobj** (object): iface object
767
768 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
769 'query-running'
770 Kwargs:
771 **query_ifaceobj** (object): query check ifaceobject. This is only
772 valid when op is 'query-checkcurr'. It is an object same as
773 ifaceobj, but contains running attribute values and its config
774 status. The modules can use it to return queried running state
775 of interfaces. status is success if the running state is same
776 as user required state in ifaceobj. error otherwise.
777 """
3e6ea735
RP
778 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
779 return
15ef32ea
RP
780 op_handler = self._run_ops.get(operation)
781 if not op_handler:
782 return
15ef32ea
RP
783 self._init_command_handlers()
784 if operation == 'query-checkcurr':
84ca006f
RP
785 op_handler(self, ifaceobj, query_ifaceobj,
786 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 787 else:
84ca006f 788 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)