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