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