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