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