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