]>
Commit | Line | Data |
---|---|---|
2c8c4ce7 RP |
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 | }} | |
141 | ||
142 | def __init__(self, *args, **kargs): | |
143 | moduleBase.__init__(self, *args, **kargs) | |
144 | self.ipcmd = None | |
145 | self.brctlcmd = None | |
146 | self.mstpctlcmd = None | |
147 | ||
148 | def _is_bridge(self, ifaceobj): | |
149 | if (ifaceobj.get_attr_value_first('mstpctl-ports') or | |
150 | ifaceobj.get_attr_value_first('bridge-ports')): | |
151 | return True | |
152 | return False | |
153 | ||
154 | def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None): | |
155 | if not self._is_bridge(ifaceobj): | |
156 | return None | |
157 | return self.parse_port_list(ifaceobj.get_attr_value_first( | |
158 | 'mstpctl-ports'), ifacenames_all) | |
159 | ||
160 | def get_dependent_ifacenames_running(self, ifaceobj): | |
161 | self._init_command_handlers() | |
162 | if (self.brctlcmd.bridge_exists(ifaceobj.name) and | |
163 | not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)): | |
164 | return None | |
165 | return self.brctlcmd.get_bridge_ports(ifaceobj.name) | |
166 | ||
167 | def _get_bridge_port_list(self, ifaceobj): | |
168 | ||
169 | # port list is also available in the previously | |
170 | # parsed dependent list. Use that if available, instead | |
171 | # of parsing port expr again | |
172 | port_list = ifaceobj.lowerifaces | |
173 | if port_list: | |
174 | ports = ifaceobj.get_attr_value_first('mstpctl-ports') | |
175 | if ports: | |
176 | return self.parse_port_list(ports) | |
177 | else: | |
178 | return None | |
179 | else: | |
180 | return port_list | |
181 | ||
182 | def _add_ports(self, ifaceobj): | |
183 | bridgeports = self._get_bridge_port_list(ifaceobj) | |
184 | ||
185 | runningbridgeports = [] | |
186 | # Delete active ports not in the new port list | |
187 | if not self.PERFMODE: | |
188 | runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name) | |
189 | if runningbridgeports: | |
190 | [self.ipcmd.link_set(bport, 'nomaster') | |
191 | for bport in runningbridgeports | |
192 | if not bridgeports or bport not in bridgeports] | |
193 | else: | |
194 | runningbridgeports = [] | |
195 | if not bridgeports: | |
196 | return | |
197 | err = 0 | |
198 | for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)): | |
199 | try: | |
200 | if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport): | |
201 | self.log_warn('%s: bridge port %s does not exist' | |
202 | %(ifaceobj.name, bridgeport)) | |
203 | err += 1 | |
204 | continue | |
205 | self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name) | |
206 | self.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport + | |
207 | '/disable_ipv6', '1') | |
208 | self.ipcmd.addr_flush(bridgeport) | |
209 | except Exception, e: | |
210 | self.log_error(str(e)) | |
211 | if err: | |
212 | self.log_error('error configuring bridge (missing ports)') | |
213 | ||
214 | def _apply_bridge_settings(self, ifaceobj): | |
215 | check = False if self.PERFMODE else True | |
216 | try: | |
217 | bridgeattrs = {k:v for k,v in | |
218 | {'treeprio' : | |
219 | ifaceobj.get_attr_value_first('mstpctl-treeprio'), | |
220 | 'ageing' : | |
221 | ifaceobj.get_attr_value_first('mstpctl-ageing'), | |
222 | 'maxage' : | |
223 | ifaceobj.get_attr_value_first('mstpctl-maxage'), | |
224 | 'fdelay' : | |
225 | ifaceobj.get_attr_value_first('mstpctl-fdelay'), | |
226 | 'maxhops' : | |
227 | ifaceobj.get_attr_value_first('mstpctl-maxhops'), | |
228 | 'txholdcount' : | |
229 | ifaceobj.get_attr_value_first('mstpctl-txholdcount'), | |
230 | 'forcevers' : | |
231 | ifaceobj.get_attr_value_first('mstpctl-forcevers'), | |
232 | 'hello' : | |
233 | ifaceobj.get_attr_value_first('mstpctl-hello') | |
234 | }.items() if v} | |
235 | ||
236 | if bridgeattrs: | |
237 | # set bridge attributes | |
238 | for k,v in bridgeattrs.items(): | |
239 | if k == 'treeprio': | |
240 | continue | |
241 | try: | |
242 | if v: | |
243 | self.mstpctlcmd.set_bridge_attr(ifaceobj.name, k, | |
244 | v, check) | |
245 | except Exception, e: | |
246 | self.logger.warn('%s' %str(e)) | |
247 | pass | |
248 | if bridgeattrs.get('treeprio'): | |
249 | try: | |
250 | self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name, | |
251 | bridgeattrs['treeprio'], check) | |
252 | except Exception, e: | |
253 | self.logger.warn('%s' %str(e)) | |
254 | pass | |
255 | ||
256 | # set bridge port attributes | |
257 | for attrname in ['mstpctl-portpathcost', 'mstpctl-portadminedge', | |
258 | 'mstpctl-portp2p', 'mstpctl-portrestrrole', | |
259 | 'mstpctl-portrestrtcn', 'mstpctl-bpduguard', | |
260 | 'mstpctl-treeportprio', 'mstpctl-treeportcost', | |
261 | 'mstpctl-portnetwork', 'mstpctl-portbpdufilter']: | |
262 | attrval = ifaceobj.get_attr_value_first(attrname) | |
263 | if not attrval: | |
264 | continue | |
265 | dstattrname = attrname.split('-')[1] | |
266 | portlist = self.parse_port_list(attrval) | |
267 | if not portlist: | |
268 | self.log_warn('%s: error parsing \'%s %s\'' | |
269 | %(ifaceobj.name, attrname, attrval)) | |
270 | continue | |
271 | for p in portlist: | |
272 | try: | |
273 | (port, val) = p.split('=') | |
274 | self.mstpctlcmd.set_bridgeport_attr(ifaceobj.name, | |
275 | port, dstattrname, val, check) | |
276 | except Exception, e: | |
277 | self.log_warn('%s: error setting %s (%s)' | |
278 | %(ifaceobj.name, attrname, str(e))) | |
279 | except Exception, e: | |
280 | self.log_warn(str(e)) | |
281 | pass | |
282 | ||
283 | def _up(self, ifaceobj): | |
284 | stp = None | |
285 | try: | |
286 | if ifaceobj.get_attr_value_first('mstpctl-ports'): | |
287 | # If bridge ports specified with mstpctl attr, create the | |
288 | # bridge and also add its ports | |
289 | self.ipcmd.batch_start() | |
290 | if not self.PERFMODE: | |
291 | if not self.ipcmd.link_exists(ifaceobj.name): | |
292 | self.ipcmd.link_create(ifaceobj.name, 'bridge') | |
293 | else: | |
294 | self.ipcmd.link_create(ifaceobj.name, 'bridge') | |
295 | self._add_ports(ifaceobj) | |
296 | self.ipcmd.batch_commit() | |
297 | stp = ifaceobj.get_attr_value_first('mstpctl-stp') | |
298 | if stp: | |
299 | self.set_iface_attr(ifaceobj, 'mstpctl-stp', | |
300 | self.brctlcmd.set_stp) | |
301 | else: | |
302 | stp = self.brctlcmd.get_stp(ifaceobj.name) | |
303 | if (self.mstpctlcmd.is_mstpd_running() and | |
304 | (stp == 'yes' or stp == 'on')): | |
305 | self._apply_bridge_settings(ifaceobj) | |
306 | except Exception, e: | |
307 | self.log_error(str(e)) | |
308 | ||
309 | def _down(self, ifaceobj): | |
310 | try: | |
311 | if ifaceobj.get_attr_value_first('mstpctl-ports'): | |
312 | # If bridge ports specified with mstpctl attr, delete the | |
313 | # bridge | |
314 | ports = self.brctlcmd.get_bridge_ports(ifaceobj.name) | |
315 | if ports: | |
316 | for p in ports: | |
317 | proc_file = ('/proc/sys/net/ipv6/conf/%s' %p + | |
318 | '/disable_ipv6') | |
319 | self.write_file(proc_file, '0') | |
320 | self.brctlcmd.delete_bridge(ifaceobj.name) | |
321 | except Exception, e: | |
322 | self.log_error(str(e)) | |
323 | ||
324 | def _query_running_attrs(self, ifaceobjrunning): | |
325 | bridgeattrdict = {} | |
326 | ||
327 | tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name) | |
328 | if not tmpbridgeattrdict: | |
329 | return bridgeattrdict | |
330 | ||
331 | for k,v in tmpbridgeattrdict.items(): | |
332 | if k == 'stp' or not v: | |
333 | continue | |
334 | if k == 'ports': | |
335 | ports = v.keys() | |
336 | continue | |
337 | attrname = 'mstpctl-' + k | |
338 | if v and v != self.get_mod_subattr(attrname, 'default'): | |
339 | bridgeattrdict[attrname] = [v] | |
340 | ||
341 | ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name) | |
342 | if ports: | |
343 | portconfig = {'mstpctl-portnetwork' : '', | |
344 | 'mstpctl-portpathcost' : '', | |
345 | 'mstpctl-portadminedge' : '', | |
346 | 'mstpctl-portautoedge' : '', | |
347 | 'mstpctl-portp2p' : '', | |
348 | 'mstpctl-portrestrrole' : '', | |
349 | 'mstpctl-portrestrtcn' : '', | |
350 | 'mstpctl-bpduguard' : '', | |
351 | 'mstpctl-treeportprio' : '', | |
352 | 'mstpctl-treeportcost' : ''} | |
353 | ||
354 | for p in ports: | |
355 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
356 | p, 'portnetwork') | |
357 | if v and v != 'no': | |
358 | portconfig['mstpctl-portnetwork'] += ' %s=%s' %(p, v) | |
359 | ||
360 | # XXX: Can we really get path cost of a port ??? | |
361 | #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p) | |
362 | #if v and v != self.get_mod_subattr('mstpctl-portpathcost', | |
363 | # 'default'): | |
364 | # portconfig['mstpctl-portpathcost'] += ' %s=%s' %(p, v) | |
365 | ||
366 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
367 | p, 'portadminedge') | |
368 | if v and v != 'no': | |
369 | portconfig['mstpctl-portadminedge'] += ' %s=%s' %(p, v) | |
370 | ||
371 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
372 | p, 'portp2p') | |
373 | if v and v != 'no': | |
374 | portconfig['mstpctl-portp2p'] += ' %s=%s' %(p, v) | |
375 | ||
376 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
377 | p, 'portrestrrole') | |
378 | if v and v != 'no': | |
379 | portconfig['mstpctl-portrestrrole'] += ' %s=%s' %(p, v) | |
380 | ||
381 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
382 | p, 'portrestrtcn') | |
383 | if v and v != 'no': | |
384 | portconfig['mstpctl-portrestrtcn'] += ' %s=%s' %(p, v) | |
385 | ||
386 | v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
387 | p, 'bpduguard') | |
388 | if v and v != 'no': | |
389 | portconfig['mstpctl-bpduguard'] += ' %s=%s' %(p, v) | |
390 | ||
391 | # XXX: Can we really get path cost of a port ??? | |
392 | #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
393 | # p, 'treeprio') | |
394 | #if v and v != self.get_mod_subattr('mstpctl-treeportprio', | |
395 | # 'default'): | |
396 | # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v) | |
397 | ||
398 | #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name, | |
399 | # p, 'treecost') | |
400 | #if v and v != self.get_mod_subattr('mstpctl-treeportcost', | |
401 | # 'default'): | |
402 | # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v) | |
403 | ||
404 | bridgeattrdict.update({k : [v] for k, v in portconfig.items() | |
405 | if v}) | |
406 | self.logger.debug(bridgeattrdict) | |
407 | return bridgeattrdict | |
408 | ||
409 | def _query_check(self, ifaceobj, ifaceobjcurr): | |
410 | # list of attributes that are not supported currently | |
411 | blacklistedattrs = ['mstpctl-portpathcost', | |
412 | 'mstpctl-treeportprio', 'mstpctl-treeportcost'] | |
413 | if not self.brctlcmd.bridge_exists(ifaceobj.name): | |
414 | self.logger.debug('bridge %s does not exist' %ifaceobj.name) | |
415 | ifaceobjcurr.status = ifaceStatus.NOTFOUND | |
416 | return | |
417 | ifaceattrs = self.dict_key_subset(ifaceobj.config, | |
418 | self.get_mod_attrs()) | |
419 | if not ifaceattrs: | |
420 | return | |
421 | runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name) | |
422 | if not runningattrs: | |
423 | runningattrs = {} | |
424 | for k in ifaceattrs: | |
425 | # for all mstpctl options | |
426 | if k in blacklistedattrs: | |
427 | continue | |
428 | # get the corresponding ifaceobj attr | |
429 | v = ifaceobj.get_attr_value_first(k) | |
430 | if not v: | |
431 | continue | |
432 | ||
433 | # Get the running attribute | |
434 | rv = runningattrs.get(k[8:]) | |
435 | if k == 'mstpctl-stp': | |
436 | # special case stp compare because it may | |
437 | # contain more than one valid values | |
438 | stp_on_vals = ['on', 'yes'] | |
439 | stp_off_vals = ['off'] | |
440 | rv = self.brctlcmd.get_stp(ifaceobj.name) | |
441 | if ((v in stp_on_vals and rv in stp_on_vals) or | |
442 | (v in stp_off_vals and rv in stp_off_vals)): | |
443 | ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0) | |
444 | else: | |
445 | ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1) | |
446 | continue | |
447 | ||
448 | if k == 'mstpctl-ports': | |
449 | # special case ports because it can contain regex or glob | |
450 | # XXX: We get all info from mstputils, which means if | |
451 | # mstpd is down, we will not be returning any bridge bridgeports | |
59bba4c9 | 452 | running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name) |
2c8c4ce7 RP |
453 | bridge_port_list = self._get_bridge_port_list(ifaceobj) |
454 | if not running_port_list and not bridge_port_list: | |
455 | continue | |
456 | portliststatus = 1 | |
457 | if running_port_list and bridge_port_list: | |
458 | difference = Set(running_port_list).symmetric_difference( | |
459 | Set(bridge_port_list)) | |
460 | if not difference: | |
461 | portliststatus = 0 | |
462 | ifaceobjcurr.update_config_with_status('mstpctl-ports', | |
463 | ' '.join(running_port_list) | |
464 | if running_port_list else '', portliststatus) | |
465 | elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard': | |
466 | # Now, look at port attributes | |
467 | # derive the mstpctlcmd attr name | |
468 | #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:] | |
469 | mstpctlcmdattrname = k[8:] | |
470 | ||
471 | # for port attributes, the attributes are in a list | |
472 | # <portname>=<portattrvalue> | |
473 | status = 0 | |
474 | currstr = '' | |
475 | vlist = self.parse_port_list(v) | |
476 | if not vlist: | |
477 | continue | |
478 | for vlistitem in vlist: | |
479 | try: | |
480 | (p, v) = vlistitem.split('=') | |
481 | currv = self.mstpctlcmd.get_bridgeport_attr( | |
482 | ifaceobj.name, p, mstpctlcmdattrname) | |
483 | if currv: | |
484 | currstr += ' %s=%s' %(p, currv) | |
485 | else: | |
486 | currstr += ' %s=%s' %(p, 'None') | |
487 | if currv != v: | |
488 | status = 1 | |
489 | except Exception, e: | |
490 | self.log_warn(str(e)) | |
491 | pass | |
492 | ifaceobjcurr.update_config_with_status(k, currstr, status) | |
493 | elif not rv: | |
494 | ifaceobjcurr.update_config_with_status(k, '', 1) | |
495 | elif v != rv: | |
496 | ifaceobjcurr.update_config_with_status(k, rv, 1) | |
497 | else: | |
498 | ifaceobjcurr.update_config_with_status(k, rv, 0) | |
499 | ||
500 | def _query_running(self, ifaceobjrunning): | |
501 | if not self.brctlcmd.bridge_exists(ifaceobjrunning.name): | |
502 | return | |
503 | if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no': | |
504 | # This bridge does not run stp, return | |
505 | return | |
506 | # if userspace stp not set, return | |
507 | if self.sysctl_get('net.bridge.bridge-stp-user-space') != '1': | |
508 | return | |
509 | # Check if mstp really knows about this bridge | |
510 | if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name): | |
511 | return | |
512 | ifaceobjrunning.update_config_dict(self._query_running_attrs( | |
513 | ifaceobjrunning)) | |
514 | ||
515 | _run_ops = {'pre-up' : _up, | |
516 | 'post-down' : _down, | |
517 | 'query-checkcurr' : _query_check, | |
518 | 'query-running' : _query_running} | |
519 | ||
520 | def get_ops(self): | |
521 | """ returns list of ops supported by this module """ | |
522 | return self._run_ops.keys() | |
523 | ||
524 | def _init_command_handlers(self): | |
525 | flags = self.get_flags() | |
526 | if not self.ipcmd: | |
527 | self.ipcmd = iproute2(**flags) | |
528 | if not self.brctlcmd: | |
529 | self.brctlcmd = brctl(**flags) | |
530 | if not self.mstpctlcmd: | |
531 | self.mstpctlcmd = mstpctlutil(**flags) | |
532 | ||
533 | def run(self, ifaceobj, operation, query_ifaceobj=None): | |
534 | """ run mstp configuration on the interface object passed as argument | |
535 | ||
536 | Args: | |
537 | **ifaceobj** (object): iface object | |
538 | ||
539 | **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr', | |
540 | 'query-running' | |
541 | Kwargs: | |
542 | **query_ifaceobj** (object): query check ifaceobject. This is only | |
543 | valid when op is 'query-checkcurr'. It is an object same as | |
544 | ifaceobj, but contains running attribute values and its config | |
545 | status. The modules can use it to return queried running state | |
546 | of interfaces. status is success if the running state is same | |
547 | as user required state in ifaceobj. error otherwise. | |
548 | """ | |
549 | op_handler = self._run_ops.get(operation) | |
550 | if not op_handler: | |
551 | return | |
552 | if operation != 'query-running' and not self._is_bridge(ifaceobj): | |
553 | return | |
554 | self._init_command_handlers() | |
555 | if operation == 'query-checkcurr': | |
556 | op_handler(self, ifaceobj, query_ifaceobj) | |
557 | else: | |
558 | op_handler(self, ifaceobj) |