diff --git a/addons/bond.py b/addons/bond.py index e6f60b0..9a13a6e 100644 --- a/addons/bond.py +++ b/addons/bond.py @@ -105,7 +105,16 @@ class bond(moduleBase): 'example' : ['bond-slaves swp1 swp2', 'bond-slaves glob swp1-2', 'bond-slaves regex (swp[1|2)'], - 'aliases': ['bond-ports']}}} + 'aliases': ['bond-ports']}, + 'bond-updelay' : + {'help' : 'bond updelay', + 'default' : '0', + 'example' : ['bond-updelay 100']}, + 'bond-downdelay': + {'help' : 'bond downdelay', + 'default' : '0', + 'example' : ['bond-downdelay 100']} + }} _bond_mode_num = {'0': 'balance-rr', '1': 'active-backup', @@ -231,7 +240,9 @@ class bond(moduleBase): ('bond-ad-actor-system' , 'ad_actor_system'), ('bond-ad-sys-priority' , 'ad_actor_sys_prio'), ('bond-ad-actor-sys-prio' , 'ad_actor_sys_prio'), - ('bond-lacp-bypass-allow', 'lacp_bypass')]) + ('bond-lacp-bypass-allow', 'lacp_bypass'), + ('bond-updelay', 'updelay'), + ('bond-downdelay', 'downdelay')]) linkup = self.ipcmd.is_link_up(ifaceobj.name) try: # order of attributes set matters for bond, so @@ -408,7 +419,11 @@ class bond(moduleBase): 'bond-num-unsol-na' : self.bondcmd.get_num_unsol_na(bondname), 'bond-num-grat-arp' : - self.bondcmd.get_num_grat_arp(bondname)} + self.bondcmd.get_num_grat_arp(bondname), + 'bond-updelay' : + self.bondcmd.get_updelay(bondname), + 'bond-downdelay' : + self.bondcmd.get_downdelay(bondname)} slaves = self.bondcmd.get_slaves(bondname) if slaves: bondattrs['bond-slaves'] = slaves diff --git a/addons/mstpctl.py b/addons/mstpctl.py index 54f659d..0cfb70f 100644 --- a/addons/mstpctl.py +++ b/addons/mstpctl.py @@ -144,7 +144,7 @@ class mstpctl(moduleBase): 'validrange' : ['0', '255'], 'default' : '2', 'required' : False, - 'jsonAttr': 'portHelloTime', + 'jsonAttr': 'helloTime', 'example' : ['mstpctl-hello 2']}, 'mstpctl-portnetwork' : { 'help' : 'enable/disable bridge assurance capability for a port', @@ -329,16 +329,32 @@ class mstpctl(moduleBase): try: # set bridge attributes for attrname, dstattrname in self._attrs_map.items(): + config_val = ifaceobj.get_attr_value_first(attrname) + default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attrname) + if not default_val: + default_val = self.get_mod_subattr(attrname,'default') + jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr') + try: + running_val = self.mstpctlcmd.get_bridge_attr( + ifaceobj.name, jsonAttr) + except: + self.logger.info('%s: could not get running %s value' + %(ifaceobj.name, attrname)) + running_val = None + if (not config_val and default_val and (running_val != default_val)): + # this happens when users remove an attribute from a port + # and expect the default to be restored with ifreload. + config_val = default_val + elif not config_val: + # there is nothing configured and no default to reset + continue try: - v = ifaceobj.get_attr_value_first(attrname) - if not v: - continue if attrname == 'mstpctl-treeprio': self.mstpctlcmd.set_bridge_treeprio(ifaceobj.name, - v, check) + config_val, check) else: self.mstpctlcmd.set_bridge_attr(ifaceobj.name, - dstattrname, v, check) + dstattrname, config_val, check) except Exception, e: self.logger.warn('%s' %str(e)) pass @@ -415,7 +431,10 @@ class mstpctl(moduleBase): else: return 'yes' else: - return self.get_mod_subattr(attr,'default') + default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attr) + if not default_val: + return self.get_mod_subattr(attr,'default') + return default_val def _apply_bridge_port_settings(self, ifaceobj, bridgename=None, bridgeifaceobj=None, @@ -660,6 +679,18 @@ class mstpctl(moduleBase): if v}) return bridgeattrdict + def _get_config_stp(self, ifaceobj): + stp = (ifaceobj.get_attr_value_first('mstpctl-stp') or + ifaceobj.get_attr_value_first('bridge-stp') or + policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr='mstpctl-stp') or + # this is a temporary method to access policy default value of bridge-stp + policymanager.policymanager_api.get_iface_default(module_name='bridge', ifname=ifaceobj.name, attr='bridge-stp')) + return utils.get_boolean_from_string(stp) + + def _get_running_stp(self, ifaceobj): + stp = self.brctlcmd.get_stp(ifaceobj.name) + return utils.get_boolean_from_string(stp) + def _query_check_bridge(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None): # list of attributes that are not supported currently @@ -680,6 +711,8 @@ class mstpctl(moduleBase): #self.logger.info('B' + str(runningattrs)) if not runningattrs: runningattrs = {} + config_stp = self._get_config_stp(ifaceobj) + running_stp = self._get_running_stp(ifaceobj) running_port_list = self.brctlcmd.get_bridge_ports(ifaceobj.name) for k in ifaceattrs: # for all mstpctl options @@ -691,6 +724,8 @@ class mstpctl(moduleBase): #unaware bridge if not running_port_list: continue + if (not config_stp or not running_stp): + continue v = ifaceobj.get_attr_value_first(k) config_val = {} running_val = {} @@ -819,6 +854,10 @@ class mstpctl(moduleBase): if (self._is_bridge(bifaceobj) and self.default_vxlan_ports_set_bpduparams and (bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)): + config_stp = self._get_config_stp(bifaceobj) + running_stp = self._get_running_stp(bifaceobj) + if (not config_stp or not running_stp): + continue for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']: jsonAttr = self.get_mod_subattr(attr, 'jsonAttr') diff --git a/debian/ifupdown2.postinst b/debian/ifupdown2.postinst index fa40daf..19365db 100644 --- a/debian/ifupdown2.postinst +++ b/debian/ifupdown2.postinst @@ -56,7 +56,7 @@ case "$1" in # Generic stuff done on all configurations if [ -f /etc/network/interfaces ] ; then - if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo0\?[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then + if ! grep -q -E "^[[:space:]]*iface[[:space:]]+l[o0]([[:space:]]+inet([[:space:]]+loopback)?)?[[:space:]]*$" /etc/network/interfaces ; then report_warn "No 'iface lo' definition found in /etc/network/interfaces" fi diff --git a/ifupdown/policymanager.py b/ifupdown/policymanager.py index b5f3123..c624c18 100644 --- a/ifupdown/policymanager.py +++ b/ifupdown/policymanager.py @@ -210,4 +210,5 @@ class policymanager(): return mod_array + policymanager_api = policymanager() diff --git a/ifupdownaddons/bondutil.py b/ifupdownaddons/bondutil.py index 366adfa..03287e5 100644 --- a/ifupdownaddons/bondutil.py +++ b/ifupdownaddons/bondutil.py @@ -31,36 +31,76 @@ class bondutil(utilsBase): except: linkCache.links[bondname] = {'linkinfo': {}} + try: + linkCache.set_attr([bondname, 'linkinfo', 'min_links'], + self.read_file_oneline( + '/sys/class/net/%s/bonding/min_links' + % bondname)) + except Exception as e: + self.logger.debug(str(e)) try: linkCache.set_attr([bondname, 'linkinfo', 'slaves'], self.read_file_oneline('/sys/class/net/%s/bonding/slaves' %bondname).split()) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'mode'], self.read_file_oneline('/sys/class/net/%s/bonding/mode' %bondname).split()[0]) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'xmit_hash_policy'], self.read_file_oneline( '/sys/class/net/%s/bonding/xmit_hash_policy' %bondname).split()[0]) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'lacp_rate'], self.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate' %bondname).split()[1]) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'ad_actor_sys_prio'], self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio' %bondname)) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'ad_actor_system'], self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system' %bondname)) + except Exception as e: + self.logger.debug(str(e)) + try: linkCache.set_attr([bondname, 'linkinfo', 'lacp_bypass'], self.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass' %bondname).split()[1]) + except Exception as e: + self.logger.debug(str(e)) + try: + linkCache.set_attr([bondname, 'linkinfo', 'updelay'], + self.read_file_oneline('/sys/class/net/%s/bonding/updelay' + %bondname)) + except Exception as e: + self.logger.debug(str(e)) + try: + linkCache.set_attr([bondname, 'linkinfo', 'downdelay'], + self.read_file_oneline('/sys/class/net/%s/bonding/downdelay' + %bondname)) + except Exception as e: + self.logger.debug(str(e)) + try: map(lambda x: linkCache.set_attr([bondname, 'linkinfo', x], self.read_file_oneline('/sys/class/net/%s/bonding/%s' %(bondname, x))), ['use_carrier', 'miimon', 'min_links', 'num_unsol_na', 'num_grat_arp']) - except Exception, e: - pass + except Exception as e: + self.logger.debug(str(e)) def _bond_linkinfo_fill_all(self): bondstr = self.read_file_oneline('/sys/class/net/bonding_masters') @@ -285,6 +325,12 @@ class bondutil(utilsBase): def get_num_grat_arp(self, bondname): return self._cache_get([bondname, 'linkinfo', 'num_grat_arp']) + def get_updelay(self, bondname): + return self._cache_get([bondname, 'linkinfo', 'updelay']) + + def get_downdelay(self, bondname): + return self._cache_get([bondname, 'linkinfo', 'downdelay']) + def enslave_slave(self, bondname, slave, prehook=None, posthook=None): slaves = self._cache_get([bondname, 'linkinfo', 'slaves']) if slaves and slave in slaves: return diff --git a/ifupdownaddons/mstpctlutil.py b/ifupdownaddons/mstpctlutil.py index 1b069b5..1452bd4 100644 --- a/ifupdownaddons/mstpctlutil.py +++ b/ifupdownaddons/mstpctlutil.py @@ -28,6 +28,17 @@ class mstpctlutil(utilsBase): 'hello' : 'hello-time', 'forcevers' : 'force-protocol-version'} + _bridge_jsonAttr_map = { + 'treeprio': 'bridgeId', + 'maxage': 'maxAge', + 'fdelay': 'fwdDelay', + 'txholdcount': 'txHoldCounter', + 'maxhops': 'maxHops', + 'ageing': 'ageingTime', + 'hello': 'helloTime', + 'forcevers': 'forceProtocolVersion', + } + _bridgeportattrmap = {'portadminedge' : 'admin-edge-port', 'portp2p' : 'admin-point-to-point', 'portrestrrole' : 'restricted-role', @@ -56,7 +67,7 @@ class mstpctlutil(utilsBase): except: return mstpctlutil._DEFAULT_PORT_PRIO - def _get_bridge_port_attrs_from_cache(self, bridgename): + def _get_bridge_and_port_attrs_from_cache(self, bridgename): attrs = MSTPAttrsCache.get(bridgename) if attrs: return attrs @@ -81,19 +92,41 @@ class mstpctlutil(utilsBase): MSTPAttrsCache.set(bridgename, mstpctl_bridgeport_attrs_dict) except Exception as e: self.logger.info('%s: cannot fetch mstpctl bridge port attributes: %s' % str(e)) - return mstpctl_bridgeport_attrs_dict + + mstpctl_bridge_attrs_dict = {} + try: + cmd = ['/sbin/mstpctl', 'showbridge', 'json', bridgename] + output = utils.exec_commandl(cmd) + if not output: + return mstpctl_bridge_attrs_dict + except Exception as e: + self.logger.info(str(e)) + return mstpctl_bridge_attrs_dict + try: + mstpctl_bridge_cache = json.loads(output.strip('\n')) + for jsonAttr in mstpctl_bridge_cache[bridgename].keys(): + mstpctl_bridge_attrs_dict[jsonAttr] = ( + str(mstpctl_bridge_cache[bridgename][jsonAttr])) + mstpctl_bridge_attrs_dict['treeprio'] = '%d' %( + int(mstpctl_bridge_attrs_dict.get('bridgeId', + '').split('.')[0], base=16) * 4096) + del mstpctl_bridge_attrs_dict['bridgeId'] + MSTPAttrsCache.bridges[bridgename].update(mstpctl_bridge_attrs_dict) + except Exception as e: + self.logger.info('%s: cannot fetch mstpctl bridge attributes: %s' % str(e)) + return MSTPAttrsCache.get(bridgename) def get_bridge_ports_attrs(self, bridgename): - return self._get_bridge_port_attrs_from_cache(bridgename) + return self._get_bridge_and_port_attrs_from_cache(bridgename) def get_bridge_port_attr(self, bridgename, portname, attrname): - attrs = self._get_bridge_port_attrs_from_cache(bridgename) + attrs = self._get_bridge_and_port_attrs_from_cache(bridgename) value = attrs.get(portname, {}).get(attrname, 'no') if value == 'True' or value == 'true': return 'yes' return str(value) - def update_cache(self, bridgename, portname, attrname, value): + def update_bridge_port_cache(self, bridgename, portname, attrname, value): attrs = self.get_bridge_ports_attrs(bridgename) if not attrs: attrs = {} @@ -102,6 +135,13 @@ class mstpctlutil(utilsBase): attrs[portname][attrname] = value MSTPAttrsCache.set(bridgename, attrs) + def update_bridge_cache(self, bridgename, attrname, value): + attrs = self.get_bridge_ports_attrs(bridgename) + if not attrs: + attrs = {} + attrs[attrname] = value + MSTPAttrsCache.set(bridgename, attrs) + def set_bridge_port_attr(self, bridgename, portname, attrname, value, json_attr=None): cache_value = self.get_bridge_port_attr(bridgename, portname, json_attr) if cache_value and cache_value == value: @@ -113,16 +153,13 @@ class mstpctlutil(utilsBase): utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, bridgename, portname, value]) if json_attr: - self.update_cache(bridgename, portname, json_attr, value) + self.update_bridge_port_cache(bridgename, portname, json_attr, value) def get_bridge_attrs(self, bridgename): bridgeattrs = {} try: - bridgeattrs = dict((k, self.get_bridge_attr(bridgename, k)) - for k in self._bridgeattrmap.keys()) - bridgeattrs['treeprio'] = '%d' %(int(bridgeattrs.get('bridgeid', - '').split('.')[0], base=16) * 4096) - del bridgeattrs['bridgeid'] + bridgeattrs = dict((k, self.get_bridge_attr(bridgename, v)) + for k,v in self._bridge_jsonAttr_map.items()) except Exception, e: self.logger.debug(bridgeattrs) self.logger.debug(str(e)) @@ -130,28 +167,32 @@ class mstpctlutil(utilsBase): return bridgeattrs def get_bridge_attr(self, bridgename, attrname): - try: - cmdl = ['/sbin/mstpctl', 'showbridge', bridgename, - self._bridgeattrmap[attrname]] - return utils.exec_commandl(cmdl).strip('\n') - except Exception, e: - pass - return None + if attrname == 'bridgeId': + attrname = 'treeprio' + return self._get_bridge_and_port_attrs_from_cache(bridgename).get(attrname) def set_bridge_attr(self, bridgename, attrname, attrvalue, check=True): if check: - attrvalue_curr = self.get_bridge_attr(bridgename, attrname) + if attrname == 'treeprio': + attrvalue_curr = self.get_bridge_attr(bridgename, attrname) + else: + attrvalue_curr = self.get_bridge_attr(bridgename, + self._bridge_jsonAttr_map[attrname]) if attrvalue_curr and attrvalue_curr == attrvalue: return if attrname == 'treeprio': utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, '%s' % bridgename, '0', '%s' % attrvalue], stdout=False, stderr=None) + self.update_bridge_cache(bridgename, attrname, str(attrvalue)) else: utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname, '%s' % bridgename, '%s' % attrvalue], stdout=False, stderr=None) + self.update_bridge_cache(bridgename, + self._bridge_jsonAttr_map[attrname], + str(attrvalue)) def set_bridge_attrs(self, bridgename, attrdict, check=True): for k, v in attrdict.iteritems(): @@ -163,17 +204,7 @@ class mstpctlutil(utilsBase): self.logger.warn('%s: %s' %(bridgename, str(e))) def get_bridge_treeprio(self, bridgename): - try: - cmdl = ['/sbin/mstpctl', - 'showbridge', - bridgename, - self._bridgeattrmap['bridgeid']] - - bridgeid = utils.exec_commandl(cmdl).strip('\n') - return '%d' %(int(bridgeid.split('.')[0], base=16) * 4096) - except: - pass - return None + return self.get_bridge_attr(bridgename, 'treeprio') def set_bridge_treeprio(self, bridgename, attrvalue, check=True): if check: @@ -182,6 +213,7 @@ class mstpctlutil(utilsBase): return utils.exec_commandl(['/sbin/mstpctl', 'settreeprio', bridgename, '0', str(attrvalue)]) + self.update_bridge_cache(bridgename, 'treeprio', str(attrvalue)) def showbridge(self, bridgename=None): if bridgename: