diff --git a/addons/mstpctl.py b/addons/mstpctl.py index 7a640f8..4501b3e 100644 --- a/addons/mstpctl.py +++ b/addons/mstpctl.py @@ -13,6 +13,7 @@ from ifupdownaddons.iproute2 import iproute2 from ifupdownaddons.mstpctlutil import mstpctlutil from ifupdownaddons.systemutils import systemUtils import ifupdown.ifupdownflags as ifupdownflags +import ifupdown.policymanager as policymanager class mstpctlFlags: PORT_PROCESSED = 0x1 @@ -187,6 +188,11 @@ class mstpctl(moduleBase): self.mstpctlcmd = None self.mstpd_running = (True if systemUtils.is_process_running('mstpd') else False) + self.default_vxlan_ports_set_bpduparams = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='mstpctl-vxlan-always-set-bpdu-params') + if self.default_vxlan_ports_set_bpduparams == 'yes': + self.default_vxlan_ports_set_bpduparams = True + else: + self.default_vxlan_ports_set_bpduparams = False def _is_bridge(self, ifaceobj): if (ifaceobj.get_attr_value_first('mstpctl-ports') or @@ -336,6 +342,26 @@ class mstpctl(moduleBase): self.log_warn(str(e)) pass + def _get_default_val(self, attr, ifaceobj, bridgeifaceobj): + if ((attr == 'mstpctl-portbpdufilter' or + attr == 'mstpctl-bpduguard') and + self.default_vxlan_ports_set_bpduparams and + (ifaceobj.link_kind & ifaceLinkKind.VXLAN)): + try: + config_val = bridgeifaceobj.get_attr_value_first(attr) + except Exception, e: + config_val = None + if config_val: + if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]: + return 'yes' + else: + index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name) + return [v.split('=')[1] for v in config_val.split()][index] + else: + return 'yes' + else: + return self.get_mod_subattr(attr,'default') + def _apply_bridge_port_settings(self, ifaceobj, bridgename=None, bridgeifaceobj=None, stp_running_on=True, @@ -351,15 +377,29 @@ class mstpctl(moduleBase): %(ifaceobj.name) + ' (stp on bridge %s is not on yet)' %bridgename) return applied + bvlan_aware = self.ipcmd.bridge_is_vlan_aware(bridgename) if (not mstpd_running or not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or - not self.ipcmd.bridge_is_vlan_aware(bridgename)): - return applied + not bvlan_aware): + if (not bvlan_aware and + self.default_vxlan_ports_set_bpduparams and + (ifaceobj.link_kind & ifaceLinkKind.VXLAN)): + for attr in ['mstpctl-portbpdufilter', + 'mstpctl-bpduguard']: + config_val = self._get_default_val(attr, ifaceobj, bridgeifaceobj) + try: + self.mstpctlcmd.set_bridgeport_attr(bridgename, + ifaceobj.name, self._port_attrs_map[attr], + config_val, check) + except Exception, e: + self.log_warn('%s: error setting %s (%s)' + %(ifaceobj.name, attr, str(e))) + return applied # set bridge port attributes for attrname, dstattrname in self._port_attrs_map.items(): attrval = ifaceobj.get_attr_value_first(attrname) config_val = ifaceobj.get_attr_value_first(attrname) - default_val = self.get_mod_subattr(attrname,'default') + default_val = self._get_default_val(attrname, ifaceobj, bridgeifaceobj) jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr') # to see the running value, stp would have to be on # so we would have parsed mstpctl showportdetail json output @@ -413,9 +453,10 @@ class mstpctl(moduleBase): mstpctlFlags.PORT_PROCESSED): continue try: - self._apply_bridge_port_settings(bportifaceobj, + self._apply_bridge_port_settings(bportifaceobj, ifaceobj.name, ifaceobj) except Exception, e: + pass self.log_warn(str(e)) def _is_running_userspace_stp_state_on(self, bridgename): @@ -584,7 +625,8 @@ class mstpctl(moduleBase): if v}) return bridgeattrdict - def _query_check_bridge(self, ifaceobj, ifaceobjcurr): + def _query_check_bridge(self, ifaceobj, ifaceobjcurr, + ifaceobj_getfunc=None): # list of attributes that are not supported currently blacklistedattrs = ['mstpctl-portpathcost', 'mstpctl-treeportprio', 'mstpctl-treeportcost'] @@ -593,15 +635,73 @@ class mstpctl(moduleBase): return ifaceattrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs()) + if self.default_vxlan_ports_set_bpduparams: + for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']: + if attr not in ifaceattrs: + ifaceattrs.append(attr) if not ifaceattrs: return runningattrs = self.mstpctlcmd.get_bridge_attrs(ifaceobj.name) if not runningattrs: runningattrs = {} + running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name) for k in ifaceattrs: # for all mstpctl options if k in blacklistedattrs: continue + if ((k == 'mstpctl-portbpdufilter' or + k == 'mstpctl-bpduguard')): + #special case, 'ifquery --check --with-defaults' on a VLAN + #unaware bridge + if not running_port_list: + continue + v = ifaceobj.get_attr_value_first(k) + config_val = {} + running_val = {} + result = 0 + bridge_ports = {} + state = '' + if v: + for bportval in v.split(): + config_val[bportval.split('=')[0]] = bportval.split('=')[1] + #for bport in bridgeports: + for bport in running_port_list: + bportifaceobjlist = ifaceobj_getfunc(bport) + if not bportifaceobjlist: + continue + for bportifaceobj in bportifaceobjlist: + if (bport not in config_val): + if (bportifaceobj.link_kind & ifaceLinkKind.VXLAN): + if (not ifupdownflags.flags.WITHDEFAULTS or + (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)): + continue + conf = 'yes' + else: + continue + else: + if ((bportifaceobj.link_kind & ifaceLinkKind.VXLAN) and + (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)): + continue + conf = config_val[bport] + jsonAttr = self.get_mod_subattr(k, 'jsonAttr') + try: + running_val = self.mstpctlcmd.get_mstpctl_bridgeport_attr(ifaceobj.name, bport, jsonAttr) + except: + self.logger.info('%s %s: could not get running %s value' + %(ifaceobj.name, bport, attr)) + running_val = None + if conf != running_val: + result = 1 + bridge_ports.update({bport : running_val}) + for port, val in bridge_ports.items(): + #running state format + #mstpctl-portbpdufilter swp2=yes swp1=yes vx-14567101=yes [pass] + #mstpctl-bpduguard swp2=yes swp1=yes vx-14567101=yes [pass] + state += port + '=' + val + ' ' + if state: + ifaceobjcurr.update_config_with_status(k, state, result) + continue + # get the corresponding ifaceobj attr v = ifaceobj.get_attr_value_first(k) if not v: @@ -626,7 +726,6 @@ class mstpctl(moduleBase): # special case ports because it can contain regex or glob # XXX: We get all info from mstputils, which means if # mstpd is down, we will not be returning any bridge bridgeports - running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name) bridge_port_list = self._get_bridge_port_list(ifaceobj) if not running_port_list and not bridge_port_list: continue @@ -674,6 +773,46 @@ class mstpctl(moduleBase): else: ifaceobjcurr.update_config_with_status(k, rv, 0) + def _query_check_bridge_vxlan_port(self, ifaceobj, ifaceobjcurr, + ifaceobj_getfunc=None): + masters = ifaceobj.upperifaces + if not masters: + return + for bridge in masters: + bifaceobjlist = ifaceobj_getfunc(bridge) + for bifaceobj in bifaceobjlist: + if (self._is_bridge(bifaceobj) and + self.default_vxlan_ports_set_bpduparams and + (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)): + for attr in ['mstpctl-portbpdufilter', + 'mstpctl-bpduguard']: + jsonAttr = self.get_mod_subattr(attr, 'jsonAttr') + config_val = bifaceobj.get_attr_value_first(attr) + if config_val: + if ifaceobj.name not in [v.split('=')[0] for v in config_val.split()]: + if not ifupdownflags.flags.WITHDEFAULTS: + continue + config_val = 'yes' + else: + index = [v.split('=')[0] for v in config_val.split()].index(ifaceobj.name) + config_val = [v.split('=')[1] for v in config_val.split()][index] + else: + if not ifupdownflags.flags.WITHDEFAULTS: + continue + config_val = 'yes' + try: + running_val = self.mstpctlcmd.get_mstpctl_bridgeport_attr(bifaceobj.name, + ifaceobj.name, jsonAttr) + except: + self.logger.info('%s %s: could not get running %s value' + %(bifaceobj.name, ifaceobj.name, attr)) + running_val = None + ifaceobjcurr.update_config_with_status(attr, + running_val, + 0 if running_val == config_val else 1) + return + + def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr): if not self.ipcmd.link_exists(ifaceobj.name): #self.logger.debug('bridge port %s does not exist' %ifaceobj.name) @@ -715,7 +854,10 @@ class mstpctl(moduleBase): def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): if self._is_bridge(ifaceobj): - self._query_check_bridge(ifaceobj, ifaceobjcurr) + self._query_check_bridge(ifaceobj, ifaceobjcurr, ifaceobj_getfunc) + elif ifaceobj.link_kind & ifaceLinkKind.VXLAN: + self._query_check_bridge_vxlan_port(ifaceobj, ifaceobjcurr, + ifaceobj_getfunc) else: self._query_check_bridge_port(ifaceobj, ifaceobjcurr) @@ -801,10 +943,59 @@ class mstpctl(moduleBase): elif self.brctlcmd.is_bridge_port(ifaceobjrunning.name): self._query_running_bridge_port(ifaceobjrunning) + def _query(self, ifaceobj, ifaceobj_getfunc=None, **kwargs): + """ add default policy attributes supported by the module """ + if not self._is_bridge(ifaceobj): + return + lowerinfs = ifaceobj.lowerifaces + if not lowerinfs: + return + if ifaceobj.get_attr_value_first('bridge-vlan-aware') != 'yes': + for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']: + state = '' + config = ifaceobj.get_attr_value_first(attr) + for port in lowerinfs: + bportobjlist = ifaceobj_getfunc(port) + for bportobj in bportobjlist: + if bportobj.get_attr_value_first('vxlan-id'): + if config: + if port not in [v.split('=')[0] for v in config.split()]: + config += ' %s=yes' %port + else: + state += '%s=yes ' %port + ifaceobj.replace_config(attr, config if config else state) + else: + for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']: + state = '' + config = ifaceobj.get_attr_value_first(attr) + for port in lowerinfs: + bportobjlist = ifaceobj_getfunc(port) + for bportobj in bportobjlist: + if bportobj.get_attr_value_first('vxlan-id'): + if config: + if port not in [v.split('=')[0] for v in config.split()]: + bportobj.update_config(attr, 'yes') + else: + index = [v.split('=')[0] for v in config.split()].index(port) + state = [v.split('=')[1] for v in config.split()][index] + bportobj.update_config(attr, '%s' %state) + v = config.split() + del v[index] + config = ' '.join(v) + else: + bportobj.update_config(attr, 'yes') + if config: + ifaceobj.replace_config(attr, config) + else: + ifaceobj.replace_config(attr, '') + + + _run_ops = {'pre-up' : _up, 'post-down' : _down, 'query-checkcurr' : _query_check, - 'query-running' : _query_running} + 'query-running' : _query_running, + 'query' : _query} def get_ops(self): """ returns list of ops supported by this module """ diff --git a/ifupdownaddons/mstpctlutil.py b/ifupdownaddons/mstpctlutil.py index 0cc812c..694439c 100644 --- a/ifupdownaddons/mstpctlutil.py +++ b/ifupdownaddons/mstpctlutil.py @@ -111,7 +111,7 @@ class mstpctlutil(utilsBase): if not v: continue try: - self.set_bridgeport_attr(self, bridgename, bridgeportname, + self.set_bridgeport_attr(bridgename, bridgeportname, k, v, check) except Exception, e: self.logger.warn(str(e))