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