]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/mstpctl.py
addons: address: add l3_intf_arp_accept policy to control ARP_ACCEPT
[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_ifaceobjs = ifaceobj_getfunc(port)
427 if bport_ifaceobjs:
428 default_val = self._get_default_val(attrname, bport_ifaceobjs[0], ifaceobj)
429 for brport_ifaceobj in bport_ifaceobjs or []:
430 attr_value = brport_ifaceobj.get_attr_value_first(attrname)
431 if attr_value:
432 default_val = attr_value
433 break
434
435 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
436 port,
437 dstattrname,
438 default_val,
439 json_attr=jsonAttr)
440 except Exception as e:
441 self.logger.debug('%s' % str(e))
442 self.logger.info('%s: not resetting %s config'
443 %(ifaceobj.name, attrname))
444 # leave the loop for this attribute
445 continue
446
447 portlist = self.parse_port_list(ifaceobj.name, config_val)
448 if not portlist:
449 self.log_error('%s: error parsing \'%s %s\''
450 %(ifaceobj.name, attrname, config_val), ifaceobj)
451 continue
452 # there was a configured value so we need to parse it
453 # and set the attribute for each port configured
454 for p in portlist:
455 try:
456 (port, val) = p.split('=')
457 # if it is not bridge port, continue
458 if not os.path.exists('/sys/class/net/%s/brport' %port):
459 continue
460 json_attr = self.get_mod_subattr(attrname, 'jsonAttr')
461 self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
462 port,
463 dstattrname,
464 val,
465 json_attr=json_attr)
466 except Exception, e:
467 self.log_error('%s: error setting %s (%s)'
468 %(ifaceobj.name, attrname, str(e)),
469 ifaceobj, raise_error=False)
470 except Exception, e:
471 self.log_warn(str(e))
472 pass
473
474 def _get_default_val(self, attr, ifaceobj, bridgeifaceobj):
475 if (self.set_default_mstp_vxlan_bridge_config
476 and ifaceobj.link_kind & ifaceLinkKind.VXLAN
477 and attr in (
478 'mstpctl-portbpdufilter',
479 'mstpctl-bpduguard',
480 'mstpctl-portadminedge',
481 )
482 ):
483 try:
484 config_val = bridgeifaceobj.get_attr_value_first(attr)
485 except Exception, e:
486 config_val = None
487 if config_val:
488 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
489 return 'yes'
490 else:
491 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
492 return [v.split('=')[1] for v in config_val.split()][index]
493 else:
494 return 'yes'
495 else:
496 default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attr)
497 if not default_val:
498 return self.get_mod_subattr(attr,'default')
499 return default_val
500
501 def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
502 bridgeifaceobj=None,
503 stp_running_on=True,
504 mstpd_running=True):
505 check = False if ifupdownflags.flags.PERFMODE else True
506 applied = False
507 if not bridgename and bridgeifaceobj:
508 bridgename = bridgeifaceobj.name
509
510 if not stp_running_on:
511 # stp may get turned on at a later point
512 self.logger.info('%s: ignoring config'
513 %(ifaceobj.name) +
514 ' (stp on bridge %s is not on yet)' %bridgename)
515 return applied
516 bvlan_aware = self.ipcmd.bridge_is_vlan_aware(bridgename)
517 if (not mstpd_running or
518 not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or
519 not bvlan_aware):
520 if (not bvlan_aware and
521 self.set_default_mstp_vxlan_bridge_config and
522 (ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
523 for attr in (
524 'mstpctl-portbpdufilter',
525 'mstpctl-bpduguard',
526 'mstpctl-portadminedge'
527 ):
528 json_attr = self.get_mod_subattr(attr, 'jsonAttr')
529 config_val = self._get_default_val(attr, ifaceobj,
530 bridgeifaceobj)
531 try:
532 self.mstpctlcmd.set_bridge_port_attr(bridgename,
533 ifaceobj.name,
534 self._port_attrs_map[attr],
535 config_val,
536 json_attr=json_attr)
537 except Exception, e:
538 self.log_warn('%s: error setting %s (%s)'
539 % (ifaceobj.name, attr, str(e)))
540
541 if not bvlan_aware:
542 # for "traditional" bridges we also want to let the user configure
543 # some attributes (possibly all of them in the future)
544 applied = self._apply_bridge_port_settings_attributes_list(
545 (
546 ('mstpctl-portrestrrole', 'portrestrrole'),
547 ('mstpctl-portautoedge', 'portautoedge')
548 ),
549 ifaceobj,
550 bridgeifaceobj,
551 bridgename,
552 applied
553 )
554 return applied
555 # set bridge port attributes
556 return self._apply_bridge_port_settings_attributes_list(
557 self._port_attrs_map.items(),
558 ifaceobj,
559 bridgeifaceobj,
560 bridgename,
561 applied
562 )
563
564 def _apply_bridge_port_settings_attributes_list(self, attributes_list, ifaceobj, bridgeifaceobj, bridgename, applied):
565 for attrname, dstattrname in attributes_list:
566 config_val = ifaceobj.get_attr_value_first(attrname)
567 default_val = self._get_default_val(attrname, ifaceobj, bridgeifaceobj)
568 jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
569 # to see the running value, stp would have to be on
570 # so we would have parsed mstpctl showportdetail json output
571 try:
572 running_val = self.mstpctlcmd.get_bridge_port_attr(bridgename,
573 ifaceobj.name, jsonAttr)
574 except:
575 self.logger.info('%s %s: could not get running %s value'
576 %(bridgename, ifaceobj.name, attrname))
577 running_val = None
578 if (not config_val and default_val and (running_val != default_val)):
579 # this happens when users remove an attribute from a port
580 # and expect the default to be restored with ifreload.
581 config_val = default_val
582 elif not config_val:
583 # there is nothing configured and no default to reset
584 continue
585
586 try:
587 self.mstpctlcmd.set_bridge_port_attr(bridgename,
588 ifaceobj.name, dstattrname, config_val, json_attr=jsonAttr)
589 applied = True
590 except Exception, e:
591 self.log_error('%s: error setting %s (%s)'
592 %(ifaceobj.name, attrname, str(e)), ifaceobj,
593 raise_error=False)
594 return applied
595
596 def _apply_bridge_port_settings_all(self, ifaceobj,
597 ifaceobj_getfunc=None):
598 self.logger.info('%s: applying mstp configuration '
599 %ifaceobj.name + 'specific to ports')
600 # Query running bridge ports. and only apply attributes on them
601 bridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
602 if not bridgeports:
603 self.logger.debug('%s: cannot find bridgeports' %ifaceobj.name)
604 return
605 for bport in bridgeports:
606 self.logger.info('%s: processing mstp config for port %s'
607 %(ifaceobj.name, bport))
608 if not self.ipcmd.link_exists(bport):
609 continue
610 if not os.path.exists('/sys/class/net/%s/brport' %bport):
611 continue
612 bportifaceobjlist = ifaceobj_getfunc(bport)
613 if not bportifaceobjlist:
614 continue
615 for bportifaceobj in bportifaceobjlist:
616 # Dont process bridge port if it already has been processed
617 if (bportifaceobj.module_flags.get(self.name,0x0) & \
618 mstpctlFlags.PORT_PROCESSED):
619 continue
620 try:
621 self._apply_bridge_port_settings(bportifaceobj,
622 ifaceobj.name, ifaceobj)
623 except Exception, e:
624 pass
625 self.log_warn(str(e))
626
627 def _is_running_userspace_stp_state_on(self, bridgename):
628 stp_state_file = '/sys/class/net/%s/bridge/stp_state' %bridgename
629 if not stp_state_file:
630 return False
631 running_stp_state = self.read_file_oneline(stp_state_file)
632 if running_stp_state and running_stp_state == '2':
633 return True
634 return False
635
636 def _up(self, ifaceobj, ifaceobj_getfunc=None):
637 # Check if bridge port
638 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
639 if bridgename:
640 mstpd_running = self.mstpd_running
641 stp_running_on = self._is_running_userspace_stp_state_on(bridgename)
642 applied = self._apply_bridge_port_settings(ifaceobj, bridgename,
643 None, stp_running_on,
644 mstpd_running)
645 if applied:
646 ifaceobj.module_flags[self.name] = \
647 ifaceobj.module_flags.setdefault(self.name,0) | \
648 mstpctlFlags.PORT_PROCESSED
649 return
650 if not self._is_bridge(ifaceobj):
651 return
652 # we are now here because the ifaceobj is a bridge
653 stp = None
654 try:
655 porterr = False
656 porterrstr = ''
657 if ifaceobj.get_attr_value_first('mstpctl-ports'):
658 # If bridge ports specified with mstpctl attr, create the
659 # bridge and also add its ports
660 self.ipcmd.batch_start()
661 if not ifupdownflags.flags.PERFMODE:
662 if not self.ipcmd.link_exists(ifaceobj.name):
663 self.ipcmd.link_create(ifaceobj.name, 'bridge')
664 else:
665 self.ipcmd.link_create(ifaceobj.name, 'bridge')
666 try:
667 self._add_ports(ifaceobj)
668 except Exception, e:
669 porterr = True
670 porterrstr = str(e)
671 pass
672 finally:
673 self.ipcmd.batch_commit()
674 running_ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
675 if running_ports:
676 # disable ipv6 for ports that were added to bridge
677 self._ports_enable_disable_ipv6(running_ports, '1')
678
679 stp = ifaceobj.get_attr_value_first('mstpctl-stp')
680 if stp:
681 self.set_iface_attr(ifaceobj, 'mstpctl-stp',
682 self.brctlcmd.bridge_set_stp)
683 else:
684 stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
685 if (self.mstpd_running and
686 (stp == 'yes' or stp == 'on')):
687 self._apply_bridge_settings(ifaceobj, ifaceobj_getfunc)
688 self._apply_bridge_port_settings_all(ifaceobj,
689 ifaceobj_getfunc=ifaceobj_getfunc)
690 except Exception, e:
691 self.log_error(str(e), ifaceobj)
692 if porterr:
693 raise Exception(porterrstr)
694
695 def _down(self, ifaceobj, ifaceobj_getfunc=None):
696 if not self._is_bridge(ifaceobj):
697 return
698 try:
699 if ifaceobj.get_attr_value_first('mstpctl-ports'):
700 # If bridge ports specified with mstpctl attr, delete the
701 # bridge
702 ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
703 if ports:
704 self._ports_enable_disable_ipv6(ports, '0')
705 self.brctlcmd.delete_bridge(ifaceobj.name)
706 except Exception, e:
707 self.log_error(str(e), ifaceobj)
708
709 def _query_running_attrs(self, ifaceobjrunning, bridge_vlan_aware=False):
710 bridgeattrdict = {}
711
712 tmpbridgeattrdict = self.mstpctlcmd.get_bridge_attrs(ifaceobjrunning.name)
713 #self.logger.info('A' + str(tmpbridgeattrdict))
714 if not tmpbridgeattrdict:
715 return bridgeattrdict
716
717 for k,v in tmpbridgeattrdict.items():
718 if k == 'stp' or not v:
719 continue
720 if k == 'ports':
721 ports = v.keys()
722 continue
723 attrname = 'mstpctl-' + k
724 if (v and v != self.get_mod_subattr(attrname, 'default')
725 and attrname != 'mstpctl-maxhops'):
726 bridgeattrdict[attrname] = [v]
727
728 ports = self.brctlcmd.get_bridge_ports(ifaceobjrunning.name)
729 # Do this only for vlan-UNAWARE-bridge
730 if ports and not bridge_vlan_aware:
731 portconfig = {'mstpctl-portautoedge' : '',
732 'mstpctl-portbpdufilter' : '',
733 'mstpctl-portnetwork' : '',
734 'mstpctl-portpathcost' : '',
735 'mstpctl-portadminedge' : '',
736 'mstpctl-portp2p' : '',
737 'mstpctl-portrestrrole' : '',
738 'mstpctl-portrestrtcn' : '',
739 'mstpctl-bpduguard' : '',
740 'mstpctl-treeportprio' : '',
741 'mstpctl-treeportcost' : ''}
742
743 for p in ports:
744
745 for attr in ['mstpctl-portautoedge',
746 'mstpctl-portbpdufilter',
747 'mstpctl-portnetwork',
748 'mstpctl-portadminedge',
749 'mstpctl-portp2p',
750 'mstpctl-portrestrrole',
751 'mstpctl-portrestrtcn',
752 'mstpctl-bpduguard',
753 '']:
754 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
755 p, attr)
756 if v and v != 'no':
757 portconfig[attr] += ' %s=%s' % (p, v)
758
759 for attr in ['mstpctl-portpathcost', 'mstpctl-treeportcost']:
760 v = self._get_bridge_port_attr_value(ifaceobjrunning.name,
761 p, attr)
762 if v and v != self.get_mod_subattr(attr, 'default'):
763 portconfig[attr] += ' %s=%s' % (p, v)
764
765 bridgeattrdict.update({k : [v] for k, v in portconfig.items()
766 if v})
767 return bridgeattrdict
768
769 def _get_config_stp(self, ifaceobj):
770 stp = (ifaceobj.get_attr_value_first('mstpctl-stp') or
771 ifaceobj.get_attr_value_first('bridge-stp') or
772 policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr='mstpctl-stp') or
773 # this is a temporary method to access policy default value of bridge-stp
774 policymanager.policymanager_api.get_iface_default(module_name='bridge', ifname=ifaceobj.name, attr='bridge-stp'))
775 return utils.get_boolean_from_string(stp)
776
777 def _get_running_stp(self, ifaceobj):
778 stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
779 return utils.get_boolean_from_string(stp)
780
781 def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
782 ifaceobj_getfunc=None):
783 # list of attributes that are not supported currently
784 blacklistedattrs = ['mstpctl-portpathcost',
785 'mstpctl-treeportprio', 'mstpctl-treeportcost']
786 if not self.brctlcmd.bridge_exists(ifaceobj.name):
787 self.logger.debug('bridge %s does not exist' %ifaceobj.name)
788 return
789 ifaceattrs = self.dict_key_subset(ifaceobj.config,
790 self.get_mod_attrs())
791 if self.set_default_mstp_vxlan_bridge_config:
792 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
793 if attr not in ifaceattrs:
794 ifaceattrs.append(attr)
795 if not ifaceattrs:
796 return
797 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
798 #self.logger.info('B' + str(runningattrs))
799 if not runningattrs:
800 runningattrs = {}
801 config_stp = self._get_config_stp(ifaceobj)
802 running_stp = self._get_running_stp(ifaceobj)
803 running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name)
804 for k in ifaceattrs:
805 # for all mstpctl options
806 if k in blacklistedattrs:
807 continue
808 if k in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
809 #special case, 'ifquery --check --with-defaults' on a VLAN
810 #unaware bridge
811 if not running_port_list:
812 continue
813 if (not config_stp or not running_stp):
814 continue
815 v = ifaceobj.get_attr_value_first(k)
816 config_val = {}
817 running_val = {}
818 result = 0
819 bridge_ports = {}
820 state = ''
821 if v:
822 for bportval in v.split():
823 config_val[bportval.split('=')[0]] = bportval.split('=')[1]
824 #for bport in bridgeports:
825 for bport in running_port_list:
826 bportifaceobjlist = ifaceobj_getfunc(bport)
827 if not bportifaceobjlist:
828 continue
829 for bportifaceobj in bportifaceobjlist:
830 if (bport not in config_val):
831 if (bportifaceobj.link_kind & ifaceLinkKind.VXLAN):
832 if (not ifupdownflags.flags.WITHDEFAULTS or
833 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
834 continue
835 conf = 'yes'
836 else:
837 continue
838 else:
839 if ((bportifaceobj.link_kind & ifaceLinkKind.VXLAN) and
840 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
841 continue
842 conf = config_val[bport]
843 jsonAttr = self.get_mod_subattr(k, 'jsonAttr')
844 try:
845 running_val = self.mstpctlcmd.get_bridge_port_attr(ifaceobj.name, bport, jsonAttr)
846 except:
847 self.logger.info('%s %s: could not get running %s value'
848 %(ifaceobj.name, bport, attr))
849 running_val = None
850 if conf != running_val:
851 result = 1
852 bridge_ports.update({bport : running_val})
853 for port, val in bridge_ports.items():
854 #running state format
855 #mstpctl-portbpdufilter swp2=yes swp1=yes vx-14567101=yes [pass]
856 #mstpctl-bpduguard swp2=yes swp1=yes vx-14567101=yes [pass]
857 state += port + '=' + val + ' '
858 if state:
859 ifaceobjcurr.update_config_with_status(k, state, result)
860 continue
861
862 # get the corresponding ifaceobj attr
863 v = ifaceobj.get_attr_value_first(k)
864 if not v:
865 continue
866
867 # Get the running attribute
868 rv = runningattrs.get(k[8:])
869 if k == 'mstpctl-stp':
870 # special case stp compare because it may
871 # contain more than one valid values
872 stp_on_vals = ['on', 'yes']
873 stp_off_vals = ['off']
874 rv = self.brctlcmd.bridge_get_stp(ifaceobj.name)
875 if ((v in stp_on_vals and rv in stp_on_vals) or
876 (v in stp_off_vals and rv in stp_off_vals)):
877 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
878 else:
879 ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 1)
880 continue
881
882 if k == 'mstpctl-ports':
883 # special case ports because it can contain regex or glob
884 # XXX: We get all info from mstputils, which means if
885 # mstpd is down, we will not be returning any bridge bridgeports
886 bridge_port_list = self._get_bridge_port_list(ifaceobj)
887 if not running_port_list and not bridge_port_list:
888 continue
889 portliststatus = 1
890 if running_port_list and bridge_port_list:
891 difference = Set(running_port_list).symmetric_difference(
892 Set(bridge_port_list))
893 if not difference:
894 portliststatus = 0
895 ifaceobjcurr.update_config_with_status('mstpctl-ports',
896 ' '.join(running_port_list)
897 if running_port_list else '', portliststatus)
898 elif k[:12] == 'mstpctl-port' or k == 'mstpctl-bpduguard':
899 # Now, look at port attributes
900 # derive the mstpctlcmd attr name
901 #mstpctlcmdattrname = k[12:] if k[:12] == 'mstpctl-port' else k[8:]
902 mstpctlcmdattrname = k[8:]
903
904 # for port attributes, the attributes are in a list
905 # <portname>=<portattrvalue>
906 status = 0
907 currstr = ''
908 vlist = self.parse_port_list(ifaceobj.name, v)
909 if not vlist:
910 continue
911 for vlistitem in vlist:
912 try:
913 (p, v) = vlistitem.split('=')
914 currv = self._get_bridge_port_attr_value(ifaceobj.name, p, k)
915 if currv:
916 currstr += ' %s=%s' %(p, currv)
917 else:
918 currstr += ' %s=%s' %(p, 'None')
919 if currv != v:
920 status = 1
921 except Exception, e:
922 self.log_warn(str(e))
923 pass
924 ifaceobjcurr.update_config_with_status(k, currstr, status)
925 elif not rv:
926 ifaceobjcurr.update_config_with_status(k, '', 1)
927 elif v != rv:
928 ifaceobjcurr.update_config_with_status(k, rv, 1)
929 else:
930 ifaceobjcurr.update_config_with_status(k, rv, 0)
931
932 def _query_check_bridge_vxlan_port(self, ifaceobj, ifaceobjcurr,
933 ifaceobj_getfunc=None):
934 masters = ifaceobj.upperifaces
935 if not masters:
936 return
937 for bridge in masters:
938 bifaceobjlist = ifaceobj_getfunc(bridge)
939 for bifaceobj in bifaceobjlist:
940 if (self._is_bridge(bifaceobj) and
941 self.set_default_mstp_vxlan_bridge_config and
942 (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
943 config_stp = self._get_config_stp(bifaceobj)
944 running_stp = self._get_running_stp(bifaceobj)
945 if (not config_stp or not running_stp):
946 continue
947 for attr in (
948 'mstpctl-portbpdufilter',
949 'mstpctl-bpduguard',
950 'mstpctl-portadminedge'
951 ):
952 jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
953 config_val = bifaceobj.get_attr_value_first(attr)
954 if config_val:
955 if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]:
956 if not ifupdownflags.flags.WITHDEFAULTS:
957 continue
958 config_val = 'yes'
959 else:
960 index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name)
961 config_val = [v.split('=')[1] for v in config_val.split()][index]
962 else:
963 if not ifupdownflags.flags.WITHDEFAULTS:
964 continue
965 config_val = 'yes'
966 try:
967 running_val = self.mstpctlcmd.get_bridge_port_attr(bifaceobj.name,
968 ifaceobj.name, jsonAttr)
969 except:
970 self.logger.info('%s %s: could not get running %s value'
971 %(bifaceobj.name, ifaceobj.name, attr))
972 running_val = None
973 ifaceobjcurr.update_config_with_status(attr,
974 running_val,
975 0 if running_val == config_val else 1)
976 return
977
978
979 def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
980 if not self.ipcmd.link_exists(ifaceobj.name):
981 #self.logger.debug('bridge port %s does not exist' %ifaceobj.name)
982 ifaceobjcurr.status = ifaceStatus.NOTFOUND
983 return
984 # Check if this is a bridge port
985 if not self._is_bridge_port(ifaceobj):
986 # mark all the bridge attributes as error
987 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
988 self._port_attrs_map.keys(), 0)
989 return
990 bridgename = self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
991 # list of attributes that are not supported currently
992 blacklistedattrs = ['mstpctl-portpathcost',
993 'mstpctl-treeportprio', 'mstpctl-treeportcost']
994 ifaceattrs = self.dict_key_subset(ifaceobj.config,
995 self._port_attrs_map.keys())
996 if not ifaceattrs:
997 return
998 runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name)
999 #self.logger.info('C' + str(runningattrs))
1000 if not runningattrs:
1001 runningattrs = {}
1002 for k in ifaceattrs:
1003 # for all mstpctl options
1004 # get the corresponding ifaceobj attr
1005 v = ifaceobj.get_attr_value_first(k)
1006 if not v or k in blacklistedattrs:
1007 ifaceobjcurr.update_config_with_status(k, v, -1)
1008 continue
1009 currv = self._get_bridge_port_attr_value(bridgename, ifaceobj.name, k)
1010 if currv:
1011 if currv != v:
1012 ifaceobjcurr.update_config_with_status(k, currv, 1)
1013 else:
1014 ifaceobjcurr.update_config_with_status(k, currv, 0)
1015 else:
1016 ifaceobjcurr.update_config_with_status(k, None, 1)
1017
1018 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
1019 if self._is_bridge(ifaceobj):
1020 self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
1021 elif ifaceobj.link_kind & ifaceLinkKind.VXLAN:
1022 self._query_check_bridge_vxlan_port(ifaceobj, ifaceobjcurr,
1023 ifaceobj_getfunc)
1024 else:
1025 self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
1026
1027 def _query_bridge_port_attr(self, ifaceobjrunning, bridgename, attr, value_cmp):
1028 v = self._get_bridge_port_attr_value(bridgename,
1029 ifaceobjrunning.name,
1030 attr)
1031 if v and value_cmp and v != value_cmp:
1032 ifaceobjrunning.update_config(attr, v)
1033 elif v and not value_cmp:
1034 ifaceobjrunning.update_config(attr, v)
1035
1036 def _query_running_bridge_port(self, ifaceobjrunning):
1037 bridgename = self.ipcmd.bridge_port_get_bridge_name(
1038 ifaceobjrunning.name)
1039 if not bridgename:
1040 self.logger.warn('%s: unable to determine bridgename'
1041 %ifaceobjrunning.name)
1042 return
1043 if self.brctlcmd.bridge_get_stp(bridgename) == 'no':
1044 # This bridge does not run stp, return
1045 return
1046 # if userspace stp not set, return
1047 if self.systcl_get_net_bridge_stp_user_space() != '1':
1048 return
1049
1050 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1051 'mstpctl-portautoedge',
1052 self.get_mod_subattr('mstpctl-portautoedge', 'default'))
1053
1054 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1055 'mstpctl-portbpdufilter',
1056 'no')
1057
1058 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1059 'mstpctl-portnetwork',
1060 'no')
1061
1062 # XXX: Can we really get path cost of a port ???
1063 #v = self.mstpctlcmd.get_portpathcost(ifaceobjrunning.name, p)
1064 #if v and v != self.get_mod_subattr('mstpctl-pathcost',
1065 # 'default'):
1066 # ifaceobjrunning.update_config('mstpctl-network', v)
1067
1068 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1069 'mstpctl-portadminedge',
1070 'no')
1071
1072 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1073 'mstpctl-portp2p',
1074 'auto')
1075
1076 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1077 'mstpctl-portrestrrole',
1078 'no')
1079
1080 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1081 'mstpctl-portrestrtcn',
1082 'no')
1083
1084 self._query_bridge_port_attr(ifaceobjrunning, bridgename,
1085 'mstpctl-bpduguard',
1086 'no')
1087
1088 # XXX: Can we really get path cost of a port ???
1089 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1090 # p, 'treeprio')
1091 #if v and v != self.get_mod_subattr('mstpctl-treeportprio',
1092 # 'default'):
1093 # portconfig['mstpctl-treeportprio'] += ' %s=%s' %(p, v)
1094
1095 #v = self.mstpctlcmd.get_bridgeport_attr(ifaceobjrunning.name,
1096 # p, 'treecost')
1097 #if v and v != self.get_mod_subattr('mstpctl-treeportcost',
1098 # 'default'):
1099 # portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
1100
1101 def _query_running_bridge(self, ifaceobjrunning):
1102 if self.brctlcmd.bridge_get_stp(ifaceobjrunning.name) == 'no':
1103 # This bridge does not run stp, return
1104 return
1105 # if userspace stp not set, return
1106 if self.systcl_get_net_bridge_stp_user_space() != '1':
1107 return
1108 # Check if mstp really knows about this bridge
1109 if not self.mstpctlcmd.mstpbridge_exists(ifaceobjrunning.name):
1110 return
1111 bridge_vlan_aware = False
1112 if ifaceobjrunning.get_attr_value_first('bridge-vlan-aware') == 'yes':
1113 bridge_vlan_aware = True
1114 ifaceobjrunning.update_config_dict(self._query_running_attrs(
1115 ifaceobjrunning,
1116 bridge_vlan_aware))
1117
1118 def _query_running(self, ifaceobjrunning, **extra_args):
1119 if self.brctlcmd.bridge_exists(ifaceobjrunning.name):
1120 self._query_running_bridge(ifaceobjrunning)
1121 elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name):
1122 self._query_running_bridge_port(ifaceobjrunning)
1123
1124 def _query_bridge_port(self, ifaceobj, ifaceobj_getfunc=None):
1125 """
1126 Example:
1127 Configuration:
1128 auto vxlan1wd
1129 iface vxlan1wd
1130 vxlan-id 1001
1131
1132 auto vxlan2wd
1133 iface vxlan2wd
1134 vxlan-id 1002
1135
1136 auto brwithdef2
1137 iface brwithdef2
1138 bridge_ports vxlan1wd vxlan2wd
1139 bridge-vlan-aware yes
1140
1141 Output:
1142 $ ifquery vxlan1wd
1143 auto vxlan1wd
1144 iface vxlan1wd
1145 vxlan-id 1001
1146
1147 $ ifquery --with-defaults vxlan1wd
1148 auto vxlan1wd
1149 iface vxlan1wd
1150 vxlan-id 1001
1151 mstpctl-portbpdufilter yes
1152 mstpctl-bpduguard yes
1153 """
1154 masters = ifaceobj.upperifaces
1155 if not masters:
1156 return
1157 try:
1158 for bridge in masters:
1159 bifaceobj = ifaceobj_getfunc(bridge)[0]
1160 if (self._is_bridge(bifaceobj) and
1161 self.set_default_mstp_vxlan_bridge_config and
1162 (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
1163 for attr in ('mstpctl-portbpdufilter',
1164 'mstpctl-bpduguard',
1165 'mstpctl-portadminedge'):
1166 jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
1167 config_val = ifaceobj.get_attr_value_first(attr)
1168 if config_val or not ifupdownflags.flags.WITHDEFAULTS:
1169 continue
1170 config_val = 'yes'
1171 ifaceobj.replace_config(attr, config_val)
1172 return
1173 except Exception, e:
1174 self.logger.info("%s: %s" %(ifaceobj.name, str(e)))
1175 pass
1176
1177 def _query(self, ifaceobj, ifaceobj_getfunc=None, **kwargs):
1178 """ add default policy attributes supported by the module """
1179 if not self._is_bridge(ifaceobj):
1180 if (ifaceobj.module_flags.get(self.name,0x0) &
1181 mstpctlFlags.PORT_PROCESSED):
1182 return
1183 self._query_bridge_port(ifaceobj, ifaceobj_getfunc)
1184 ifaceobj.module_flags[self.name] = (
1185 ifaceobj.module_flags.setdefault(self.name,0) |
1186 mstpctlFlags.PORT_PROCESSED)
1187 return
1188 lowerinfs = ifaceobj.lowerifaces
1189 if not lowerinfs:
1190 return
1191 if ifaceobj.get_attr_value_first('bridge-vlan-aware') != 'yes':
1192 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1193 state = ''
1194 config = ifaceobj.get_attr_value_first(attr)
1195 for port in lowerinfs:
1196 bportobjlist = ifaceobj_getfunc(port)
1197 for bportobj in bportobjlist:
1198 if bportobj.get_attr_value_first('vxlan-id'):
1199 if config:
1200 if port not in [v.split('=')[0] for v in config.split()]:
1201 config += ' %s=yes' %port
1202 else:
1203 state += '%s=yes ' %port
1204 ifaceobj.replace_config(attr, config if config else state)
1205 else:
1206 for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
1207 state = ''
1208 config = ifaceobj.get_attr_value_first(attr)
1209 for port in lowerinfs:
1210 bportobjlist = ifaceobj_getfunc(port)
1211 for bportobj in bportobjlist:
1212 if (bportobj.module_flags.get(self.name,0x0) &
1213 mstpctlFlags.PORT_PROCESSED):
1214 continue
1215 if bportobj.get_attr_value_first('vxlan-id'):
1216 if config:
1217 if port not in [v.split('=')[0] for v in config.split()]:
1218 bportobj.update_config(attr, 'yes')
1219 else:
1220 index = [v.split('=')[0] for v in config.split()].index(port)
1221 state = [v.split('=')[1] for v in config.split()][index]
1222 bportobj.update_config(attr, '%s' %state)
1223 v = config.split()
1224 del v[index]
1225 config = ' '.join(v)
1226 else:
1227 bportobj.replace_config(attr, 'yes')
1228 bportobj.module_flags[self.name] = (
1229 bportobj.module_flags.setdefault(self.name,0) |
1230 mstpctlFlags.PORT_PROCESSED)
1231 if config:
1232 ifaceobj.replace_config(attr, config)
1233
1234
1235
1236 _run_ops = {'pre-up' : _up,
1237 'post-down' : _down,
1238 'query-checkcurr' : _query_check,
1239 'query-running' : _query_running,
1240 'query' : _query}
1241
1242 def get_ops(self):
1243 """ returns list of ops supported by this module """
1244 return self._run_ops.keys()
1245
1246 def _init_command_handlers(self):
1247 if not self.ipcmd:
1248 self.ipcmd = self.brctlcmd = LinkUtils()
1249 if not self.mstpctlcmd:
1250 self.mstpctlcmd = mstpctlutil()
1251
1252 def run(self, ifaceobj, operation, query_ifaceobj=None,
1253 ifaceobj_getfunc=None, **extra_args):
1254 """ run mstp configuration on the interface object passed as argument
1255
1256 Args:
1257 **ifaceobj** (object): iface object
1258
1259 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1260 'query-running'
1261 Kwargs:
1262 **query_ifaceobj** (object): query check ifaceobject. This is only
1263 valid when op is 'query-checkcurr'. It is an object same as
1264 ifaceobj, but contains running attribute values and its config
1265 status. The modules can use it to return queried running state
1266 of interfaces. status is success if the running state is same
1267 as user required state in ifaceobj. error otherwise.
1268 """
1269 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1270 return
1271 op_handler = self._run_ops.get(operation)
1272 if not op_handler:
1273 return
1274 self._init_command_handlers()
1275 if operation == 'query-checkcurr':
1276 op_handler(self, ifaceobj, query_ifaceobj,
1277 ifaceobj_getfunc=ifaceobj_getfunc)
1278 else:
1279 op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)