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