]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/mstpctl.py
mstpctl: don't load module if missing /sbin/mstpctl
[mirror_ifupdown2.git] / ifupdown2 / addons / mstpctl.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 import os
8
9 from sets import Set
10
11 try:
12 from ifupdown2.ifupdown.iface import *
13 from ifupdown2.ifupdown.utils import utils
14 from ifupdown2.ifupdown.netlink import netlink
15
16 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
17 import ifupdown2.ifupdown.policymanager as policymanager
18
19 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
20 from ifupdown2.ifupdownaddons.modulebase import moduleBase
21 from ifupdown2.ifupdownaddons.mstpctlutil import mstpctlutil
22 from ifupdown2.ifupdownaddons.systemutils import systemUtils
23 from ifupdown2.ifupdown.exceptions import moduleNotSupported
24 except ImportError:
25 from ifupdown.iface import *
26 from ifupdown.utils import utils
27 from ifupdown.netlink import netlink
28
29 import ifupdown.ifupdownflags as ifupdownflags
30 import ifupdown.policymanager as policymanager
31
32 from ifupdownaddons.LinkUtils import LinkUtils
33 from ifupdownaddons.modulebase import moduleBase
34 from ifupdownaddons.mstpctlutil import mstpctlutil
35 from ifupdownaddons.systemutils import systemUtils
36 from ifupdown.exceptions import moduleNotSupported
37
38
39 class mstpctlFlags:
40 PORT_PROCESSED = 0x1
41
42 class mstpctl(moduleBase):
43 """ ifupdown2 addon module to configure mstp attributes """
44
45 _modinfo = {'mhelp' : 'mstp configuration module for bridges',
46 'attrs' : {
47 'mstpctl-ports' :
48 {'help' : 'mstp ports',
49 'compat' : True,
50 'deprecated': True,
51 'new-attribute': 'bridge-ports'},
52 'mstpctl-stp' :
53 {'help': 'bridge stp yes/no',
54 'validvals' : ['yes', 'no', 'on', 'off'],
55 'compat' : True,
56 'default' : 'no',
57 'deprecated': True,
58 'new-attribute': 'bridge-stp'},
59 'mstpctl-treeprio' :
60 {'help': 'tree priority',
61 'default' : '32768',
62 'validvals' : ['0', '4096', '8192', '12288', '16384',
63 '20480', '24576', '28672', '32768',
64 '36864', '40960', '45056', '49152',
65 '53248', '57344', '61440'],
66 'required' : False,
67 'example' : ['mstpctl-treeprio 32768']},
68 'mstpctl-ageing' :
69 {'help': 'ageing time',
70 'validrange' : ['0', '4096'],
71 'default' : '300',
72 'required' : False,
73 'jsonAttr': 'ageingTime',
74 'example' : ['mstpctl-ageing 300']},
75 'mstpctl-maxage' :
76 { 'help' : 'max message age',
77 'validrange' : ['0', '255'],
78 'default' : '20',
79 'jsonAttr': 'bridgeMaxAge',
80 'required' : False,
81 'example' : ['mstpctl-maxage 20']},
82 'mstpctl-fdelay' :
83 { 'help' : 'set forwarding delay',
84 'validrange' : ['0', '255'],
85 'default' : '15',
86 'jsonAttr': 'bridgeFwdDelay',
87 'required' : False,
88 'example' : ['mstpctl-fdelay 15']},
89 'mstpctl-maxhops' :
90 { 'help' : 'bridge max hops',
91 'validrange' : ['0', '255'],
92 'default' : '20',
93 'jsonAttr': 'maxHops',
94 'required' : False,
95 'example' : ['mstpctl-maxhops 15']},
96 'mstpctl-txholdcount' :
97 { 'help' : 'bridge transmit holdcount',
98 'validrange' : ['0', '255'],
99 'default' : '6',
100 'jsonAttr': 'txHoldCounter',
101 'required' : False,
102 'example' : ['mstpctl-txholdcount 6']},
103 'mstpctl-forcevers' :
104 { 'help' : 'bridge force stp version',
105 'validvals' : ['rstp', ],
106 'default' : 'rstp',
107 'required' : False,
108 'jsonAttr': 'forceProtocolVersion',
109 'example' : ['mstpctl-forcevers rstp']},
110 'mstpctl-portpathcost' :
111 { 'help' : 'bridge port path cost',
112 'validvals': ['<interface-range-list>'],
113 'validrange' : ['0', '65535'],
114 'default' : '0',
115 'jsonAttr' : 'adminExtPortCost',
116 'required' : False,
117 'example' : ['under the bridge: mstpctl-portpathcost swp1=0 swp2=1',
118 'under the port (recommended): mstpctl-portpathcost 0']},
119 'mstpctl-portp2p' :
120 { 'help' : 'bridge port p2p detection mode',
121 'default' : 'auto',
122 'jsonAttr' : 'adminPointToPoint',
123 'validvals' : ['<interface-yes-no-auto-list>'],
124 'required' : False,
125 'example' : ['under the bridge: mstpctl-portp2p swp1=yes swp2=no',
126 'under the port (recommended): mstpctl-portp2p yes']},
127 'mstpctl-portrestrrole' :
128 { 'help' :
129 'enable/disable port ability to take root role of the port',
130 'default' : 'no',
131 'jsonAttr' : 'restrictedRole',
132 'validvals' : ['<interface-yes-no-list>'],
133 'required' : False,
134 'example' : ['under the bridge: mstpctl-portrestrrole swp1=yes swp2=no',
135 'under the port (recommended): mstpctl-portrestrrole yes']},
136 'mstpctl-portrestrtcn' :
137 { 'help' :
138 'enable/disable port ability to propagate received topology change notification of the port',
139 'default' : 'no',
140 'jsonAttr' : 'restrictedTcn',
141 'validvals' : ['<interface-yes-no-list>'],
142 'required' : False,
143 'example' : ['under the bridge: mstpctl-portrestrtcn swp1=yes swp2=no',
144 'under the port (recommended): mstpctl-portrestrtcn yes']},
145 'mstpctl-bpduguard' :
146 { 'help' :
147 'enable/disable bpduguard',
148 'default' : 'no',
149 'jsonAttr' : 'bpduGuardPort',
150 'validvals' : ['<interface-yes-no-list>'],
151 'required' : False,
152 'example' : ['under the bridge: mstpctl-bpduguard swp1=yes swp2=no',
153 'under the port (recommended): mstpctl-bpduguard yes']},
154 'mstpctl-treeportprio' :
155 { 'help': 'Sets the <port>\'s priority MSTI instance. '
156 'The priority value must be a number between 0 and 240 and a multiple of 16.',
157 'default' : '128',
158 'validvals': ['<interface-range-list-multiple-of-16>'],
159 'validrange' : ['0', '240'],
160 'jsonAttr': 'treeportprio',
161 'required' : False,
162 'example' : ['under the bridge: mstpctl-treeportprio swp1=128 swp2=128',
163 'under the port (recommended): mstpctl-treeportprio 128']},
164 'mstpctl-hello' :
165 { 'help' : 'set hello time',
166 'validrange' : ['0', '255'],
167 'default' : '2',
168 'required' : False,
169 'jsonAttr': 'helloTime',
170 'example' : ['mstpctl-hello 2']},
171 'mstpctl-portnetwork' :
172 { 'help' : 'enable/disable bridge assurance capability for a port',
173 'validvals' : ['<interface-yes-no-list>'],
174 'default' : 'no',
175 'jsonAttr' : 'networkPort',
176 'required' : False,
177 'example' : ['under the bridge: mstpctl-portnetwork swp1=yes swp2=no',
178 'under the port (recommended): mstpctl-portnetwork yes']},
179 'mstpctl-portadminedge' :
180 { 'help' : 'enable/disable initial edge state of the port',
181 'validvals' : ['<interface-yes-no-list>'],
182 'default' : 'no',
183 'jsonAttr' : 'adminEdgePort',
184 'required' : False,
185 'example' : ['under the bridge: mstpctl-portadminedge swp1=yes swp2=no',
186 'under the port (recommended): mstpctl-portadminedge yes']},
187 'mstpctl-portautoedge' :
188 { 'help' : 'enable/disable auto transition to/from edge state of the port',
189 'validvals' : ['<interface-yes-no-list>'],
190 'default' : 'yes',
191 'jsonAttr' : 'autoEdgePort',
192 'required' : False,
193 'example' : ['under the bridge: mstpctl-portautoedge swp1=yes swp2=no',
194 'under the port (recommended): mstpctl-portautoedge yes']},
195 'mstpctl-treeportcost' :
196 { 'help' : 'port tree cost',
197 'validrange' : ['0', '255'],
198 'required' : False,
199 'jsonAttr': 'extPortCost',
200 },
201 'mstpctl-portbpdufilter' :
202 { 'help' : 'enable/disable bpdu filter on a port. ' +
203 'syntax varies when defined under a bridge ' +
204 'vs under a port',
205 'validvals' : ['<interface-yes-no-list>'],
206 'jsonAttr' : 'bpduFilterPort',
207 'default' : 'no',
208 'required' : False,
209 'example' : ['under a bridge: mstpctl-portbpdufilter swp1=no swp2=no',
210 'under a port: mstpctl-portbpdufilter yes']},
211 }}
212
213 # Maps mstp bridge attribute names to corresponding mstpctl commands
214 # XXX: This can be encoded in the modules dict above
215 _attrs_map = OrderedDict([('mstpctl-treeprio' , 'treeprio'),
216 ('mstpctl-ageing' , 'ageing'),
217 ('mstpctl-fdelay' , 'fdelay'),
218 ('mstpctl-maxage' , 'maxage'),
219 ('mstpctl-maxhops' , 'maxhops'),
220 ('mstpctl-txholdcount' , 'txholdcount'),
221 ('mstpctl-forcevers', 'forcevers'),
222 ('mstpctl-hello' , 'hello')])
223
224 # Maps mstp port attribute names to corresponding mstpctl commands
225 # XXX: This can be encoded in the modules dict above
226 _port_attrs_map = {'mstpctl-portpathcost' : 'portpathcost',
227 'mstpctl-portadminedge' : 'portadminedge',
228 'mstpctl-portautoedge' : 'portautoedge' ,
229 'mstpctl-portp2p' : 'portp2p',
230 'mstpctl-portrestrrole' : 'portrestrrole',
231 'mstpctl-portrestrtcn' : 'portrestrtcn',
232 'mstpctl-bpduguard' : 'bpduguard',
233 'mstpctl-treeportprio' : 'treeportprio',
234 'mstpctl-treeportcost' : 'treeportcost',
235 'mstpctl-portnetwork' : 'portnetwork',
236 'mstpctl-portbpdufilter' : 'portbpdufilter'}
237
238 def __init__(self, *args, **kargs):
239 moduleBase.__init__(self, *args, **kargs)
240 if not os.path.exists('/sbin/mstpctl'):
241 raise moduleNotSupported('module init failed: no /sbin/mstpctl found')
242 self.ipcmd = None
243 self.name = self.__class__.__name__
244 self.brctlcmd = None
245 self.mstpctlcmd = None
246 self.mstpd_running = (True if systemUtils.is_process_running('mstpd')
247 else False)
248
249 # Background -
250 # The ask is to make "mstpctl-portadminedge yes" part of the default ifupdown2
251 # policy for all vxlan interfaces. In the absence of this, the mstp work flow
252 # is flawed in the event of vxlan flap.
253 # Details -
254 # As of today, for vxlan interfaces "oper edge port" is set to 'yes' and also
255 # "bpdufilter port" is also set to 'yes'. So, in a case where bridge has multiple
256 # vxlan interfaces, if one vxlan interface is flapped, this would trigger mstp
257 # re-evaluation of states on other vxlan interfaces, creating momentary traffic
258 # glitch on those vxlans. Setting "admin edge port" to yes (in addition to the
259 # defaults we already have) prevents this.
260 #
261 # We use to only support 'mstpctl-vxlan-always-set-bpdu-params' but introducing a
262 # separate policy attribute doesn't make sense, we should have one single
263 # attribute to handle the whole thing (and deprecate mstpctl-vxlan-always-set-bpdu-params)
264 # mstpctl-set-default-vxlan-bridge-attrs=yes will set
265 # mstpctl-portbpdufilter
266 # mstpctl-bpduguard
267 # mstpctl-portadminedge
268 #
269 self.set_default_mstp_vxlan_bridge_config = utils.get_boolean_from_string(
270 policymanager.policymanager_api.get_module_globals(
271 module_name=self.__class__.__name__,
272 attr='mstpctl-vxlan-always-set-bpdu-params'
273 )
274 ) or utils.get_boolean_from_string(
275 policymanager.policymanager_api.get_module_globals(
276 module_name=self.__class__.__name__,
277 attr='mstpctl-set-default-vxlan-bridge-attrs'
278 )
279 )
280
281 def syntax_check(self, ifaceobj, ifaceobj_getfunc):
282 if self._is_bridge(ifaceobj):
283 if (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE
284 and ifaceobj.get_attr_value_first('mstpctl-portadminedge')):
285 self.logger.error('%s: unsupported use of keyword '
286 '\'mstpctl-portadminedge\' when '
287 'bridge-vlan-aware is on'
288 % ifaceobj.name)
289 return False
290 return True
291
292 def _is_bridge(self, ifaceobj):
293 if (ifaceobj.get_attr_value_first('mstpctl-ports') or
294 ifaceobj.get_attr_value_first('bridge-ports')):
295 return True
296 return False
297
298 def _is_bridge_port(self, ifaceobj):
299 if self.brctlcmd.is_bridge_port(ifaceobj.name):
300 return True
301 return False
302
303 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
304 if not self._is_bridge(ifaceobj):
305 return None
306 return self.parse_port_list(ifaceobj.name,
307 ifaceobj.get_attr_value_first(
308 'mstpctl-ports'), ifacenames_all)
309
310 def get_dependent_ifacenames_running(self, ifaceobj):
311 self._init_command_handlers()
312 if (self.brctlcmd.bridge_exists(ifaceobj.name) and
313 not self.mstpctlcmd.mstpbridge_exists(ifaceobj.name)):
314 return None
315 return self.brctlcmd.get_bridge_ports(ifaceobj.name)
316
317 def _get_bridge_port_attr_value(self, bridgename, portname, attr):
318 json_attr = self.get_mod_subattr(attr, 'jsonAttr')
319 return self.mstpctlcmd.get_bridge_port_attr(bridgename,
320 portname,
321 json_attr)
322
323 def _get_bridge_port_list(self, ifaceobj):
324
325 # port list is also available in the previously
326 # parsed dependent list. Use that if available, instead
327 # of parsing port expr again
328 port_list = ifaceobj.lowerifaces
329 if port_list:
330 return port_list
331 ports = ifaceobj.get_attr_value_first('mstpctl-ports')
332 if ports:
333 return self.parse_port_list(ifaceobj.name, ports)
334 else:
335 return None
336
337 def _ports_enable_disable_ipv6(self, ports, enable='1'):
338 for p in ports:
339 try:
340 self.write_file('/proc/sys/net/ipv6/conf/%s' %p +
341 '/disable_ipv6', enable)
342 except Exception, e:
343 self.logger.info(str(e))
344 pass
345
346 def _add_ports(self, ifaceobj):
347 bridgeports = self._get_bridge_port_list(ifaceobj)
348
349 runningbridgeports = []
350 # Delete active ports not in the new port list
351 if not ifupdownflags.flags.PERFMODE:
352 runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
353 if runningbridgeports:
354 [self.ipcmd.link_set(bport, 'nomaster')
355 for bport in runningbridgeports
356 if not bridgeports or bport not in bridgeports]
357 else:
358 runningbridgeports = []
359 if not bridgeports:
360 return
361 err = 0
362 for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
363 try:
364 if (not ifupdownflags.flags.DRYRUN and
365 not self.ipcmd.link_exists(bridgeport)):
366 self.log_warn('%s: bridge port %s does not exist'
367 %(ifaceobj.name, bridgeport))
368 err += 1
369 continue
370 self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
371 self.ipcmd.addr_flush(bridgeport)
372 except Exception, e:
373 self.log_error(str(e), ifaceobj)
374
375 if err:
376 self.log_error('error configuring bridge (missing ports)')
377
378 def _apply_bridge_settings(self, ifaceobj, ifaceobj_getfunc):
379 check = False if ifupdownflags.flags.PERFMODE else True
380 try:
381 # set bridge attributes
382 for attrname, dstattrname in self._attrs_map.items():
383 config_val = ifaceobj.get_attr_value_first(attrname)
384 default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attrname)
385 if not default_val:
386 default_val = self.get_mod_subattr(attrname, 'default')
387 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
388 try:
389 running_val = self.mstpctlcmd.get_bridge_attr(
390 ifaceobj.name, jsonAttr)
391 except:
392 self.logger.info('%s: could not get running %s value'
393 %(ifaceobj.name, attrname))
394 running_val = None
395 if (not config_val and default_val and (running_val != default_val)):
396 # this happens when users remove an attribute from a port
397 # and expect the default to be restored with ifreload.
398 config_val = default_val
399 elif not config_val:
400 # there is nothing configured and no default to reset
401 continue
402 try:
403 if attrname == 'mstpctl-treeprio':
404 self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name,
405 config_val, check)
406 else:
407 self.mstpctlcmd.set_bridge_attr(ifaceobj.name,
408 dstattrname, config_val, check)
409 except Exception, e:
410 self.logger.warn('%s' %str(e))
411 pass
412
413 if self.ipcmd.bridge_is_vlan_aware(ifaceobj.name):
414 return
415 # set bridge port attributes
416 for attrname, dstattrname in self._port_attrs_map.items():
417 config_val = ifaceobj.get_attr_value_first(attrname)
418 default_val = self.get_mod_subattr(attrname,'default')
419 if not config_val:
420 # nothing configured, we may need to reset all ports to defaults
421 # if the default exists and jsonAttribute conversion exists
422 try:
423 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
424 if default_val and jsonAttr:
425 bridgeports = self._get_bridge_port_list(ifaceobj)
426 for port in bridgeports:
427 if not self.brctlcmd.is_bridge_port(port):
428 continue
429
430 bport_ifaceobjs = ifaceobj_getfunc(port)
431 if bport_ifaceobjs:
432 default_val = self._get_default_val(attrname, bport_ifaceobjs[0], ifaceobj)
433 for brport_ifaceobj in bport_ifaceobjs or []:
434 attr_value = brport_ifaceobj.get_attr_value_first(attrname)
435 if attr_value:
436 default_val = attr_value
437 break
438
439 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
440 port,
441 dstattrname,
442 default_val,
443 json_attr=jsonAttr)
444 except Exception as e:
445 self.logger.debug('%s' % str(e))
446 self.logger.info('%s: not resetting %s config'
447 %(ifaceobj.name, attrname))
448 # leave the loop for this attribute
449 continue
450
451 portlist = self.parse_port_list(ifaceobj.name, config_val)
452 if not portlist:
453 self.log_error('%s: error parsing \'%s %s\''
454 %(ifaceobj.name, attrname, config_val), ifaceobj)
455 continue
456 # there was a configured value so we need to parse it
457 # and set the attribute for each port configured
458 for p in portlist:
459 try:
460 (port, val) = p.split('=')
461 # if it is not bridge port, continue
462 if not os.path.exists('/sys/class/net/%s/brport' %port):
463 continue
464 json_attr = self.get_mod_subattr(attrname, 'jsonAttr')
465 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
466 port,
467 dstattrname,
468 val,
469 json_attr=json_attr)
470 except Exception, e:
471 self.log_error('%s: error setting %s (%s)'
472 %(ifaceobj.name, attrname, str(e)),
473 ifaceobj, raise_error=False)
474 except Exception, e:
475 self.log_warn(str(e))
476 pass
477
478 def _get_default_val(self, attr, ifaceobj, bridgeifaceobj):
479 if (self.set_default_mstp_vxlan_bridge_config
480 and ifaceobj.link_kind & ifaceLinkKind.VXLAN
481 and attr in (
482 'mstpctl-portbpdufilter',
483 'mstpctl-bpduguard',
484 'mstpctl-portadminedge',
485 )
486 ):
487 try:
488 config_val = bridgeifaceobj.get_attr_value_first(attr)
489 except Exception, e:
490 config_val = None
491 if config_val:
492 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
493 return 'yes'
494 else:
495 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
496 return [v.split('=')[1] for v in config_val.split()][index]
497 else:
498 return 'yes'
499 else:
500 default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attr)
501 if not default_val:
502 return self.get_mod_subattr(attr,'default')
503 return default_val
504
505 def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
506 bridgeifaceobj=None,
507 stp_running_on=True,
508 mstpd_running=True):
509 check = False if ifupdownflags.flags.PERFMODE else True
510 applied = False
511 if not bridgename and bridgeifaceobj:
512 bridgename = bridgeifaceobj.name
513
514 if not stp_running_on:
515 # stp may get turned on at a later point
516 self.logger.info('%s: ignoring config'
517 %(ifaceobj.name) +
518 ' (stp on bridge %s is not on yet)' %bridgename)
519 return applied
520 bvlan_aware = self.ipcmd.bridge_is_vlan_aware(bridgename)
521 if (not mstpd_running or
522 not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or
523 not bvlan_aware):
524 if (not bvlan_aware and
525 self.set_default_mstp_vxlan_bridge_config and
526 (ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
527 for attr in (
528 'mstpctl-portbpdufilter',
529 'mstpctl-bpduguard',
530 'mstpctl-portadminedge'
531 ):
532 json_attr = self.get_mod_subattr(attr, 'jsonAttr')
533 config_val = self._get_default_val(attr, ifaceobj,
534 bridgeifaceobj)
535 try:
536 self.mstpctlcmd.set_bridge_port_attr(bridgename,
537 ifaceobj.name,
538 self._port_attrs_map[attr],
539 config_val,
540 json_attr=json_attr)
541 except Exception, e:
542 self.log_warn('%s: error setting %s (%s)'
543 % (ifaceobj.name, attr, str(e)))
544
545 if not bvlan_aware:
546 # for "traditional" bridges we also want to let the user configure
547 # some attributes (possibly all of them in the future)
548 applied = self._apply_bridge_port_settings_attributes_list(
549 (
550 ('mstpctl-portrestrrole', 'portrestrrole'),
551 ('mstpctl-portautoedge', 'portautoedge')
552 ),
553 ifaceobj,
554 bridgeifaceobj,
555 bridgename,
556 applied
557 )
558 return applied
559 # set bridge port attributes
560 return self._apply_bridge_port_settings_attributes_list(
561 self._port_attrs_map.items(),
562 ifaceobj,
563 bridgeifaceobj,
564 bridgename,
565 applied
566 )
567
568 def _apply_bridge_port_settings_attributes_list(self, attributes_list, ifaceobj, bridgeifaceobj, bridgename, applied):
569 for attrname, dstattrname in attributes_list:
570 config_val = ifaceobj.get_attr_value_first(attrname)
571 default_val = self._get_default_val(attrname, ifaceobj, bridgeifaceobj)
572 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
573 # to see the running value, stp would have to be on
574 # so we would have parsed mstpctl showportdetail json output
575 try:
576 running_val = self.mstpctlcmd.get_bridge_port_attr(bridgename,
577 ifaceobj.name, jsonAttr)
578 except:
579 self.logger.info('%s %s: could not get running %s value'
580 %(bridgename, ifaceobj.name, attrname))
581 running_val = None
582 if (not config_val and default_val and (running_val != default_val)):
583 # this happens when users remove an attribute from a port
584 # and expect the default to be restored with ifreload.
585 config_val = default_val
586 elif not config_val:
587 # there is nothing configured and no default to reset
588 continue
589
590 try:
591 self.mstpctlcmd.set_bridge_port_attr(bridgename,
592 ifaceobj.name, dstattrname, config_val, json_attr=jsonAttr)
593 applied = True
594 except Exception, e:
595 self.log_error('%s: error setting %s (%s)'
596 %(ifaceobj.name, attrname, str(e)), ifaceobj,
597 raise_error=False)
598 return applied
599
600 def _apply_bridge_port_settings_all(self, ifaceobj,
601 ifaceobj_getfunc=None):
602 self.logger.info('%s: applying mstp configuration '
603 %ifaceobj.name + 'specific to ports')
604 # Query running bridge ports. and only apply attributes on them
605 bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
606 if not bridgeports:
607 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
608 return
609 for bport in bridgeports:
610 self.logger.info('%s: processing mstp config for port %s'
611 %(ifaceobj.name, bport))
612 if not self.ipcmd.link_exists(bport):
613 continue
614 if not os.path.exists('/sys/class/net/%s/brport' %bport):
615 continue
616 bportifaceobjlist = ifaceobj_getfunc(bport)
617 if not bportifaceobjlist:
618 continue
619 for bportifaceobj in bportifaceobjlist:
620 # Dont process bridge port if it already has been processed
621 if (bportifaceobj.module_flags.get(self.name,0x0) & \
622 mstpctlFlags.PORT_PROCESSED):
623 continue
624 try:
625 self._apply_bridge_port_settings(bportifaceobj,
626 ifaceobj.name, ifaceobj)
627 except Exception, e:
628 pass
629 self.log_warn(str(e))
630
631 def _is_running_userspace_stp_state_on(self, bridgename):
632 stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
633 if not stp_state_file:
634 return False
635 running_stp_state = self.read_file_oneline(stp_state_file)
636 if running_stp_state and running_stp_state == '2':
637 return True
638 return False
639
640 def _up(self, ifaceobj, ifaceobj_getfunc=None):
641 # Check if bridge port
642 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
643 if bridgename:
644 mstpd_running = self.mstpd_running
645 stp_running_on = self._is_running_userspace_stp_state_on(bridgename)
646 applied = self._apply_bridge_port_settings(ifaceobj, bridgename,
647 None, stp_running_on,
648 mstpd_running)
649 if applied:
650 ifaceobj.module_flags[self.name] = \
651 ifaceobj.module_flags.setdefault(self.name,0) | \
652 mstpctlFlags.PORT_PROCESSED
653 return
654 if not self._is_bridge(ifaceobj):
655 return
656 # we are now here because the ifaceobj is a bridge
657 stp = None
658 try:
659 porterr = False
660 porterrstr = ''
661 if ifaceobj.get_attr_value_first('mstpctl-ports'):
662 # If bridge ports specified with mstpctl attr, create the
663 # bridge and also add its ports
664 self.ipcmd.batch_start()
665 if not ifupdownflags.flags.PERFMODE:
666 if not self.ipcmd.link_exists(ifaceobj.name):
667 self.ipcmd.link_create(ifaceobj.name, 'bridge')
668 else:
669 self.ipcmd.link_create(ifaceobj.name, 'bridge')
670 try:
671 self._add_ports(ifaceobj)
672 except Exception, e:
673 porterr = True
674 porterrstr = str(e)
675 pass
676 finally:
677 self.ipcmd.batch_commit()
678 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
679 if running_ports:
680 # disable ipv6 for ports that were added to bridge
681 self._ports_enable_disable_ipv6(running_ports, '1')
682
683 stp = ifaceobj.get_attr_value_first('mstpctl-stp')
684 if stp:
685 self.set_iface_attr(ifaceobj, 'mstpctl-stp',
686 self.brctlcmd.bridge_set_stp)
687 else:
688 stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
689 if (self.mstpd_running and
690 (stp == 'yes' or stp == 'on')):
691 self._apply_bridge_settings(ifaceobj, ifaceobj_getfunc)
692 self._apply_bridge_port_settings_all(ifaceobj,
693 ifaceobj_getfunc=ifaceobj_getfunc)
694 except Exception, e:
695 self.log_error(str(e), ifaceobj)
696 if porterr:
697 raise Exception(porterrstr)
698
699 def _down(self, ifaceobj, ifaceobj_getfunc=None):
700 if not self._is_bridge(ifaceobj):
701 return
702 try:
703 if ifaceobj.get_attr_value_first('mstpctl-ports'):
704 # If bridge ports specified with mstpctl attr, delete the
705 # bridge
706 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
707 if ports:
708 self._ports_enable_disable_ipv6(ports, '0')
709 self.brctlcmd.delete_bridge(ifaceobj.name)
710 except Exception, e:
711 self.log_error(str(e), ifaceobj)
712
713 def _query_running_attrs(self, ifaceobjrunning, bridge_vlan_aware=False):
714 bridgeattrdict = {}
715
716 tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
717 #self.logger.info('A' + str(tmpbridgeattrdict))
718 if not tmpbridgeattrdict:
719 return bridgeattrdict
720
721 for k,v in tmpbridgeattrdict.items():
722 if k == 'stp' or not v:
723 continue
724 if k == 'ports':
725 ports = v.keys()
726 continue
727 attrname = 'mstpctl-' + k
728 if (v and v != self.get_mod_subattr(attrname, 'default')
729 and attrname != 'mstpctl-maxhops'):
730 bridgeattrdict[attrname] = [v]
731
732 ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
733 # Do this only for vlan-UNAWARE-bridge
734 if ports and not bridge_vlan_aware:
735 portconfig = {'mstpctl-portautoedge' : '',
736 'mstpctl-portbpdufilter' : '',
737 'mstpctl-portnetwork' : '',
738 'mstpctl-portpathcost' : '',
739 'mstpctl-portadminedge' : '',
740 'mstpctl-portp2p' : '',
741 'mstpctl-portrestrrole' : '',
742 'mstpctl-portrestrtcn' : '',
743 'mstpctl-bpduguard' : '',
744 'mstpctl-treeportprio' : '',
745 'mstpctl-treeportcost' : ''}
746
747 for p in ports:
748
749 for attr in ['mstpctl-portautoedge',
750 'mstpctl-portbpdufilter',
751 'mstpctl-portnetwork',
752 'mstpctl-portadminedge',
753 'mstpctl-portp2p',
754 'mstpctl-portrestrrole',
755 'mstpctl-portrestrtcn',
756 'mstpctl-bpduguard',
757 '']:
758 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
759 p, attr)
760 if v and v != 'no':
761 portconfig[attr] += ' %s=%s' % (p, v)
762
763 for attr in ['mstpctl-portpathcost', 'mstpctl-treeportcost']:
764 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
765 p, attr)
766 if v and v != self.get_mod_subattr(attr, 'default'):
767 portconfig[attr] += ' %s=%s' % (p, v)
768
769 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
770 if v})
771 return bridgeattrdict
772
773 def _get_config_stp(self, ifaceobj):
774 stp = (ifaceobj.get_attr_value_first('mstpctl-stp') or
775 ifaceobj.get_attr_value_first('bridge-stp') or
776 policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr='mstpctl-stp') or
777 # this is a temporary method to access policy default value of bridge-stp
778 policymanager.policymanager_api.get_iface_default(module_name='bridge', ifname=ifaceobj.name, attr='bridge-stp'))
779 return utils.get_boolean_from_string(stp)
780
781 def _get_running_stp(self, ifaceobj):
782 stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
783 return utils.get_boolean_from_string(stp)
784
785 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
786 ifaceobj_getfunc=None):
787 # list of attributes that are not supported currently
788 blacklistedattrs = ['mstpctl-portpathcost',
789 'mstpctl-treeportprio', 'mstpctl-treeportcost']
790 if not self.brctlcmd.bridge_exists(ifaceobj.name):
791 self.logger.debug('bridge %s does not exist' %ifaceobj.name)
792 return
793 ifaceattrs = self.dict_key_subset(ifaceobj.config,
794 self.get_mod_attrs())
795 if self.set_default_mstp_vxlan_bridge_config:
796 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
797 if attr not in ifaceattrs:
798 ifaceattrs.append(attr)
799 if not ifaceattrs:
800 return
801 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
802 #self.logger.info('B' + str(runningattrs))
803 if not runningattrs:
804 runningattrs = {}
805 config_stp = self._get_config_stp(ifaceobj)
806 running_stp = self._get_running_stp(ifaceobj)
807 running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
808 for k in ifaceattrs:
809 # for all mstpctl options
810 if k in blacklistedattrs:
811 continue
812 if k in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
813 #special case, 'ifquery --check --with-defaults' on a VLAN
814 #unaware bridge
815 if not running_port_list:
816 continue
817 if (not config_stp or not running_stp):
818 continue
819 v = ifaceobj.get_attr_value_first(k)
820 config_val = {}
821 running_val = {}
822 result = 0
823 bridge_ports = {}
824 state = ''
825 if v:
826 for bportval in v.split():
827 config_val[bportval.split('=')[0]] = bportval.split('=')[1]
828 #for bport in bridgeports:
829 for bport in running_port_list:
830 bportifaceobjlist = ifaceobj_getfunc(bport)
831 if not bportifaceobjlist:
832 continue
833 for bportifaceobj in bportifaceobjlist:
834 if (bport not in config_val):
835 if (bportifaceobj.link_kind & ifaceLinkKind.VXLAN):
836 if (not ifupdownflags.flags.WITHDEFAULTS or
837 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
838 continue
839 conf = 'yes'
840 else:
841 continue
842 else:
843 if ((bportifaceobj.link_kind & ifaceLinkKind.VXLAN) and
844 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
845 continue
846 conf = config_val[bport]
847 jsonAttr = self.get_mod_subattr(k, 'jsonAttr')
848 try:
849 running_val = self.mstpctlcmd.get_bridge_port_attr(ifaceobj.name, bport, jsonAttr)
850 except:
851 self.logger.info('%s %s: could not get running %s value'
852 %(ifaceobj.name, bport, attr))
853 running_val = None
854 if conf != running_val:
855 result = 1
856 bridge_ports.update({bport : running_val})
857 for port, val in bridge_ports.items():
858 #running state format
859 #mstpctl-portbpdufilter swp2=yes swp1=yes vx-14567101=yes [pass]
860 #mstpctl-bpduguard swp2=yes swp1=yes vx-14567101=yes [pass]
861 state += port + '=' + val + ' '
862 if state:
863 ifaceobjcurr.update_config_with_status(k, state, result)
864 continue
865
866 # get the corresponding ifaceobj attr
867 v = ifaceobj.get_attr_value_first(k)
868 if not v:
869 continue
870
871 # Get the running attribute
872 rv = runningattrs.get(k[8:])
873 if k == 'mstpctl-stp':
874 # special case stp compare because it may
875 # contain more than one valid values
876 stp_on_vals = ['on', 'yes']
877 stp_off_vals = ['off']
878 rv = self.brctlcmd.bridge_get_stp(ifaceobj.name)
879 if ((v in stp_on_vals and rv in stp_on_vals) or
880 (v in stp_off_vals and rv in stp_off_vals)):
881 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
882 else:
883 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
884 continue
885
886 if k == 'mstpctl-ports':
887 # special case ports because it can contain regex or glob
888 # XXX: We get all info from mstputils, which means if
889 # mstpd is down, we will not be returning any bridge bridgeports
890 bridge_port_list = self._get_bridge_port_list(ifaceobj)
891 if not running_port_list and not bridge_port_list:
892 continue
893 portliststatus = 1
894 if running_port_list and bridge_port_list:
895 difference = Set(running_port_list).symmetric_difference(
896 Set(bridge_port_list))
897 if not difference:
898 portliststatus = 0
899 ifaceobjcurr.update_config_with_status('mstpctl-ports',
900 ' '.join(running_port_list)
901 if running_port_list else '', portliststatus)
902 elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
903 # Now, look at port attributes
904 # derive the mstpctlcmd attr name
905 #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
906 mstpctlcmdattrname = k[8:]
907
908 # for port attributes, the attributes are in a list
909 # <portname>=<portattrvalue>
910 status = 0
911 currstr = ''
912 vlist = self.parse_port_list(ifaceobj.name, v)
913 if not vlist:
914 continue
915 for vlistitem in vlist:
916 try:
917 (p, v) = vlistitem.split('=')
918 currv = self._get_bridge_port_attr_value(ifaceobj.name, p, k)
919 if currv:
920 currstr += ' %s=%s' %(p, currv)
921 else:
922 currstr += ' %s=%s' %(p, 'None')
923 if currv != v:
924 status = 1
925 except Exception, e:
926 self.log_warn(str(e))
927 pass
928 ifaceobjcurr.update_config_with_status(k, currstr, status)
929 elif not rv:
930 ifaceobjcurr.update_config_with_status(k, '', 1)
931 elif v != rv:
932 ifaceobjcurr.update_config_with_status(k, rv, 1)
933 else:
934 ifaceobjcurr.update_config_with_status(k, rv, 0)
935
936 def _query_check_bridge_vxlan_port(self, ifaceobj, ifaceobjcurr,
937 ifaceobj_getfunc=None):
938 masters = ifaceobj.upperifaces
939 if not masters:
940 return
941 for bridge in masters:
942 bifaceobjlist = ifaceobj_getfunc(bridge)
943 for bifaceobj in bifaceobjlist:
944 if (self._is_bridge(bifaceobj) and
945 self.set_default_mstp_vxlan_bridge_config and
946 (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
947 config_stp = self._get_config_stp(bifaceobj)
948 running_stp = self._get_running_stp(bifaceobj)
949 if (not config_stp or not running_stp):
950 continue
951 for attr in (
952 'mstpctl-portbpdufilter',
953 'mstpctl-bpduguard',
954 'mstpctl-portadminedge'
955 ):
956 jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
957 config_val = bifaceobj.get_attr_value_first(attr)
958 if config_val:
959 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
960 if not ifupdownflags.flags.WITHDEFAULTS:
961 continue
962 config_val = 'yes'
963 else:
964 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
965 config_val = [v.split('=')[1] for v in config_val.split()][index]
966 else:
967 if not ifupdownflags.flags.WITHDEFAULTS:
968 continue
969 config_val = 'yes'
970 try:
971 running_val = self.mstpctlcmd.get_bridge_port_attr(bifaceobj.name,
972 ifaceobj.name, jsonAttr)
973 except:
974 self.logger.info('%s %s: could not get running %s value'
975 %(bifaceobj.name, ifaceobj.name, attr))
976 running_val = None
977 ifaceobjcurr.update_config_with_status(attr,
978 running_val,
979 0 if running_val == config_val else 1)
980 return
981
982
983 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
984 if not self.ipcmd.link_exists(ifaceobj.name):
985 #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
986 ifaceobjcurr.status = ifaceStatus.NOTFOUND
987 return
988 # Check if this is a bridge port
989 if not self._is_bridge_port(ifaceobj):
990 # mark all the bridge attributes as error
991 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
992 self._port_attrs_map.keys(), 0)
993 return
994 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
995 # list of attributes that are not supported currently
996 blacklistedattrs = ['mstpctl-portpathcost',
997 'mstpctl-treeportprio', 'mstpctl-treeportcost']
998 ifaceattrs = self.dict_key_subset(ifaceobj.config,
999 self._port_attrs_map.keys())
1000 if not ifaceattrs:
1001 return
1002 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
1003 #self.logger.info('C' + str(runningattrs))
1004 if not runningattrs:
1005 runningattrs = {}
1006 for k in ifaceattrs:
1007 # for all mstpctl options
1008 # get the corresponding ifaceobj attr
1009 v = ifaceobj.get_attr_value_first(k)
1010 if not v or k in blacklistedattrs:
1011 ifaceobjcurr.update_config_with_status(k, v, -1)
1012 continue
1013 currv = self._get_bridge_port_attr_value(bridgename, ifaceobj.name, k)
1014 if currv:
1015 if currv != v:
1016 ifaceobjcurr.update_config_with_status(k, currv, 1)
1017 else:
1018 ifaceobjcurr.update_config_with_status(k, currv, 0)
1019 else:
1020 ifaceobjcurr.update_config_with_status(k, None, 1)
1021
1022 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
1023 if self._is_bridge(ifaceobj):
1024 self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
1025 elif ifaceobj.link_kind & ifaceLinkKind.VXLAN:
1026 self._query_check_bridge_vxlan_port(ifaceobj, ifaceobjcurr,
1027 ifaceobj_getfunc)
1028 else:
1029 self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
1030
1031 def _query_bridge_port_attr(self, ifaceobjrunning, bridgename, attr, value_cmp):
1032 v = self._get_bridge_port_attr_value(bridgename,
1033 ifaceobjrunning.name,
1034 attr)
1035 if v and value_cmp and v != value_cmp:
1036 ifaceobjrunning.update_config(attr, v)
1037 elif v and not value_cmp:
1038 ifaceobjrunning.update_config(attr, v)
1039
1040 def _query_running_bridge_port(self, ifaceobjrunning):
1041 bridgename = self.ipcmd.bridge_port_get_bridge_name(
1042 ifaceobjrunning.name)
1043 if not bridgename:
1044 self.logger.warn('%s: unable to determine bridgename'
1045 %ifaceobjrunning.name)
1046 return
1047 if self.brctlcmd.bridge_get_stp(bridgename) == 'no':
1048 # This bridge does not run stp, return
1049 return
1050 # if userspace stp not set, return
1051 if self.systcl_get_net_bridge_stp_user_space() != '1':
1052 return
1053
1054 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1055 'mstpctl-portautoedge',
1056 self.get_mod_subattr('mstpctl-portautoedge', 'default'))
1057
1058 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1059 'mstpctl-portbpdufilter',
1060 'no')
1061
1062 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1063 'mstpctl-portnetwork',
1064 'no')
1065
1066 # XXX: Can we really get path cost of a port ???
1067 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
1068 #if v and v != self.get_mod_subattr('mstpctl-pathcost',
1069 # 'default'):
1070 # ifaceobjrunning.update_config('mstpctl-network', v)
1071
1072 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1073 'mstpctl-portadminedge',
1074 'no')
1075
1076 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1077 'mstpctl-portp2p',
1078 'auto')
1079
1080 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1081 'mstpctl-portrestrrole',
1082 'no')
1083
1084 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1085 'mstpctl-portrestrtcn',
1086 'no')
1087
1088 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1089 'mstpctl-bpduguard',
1090 'no')
1091
1092 # XXX: Can we really get path cost of a port ???
1093 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1094 # p, 'treeprio')
1095 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
1096 # 'default'):
1097 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
1098
1099 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1100 # p, 'treecost')
1101 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
1102 # 'default'):
1103 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
1104
1105 def _query_running_bridge(self, ifaceobjrunning):
1106 if self.brctlcmd.bridge_get_stp(ifaceobjrunning.name) == 'no':
1107 # This bridge does not run stp, return
1108 return
1109 # if userspace stp not set, return
1110 if self.systcl_get_net_bridge_stp_user_space() != '1':
1111 return
1112 # Check if mstp really knows about this bridge
1113 if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
1114 return
1115 bridge_vlan_aware = False
1116 if ifaceobjrunning.get_attr_value_first('bridge-vlan-aware') == 'yes':
1117 bridge_vlan_aware = True
1118 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1119 ifaceobjrunning,
1120 bridge_vlan_aware))
1121
1122 def _query_running(self, ifaceobjrunning, **extra_args):
1123 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
1124 self._query_running_bridge(ifaceobjrunning)
1125 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
1126 self._query_running_bridge_port(ifaceobjrunning)
1127
1128 def _query_bridge_port(self, ifaceobj, ifaceobj_getfunc=None):
1129 """
1130 Example:
1131 Configuration:
1132 auto vxlan1wd
1133 iface vxlan1wd
1134 vxlan-id 1001
1135
1136 auto vxlan2wd
1137 iface vxlan2wd
1138 vxlan-id 1002
1139
1140 auto brwithdef2
1141 iface brwithdef2
1142 bridge_ports vxlan1wd vxlan2wd
1143 bridge-vlan-aware yes
1144
1145 Output:
1146 $ ifquery vxlan1wd
1147 auto vxlan1wd
1148 iface vxlan1wd
1149 vxlan-id 1001
1150
1151 $ ifquery --with-defaults vxlan1wd
1152 auto vxlan1wd
1153 iface vxlan1wd
1154 vxlan-id 1001
1155 mstpctl-portbpdufilter yes
1156 mstpctl-bpduguard yes
1157 """
1158 masters = ifaceobj.upperifaces
1159 if not masters:
1160 return
1161 try:
1162 for bridge in masters:
1163 bifaceobj = ifaceobj_getfunc(bridge)[0]
1164 if (self._is_bridge(bifaceobj) and
1165 self.set_default_mstp_vxlan_bridge_config and
1166 (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
1167 for attr in ('mstpctl-portbpdufilter',
1168 'mstpctl-bpduguard',
1169 'mstpctl-portadminedge'):
1170 jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
1171 config_val = ifaceobj.get_attr_value_first(attr)
1172 if config_val or not ifupdownflags.flags.WITHDEFAULTS:
1173 continue
1174 config_val = 'yes'
1175 ifaceobj.replace_config(attr, config_val)
1176 return
1177 except Exception, e:
1178 self.logger.info("%s: %s" %(ifaceobj.name, str(e)))
1179 pass
1180
1181 def _query(self, ifaceobj, ifaceobj_getfunc=None, **kwargs):
1182 """ add default policy attributes supported by the module """
1183 if not self._is_bridge(ifaceobj):
1184 if (ifaceobj.module_flags.get(self.name,0x0) &
1185 mstpctlFlags.PORT_PROCESSED):
1186 return
1187 self._query_bridge_port(ifaceobj, ifaceobj_getfunc)
1188 ifaceobj.module_flags[self.name] = (
1189 ifaceobj.module_flags.setdefault(self.name,0) |
1190 mstpctlFlags.PORT_PROCESSED)
1191 return
1192 lowerinfs = ifaceobj.lowerifaces
1193 if not lowerinfs:
1194 return
1195 if ifaceobj.get_attr_value_first('bridge-vlan-aware') != 'yes':
1196 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1197 state = ''
1198 config = ifaceobj.get_attr_value_first(attr)
1199 for port in lowerinfs:
1200 bportobjlist = ifaceobj_getfunc(port)
1201 for bportobj in bportobjlist:
1202 if bportobj.get_attr_value_first('vxlan-id'):
1203 if config:
1204 if port not in [v.split('=')[0] for v in config.split()]:
1205 config += ' %s=yes' %port
1206 else:
1207 state += '%s=yes ' %port
1208 ifaceobj.replace_config(attr, config if config else state)
1209 else:
1210 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1211 state = ''
1212 config = ifaceobj.get_attr_value_first(attr)
1213 for port in lowerinfs:
1214 bportobjlist = ifaceobj_getfunc(port)
1215 for bportobj in bportobjlist:
1216 if (bportobj.module_flags.get(self.name,0x0) &
1217 mstpctlFlags.PORT_PROCESSED):
1218 continue
1219 if bportobj.get_attr_value_first('vxlan-id'):
1220 if config:
1221 if port not in [v.split('=')[0] for v in config.split()]:
1222 bportobj.update_config(attr, 'yes')
1223 else:
1224 index = [v.split('=')[0] for v in config.split()].index(port)
1225 state = [v.split('=')[1] for v in config.split()][index]
1226 bportobj.update_config(attr, '%s' %state)
1227 v = config.split()
1228 del v[index]
1229 config = ' '.join(v)
1230 else:
1231 bportobj.replace_config(attr, 'yes')
1232 bportobj.module_flags[self.name] = (
1233 bportobj.module_flags.setdefault(self.name,0) |
1234 mstpctlFlags.PORT_PROCESSED)
1235 if config:
1236 ifaceobj.replace_config(attr, config)
1237
1238
1239
1240 _run_ops = {'pre-up' : _up,
1241 'post-down' : _down,
1242 'query-checkcurr' : _query_check,
1243 'query-running' : _query_running,
1244 'query' : _query}
1245
1246 def get_ops(self):
1247 """ returns list of ops supported by this module """
1248 return self._run_ops.keys()
1249
1250 def _init_command_handlers(self):
1251 if not self.ipcmd:
1252 self.ipcmd = self.brctlcmd = LinkUtils()
1253 if not self.mstpctlcmd:
1254 self.mstpctlcmd = mstpctlutil()
1255
1256 def run(self, ifaceobj, operation, query_ifaceobj=None,
1257 ifaceobj_getfunc=None, **extra_args):
1258 """ run mstp configuration on the interface object passed as argument
1259
1260 Args:
1261 **ifaceobj** (object): iface object
1262
1263 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1264 'query-running'
1265 Kwargs:
1266 **query_ifaceobj** (object): query check ifaceobject. This is only
1267 valid when op is 'query-checkcurr'. It is an object same as
1268 ifaceobj, but contains running attribute values and its config
1269 status. The modules can use it to return queried running state
1270 of interfaces. status is success if the running state is same
1271 as user required state in ifaceobj. error otherwise.
1272 """
1273 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1274 return
1275 op_handler = self._run_ops.get(operation)
1276 if not op_handler:
1277 return
1278 self._init_command_handlers()
1279 if operation == 'query-checkcurr':
1280 op_handler(self, ifaceobj, query_ifaceobj,
1281 ifaceobj_getfunc=ifaceobj_getfunc)
1282 else:
1283 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)