mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			506 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			506 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python3
 | 
						|
#
 | 
						|
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
 | 
						|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
 | 
						|
#
 | 
						|
 | 
						|
import os
 | 
						|
import re
 | 
						|
import logging
 | 
						|
import traceback
 | 
						|
from functools import reduce
 | 
						|
 | 
						|
try:
 | 
						|
    from ifupdown2.ifupdown.iface import *
 | 
						|
    from ifupdown2.ifupdown.utils import utils
 | 
						|
 | 
						|
    import ifupdown2.ifupdown.exceptions as exceptions
 | 
						|
    import ifupdown2.ifupdown.policymanager as policymanager
 | 
						|
    import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
 | 
						|
except (ImportError, ModuleNotFoundError):
 | 
						|
    from ifupdown.iface import *
 | 
						|
    from ifupdown.utils import utils
 | 
						|
 | 
						|
    import ifupdown.exceptions as exceptions
 | 
						|
    import ifupdown.policymanager as policymanager
 | 
						|
    import ifupdown.ifupdownflags as ifupdownflags
 | 
						|
 | 
						|
 | 
						|
class NotSupported(Exception):
 | 
						|
    pass
 | 
						|
 | 
						|
class moduleBase(object):
 | 
						|
    """ Base class for ifupdown addon modules
 | 
						|
 | 
						|
    Provides common infrastructure methods for all addon modules """
 | 
						|
 | 
						|
    def __init__(self, *args, **kargs):
 | 
						|
        self.modulename = self.__class__.__name__
 | 
						|
        self.logger = logging.getLogger('ifupdown.' + self.modulename)
 | 
						|
 | 
						|
        # vrfs are a global concept and a vrf context can be applicable
 | 
						|
        # to all global vrf commands. Get the default vrf-exec-cmd-prefix
 | 
						|
        # here so that all modules can use it
 | 
						|
        self.vrf_exec_cmd_prefix = policymanager.policymanager_api.get_module_globals('vrf', attr='vrf-exec-cmd-prefix')
 | 
						|
 | 
						|
        # explanations are shown in parse_glob
 | 
						|
        self.glob_regexs = [re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\]([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)"),
 | 
						|
                            re.compile(r"([A-Za-z0-9\-]+[A-Za-z])(\d+)\-(\d+)(.*)"),
 | 
						|
                            re.compile(r"([A-Za-z0-9\-]+)\[(\d+)\-(\d+)\](.*)")]
 | 
						|
 | 
						|
        self._bridge_stp_user_space = None
 | 
						|
 | 
						|
        self.merge_modinfo_with_policy_files()
 | 
						|
 | 
						|
    def merge_modinfo_with_policy_files(self):
 | 
						|
        """
 | 
						|
            update addons modinfo dictionary with system/user defined values in policy files
 | 
						|
            Any value can be updated except the module help "mhelp"
 | 
						|
 | 
						|
            We also check if the policy attributes really exist to make sure someone is not
 | 
						|
            trying to "inject" new attributes to prevent breakages and security issue
 | 
						|
        """
 | 
						|
        attrs = dict(self.get_modinfo().get('attrs', {}))
 | 
						|
 | 
						|
        if not attrs:
 | 
						|
            return
 | 
						|
 | 
						|
        error_msg = 'this attribute doesn\'t exist or isn\'t supported'
 | 
						|
 | 
						|
        # first check module_defaults
 | 
						|
        for key, value in list(policymanager.policymanager_api.get_module_defaults(self.modulename).items()):
 | 
						|
            if not key in attrs:
 | 
						|
                self.logger.warning('%s: %s: %s' % (self.modulename, key, error_msg))
 | 
						|
                continue
 | 
						|
            attrs[key]['default'] = value
 | 
						|
 | 
						|
        # then check module_globals (overrides module_defaults)
 | 
						|
        policy_modinfo = policymanager.policymanager_api.get_module_globals(self.modulename, '_modinfo')
 | 
						|
        if policy_modinfo:
 | 
						|
            policy_attrs = policy_modinfo.get('attrs', {})
 | 
						|
            update_attrs = dict()
 | 
						|
 | 
						|
            for attr_name, attr_description in list(policy_attrs.items()):
 | 
						|
                if attr_name not in attrs:
 | 
						|
                    self.logger.warning('%s: %s: %s' % (self.modulename, attr_name, error_msg))
 | 
						|
                else:
 | 
						|
                    update_attrs[attr_name] = attr_description
 | 
						|
 | 
						|
            attrs.update(update_attrs)
 | 
						|
 | 
						|
        return attrs
 | 
						|
 | 
						|
    def log_warn(self, str, ifaceobj=None):
 | 
						|
        """ log a warning if err str is not one of which we should ignore """
 | 
						|
        if not self.ignore_error(str) and not ifupdownflags.flags.IGNORE_ERRORS:
 | 
						|
            if self.logger.getEffectiveLevel() == logging.DEBUG:
 | 
						|
                traceback.print_stack()
 | 
						|
                traceback.print_exc()
 | 
						|
            self.logger.warning(str)
 | 
						|
            if ifaceobj:
 | 
						|
                ifaceobj.set_status(ifaceStatus.WARNING)
 | 
						|
        pass
 | 
						|
 | 
						|
    def log_error(self, str, ifaceobj=None, raise_error=True):
 | 
						|
        """ log an err if err str is not one of which we should ignore and raise an exception """
 | 
						|
        if not self.ignore_error(str) and not ifupdownflags.flags.IGNORE_ERRORS:
 | 
						|
            if self.logger.getEffectiveLevel() == logging.DEBUG:
 | 
						|
                traceback.print_stack()
 | 
						|
                traceback.print_exc()
 | 
						|
            if raise_error:
 | 
						|
                if ifaceobj:
 | 
						|
                    ifaceobj.set_status(ifaceStatus.ERROR)
 | 
						|
                raise Exception(str)
 | 
						|
            else:
 | 
						|
                self.logger.error(str)
 | 
						|
        else:
 | 
						|
            pass
 | 
						|
 | 
						|
    def is_process_running(self, procName):
 | 
						|
        try:
 | 
						|
            utils.exec_command('%s -x %s' %
 | 
						|
                               (utils.pidof_cmd, procName))
 | 
						|
        except Exception:
 | 
						|
            return False
 | 
						|
        else:
 | 
						|
            return True
 | 
						|
 | 
						|
    def get_ifaces_from_proc(self):
 | 
						|
        ifacenames = []
 | 
						|
        with open('/proc/net/dev') as f:
 | 
						|
            try:
 | 
						|
                lines = f.readlines()
 | 
						|
                for line in lines[2:]:
 | 
						|
                    ifacenames.append(line.split()[0].strip(': '))
 | 
						|
            except Exception:
 | 
						|
                raise
 | 
						|
        return ifacenames
 | 
						|
 | 
						|
    def parse_regex(self, ifacename, expr, ifacenames=None):
 | 
						|
        try:
 | 
						|
            proc_ifacenames = self.get_ifaces_from_proc()
 | 
						|
        except Exception:
 | 
						|
            self.logger.warning('%s: error reading ifaces from proc' %ifacename)
 | 
						|
 | 
						|
        for proc_ifacename in proc_ifacenames:
 | 
						|
            try:
 | 
						|
                if re.search(expr + '$', proc_ifacename):
 | 
						|
                    yield proc_ifacename
 | 
						|
            except Exception as e:
 | 
						|
                raise Exception('%s: error searching regex \'%s\' in %s (%s)'
 | 
						|
                                %(ifacename, expr, proc_ifacename, str(e)))
 | 
						|
        if not ifacenames:
 | 
						|
            return
 | 
						|
        for ifacename in ifacenames:
 | 
						|
            try:
 | 
						|
                if re.search(expr + '$', ifacename):
 | 
						|
                    yield ifacename
 | 
						|
            except Exception as e:
 | 
						|
                raise Exception('%s: error searching regex \'%s\' in %s (%s)'
 | 
						|
                                %(ifacename, expr, ifacename, str(e)))
 | 
						|
 | 
						|
    def ifname_is_glob(self, ifname):
 | 
						|
        """
 | 
						|
        Used by iface where ifname could be swp7 or swp[1-10].300
 | 
						|
        """
 | 
						|
        if (self.glob_regexs[0].match(ifname) or
 | 
						|
            self.glob_regexs[1].match(ifname) or
 | 
						|
            self.glob_regexs[2].match(ifname)):
 | 
						|
            return True
 | 
						|
        return False
 | 
						|
 | 
						|
    def parse_glob(self, ifacename, expr):
 | 
						|
        errmsg = ('error parsing glob expression \'%s\'' %expr +
 | 
						|
                    ' (supported glob syntax: swp1-10.300 or swp[1-10].300' +
 | 
						|
                    '  or swp[1-10]sub[0-4].300')
 | 
						|
 | 
						|
        if ',' in expr:
 | 
						|
            self.logger.warning('%s: comma are not supported in glob: %s' % (ifacename, errmsg))
 | 
						|
            yield expr
 | 
						|
            return
 | 
						|
 | 
						|
        regexs = self.glob_regexs
 | 
						|
 | 
						|
        if regexs[0].match(expr):
 | 
						|
            # the first regex checks for exactly two levels of ranges defined only with square brackets
 | 
						|
            # (e.g. swpxyz[10-23]subqwe[0-4].100) to handle naming with two levels of port names.
 | 
						|
            m = regexs[0].match(expr)
 | 
						|
            mlist = m.groups()
 | 
						|
            if len(mlist) < 7:
 | 
						|
                # we have problems and should not continue
 | 
						|
                raise Exception('%s: error: unhandled glob expression %s\n%s' % (ifacename, expr,errmsg))
 | 
						|
 | 
						|
            prefix = mlist[0]
 | 
						|
            suffix = mlist[6]
 | 
						|
            start_index = int(mlist[1])
 | 
						|
            end_index = int(mlist[2])
 | 
						|
            sub_string = mlist[3]
 | 
						|
            start_sub = int(mlist[4])
 | 
						|
            end_sub = int(mlist[5])
 | 
						|
            for i in range(start_index, end_index + 1):
 | 
						|
                for j in range(start_sub, end_sub + 1):
 | 
						|
                    yield prefix + '%d%s%d' % (i,sub_string,j) + suffix
 | 
						|
 | 
						|
        elif regexs[1].match(expr) or regexs[2].match(expr):
 | 
						|
            # the second regex for 1 level with a range (e.g. swp10-14.100
 | 
						|
            # the third regex checks for 1 level with [] (e.g. swp[10-14].100)
 | 
						|
            start_index = 0
 | 
						|
            end_index = 0
 | 
						|
            if regexs[1].match(expr):
 | 
						|
                m = regexs[1].match(expr)
 | 
						|
            else:
 | 
						|
                m = regexs[2].match(expr)
 | 
						|
            mlist = m.groups()
 | 
						|
            if len(mlist) != 4:
 | 
						|
                raise Exception('%s: ' %ifacename + errmsg + '(unexpected len)')
 | 
						|
            prefix = mlist[0]
 | 
						|
            suffix = mlist[3]
 | 
						|
            start_index = int(mlist[1])
 | 
						|
            end_index = int(mlist[2])
 | 
						|
            for i in range(start_index, end_index + 1):
 | 
						|
                yield prefix + '%d' %i + suffix
 | 
						|
 | 
						|
        else:
 | 
						|
            # Could not match anything.
 | 
						|
            self.logger.warning('%s: %s' %(ifacename, errmsg))
 | 
						|
            yield expr
 | 
						|
 | 
						|
    def parse_port_list(self, ifacename, port_expr, ifacenames=None):
 | 
						|
        """ parse port list containing glob and regex
 | 
						|
 | 
						|
        Args:
 | 
						|
            port_expr (str): expression
 | 
						|
            ifacenames (list): list of interface names. This needs to be specified if the expression has a regular expression
 | 
						|
        """
 | 
						|
        regex = 0
 | 
						|
        glob = 0
 | 
						|
        portlist = []
 | 
						|
 | 
						|
        if not port_expr:
 | 
						|
            return None
 | 
						|
        exprs = re.split(r'[\s\t]\s*', port_expr)
 | 
						|
        self.logger.debug('%s: evaluating port expr \'%s\''
 | 
						|
                         %(ifacename, str(exprs)))
 | 
						|
        for expr in exprs:
 | 
						|
            if expr == 'noregex':
 | 
						|
                regex = 0
 | 
						|
            elif expr == 'noglob':
 | 
						|
                glob = 0
 | 
						|
            elif expr == 'regex':
 | 
						|
                regex = 1
 | 
						|
            elif expr == 'glob':
 | 
						|
                glob = 1
 | 
						|
            elif regex:
 | 
						|
                for port in self.parse_regex(ifacename, expr, ifacenames):
 | 
						|
                    if port not in portlist:
 | 
						|
                        portlist.append(port)
 | 
						|
                regex = 0
 | 
						|
            elif glob:
 | 
						|
                for port in self.parse_glob(ifacename, expr):
 | 
						|
                    portlist.append(port)
 | 
						|
                glob = 0
 | 
						|
            else:
 | 
						|
                portlist.append(expr)
 | 
						|
        if not portlist:
 | 
						|
            return None
 | 
						|
        return portlist
 | 
						|
 | 
						|
    def ignore_error(self, errmsg):
 | 
						|
        if (ifupdownflags.flags.FORCE or re.search(r'exists', errmsg,
 | 
						|
            re.IGNORECASE | re.MULTILINE)):
 | 
						|
            return True
 | 
						|
        return False
 | 
						|
 | 
						|
    def write_file(self, filename, strexpr):
 | 
						|
        """ writes string to a file """
 | 
						|
        try:
 | 
						|
            self.logger.info('writing \'%s\'' %strexpr +
 | 
						|
                ' to file %s' %filename)
 | 
						|
            if ifupdownflags.flags.DRYRUN:
 | 
						|
                return 0
 | 
						|
            with open(filename, 'w') as f:
 | 
						|
                f.write(strexpr)
 | 
						|
        except IOError as e:
 | 
						|
            self.logger.warning('error writing to file %s'
 | 
						|
                %filename + '(' + str(e) + ')')
 | 
						|
            return -1
 | 
						|
        return 0
 | 
						|
 | 
						|
    def read_file(self, filename):
 | 
						|
        """ read file and return lines from the file """
 | 
						|
        try:
 | 
						|
            self.logger.info('reading \'%s\'' %filename)
 | 
						|
            with open(filename, 'r') as f:
 | 
						|
                return f.readlines()
 | 
						|
        except Exception:
 | 
						|
            return None
 | 
						|
        return None
 | 
						|
 | 
						|
    def read_file_oneline(self, filename):
 | 
						|
        """ reads and returns first line from the file """
 | 
						|
        try:
 | 
						|
            self.logger.info('reading \'%s\'' %filename)
 | 
						|
            with open(filename, 'r') as f:
 | 
						|
                return f.readline().strip('\n')
 | 
						|
        except Exception:
 | 
						|
            return None
 | 
						|
        return None
 | 
						|
 | 
						|
    def sysctl_set(self, variable, value):
 | 
						|
        """ set sysctl variable to value passed as argument """
 | 
						|
        utils.exec_command('%s %s=%s' %
 | 
						|
                           (utils.sysctl_cmd, variable, value))
 | 
						|
 | 
						|
    def sysctl_get(self, variable):
 | 
						|
        """ get value of sysctl variable """
 | 
						|
        output = utils.exec_command('%s %s' %
 | 
						|
                                    (utils.sysctl_cmd, variable))
 | 
						|
        split = output.split('=')
 | 
						|
        if len(split) > 1:
 | 
						|
            return split[1].strip()
 | 
						|
        return None
 | 
						|
 | 
						|
    def systcl_get_net_bridge_stp_user_space(self):
 | 
						|
        if self._bridge_stp_user_space:
 | 
						|
            return self._bridge_stp_user_space
 | 
						|
        try:
 | 
						|
            self._bridge_stp_user_space = self.sysctl_get('net.bridge.bridge-stp-user-space')
 | 
						|
        except Exception:
 | 
						|
            self._bridge_stp_user_space = 0
 | 
						|
 | 
						|
        return self._bridge_stp_user_space
 | 
						|
 | 
						|
    def set_iface_attr(self, ifaceobj, attr_name, attr_valsetfunc,
 | 
						|
                       prehook=None, prehookargs=None):
 | 
						|
        ifacename = ifaceobj.name
 | 
						|
        attrvalue = ifaceobj.get_attr_value_first(attr_name)
 | 
						|
        if attrvalue:
 | 
						|
            if prehook:
 | 
						|
                if prehookargs:
 | 
						|
                    prehook(prehookargs)
 | 
						|
                else:
 | 
						|
                    prehook(ifacename)
 | 
						|
            attr_valsetfunc(ifacename, attrvalue)
 | 
						|
 | 
						|
    def query_n_update_ifaceobjcurr_attr(self, ifaceobj, ifaceobjcurr,
 | 
						|
                                       attr_name, attr_valgetfunc,
 | 
						|
                                       attr_valgetextraarg=None):
 | 
						|
        attrvalue = ifaceobj.get_attr_value_first(attr_name)
 | 
						|
        if not attrvalue:
 | 
						|
            return
 | 
						|
        if attr_valgetextraarg:
 | 
						|
            runningattrvalue = attr_valgetfunc(ifaceobj.name,
 | 
						|
                                             attr_valgetextraarg)
 | 
						|
        else:
 | 
						|
            runningattrvalue = attr_valgetfunc(ifaceobj.name)
 | 
						|
        if (not runningattrvalue or
 | 
						|
            (runningattrvalue != attrvalue)):
 | 
						|
            ifaceobjcurr.update_config_with_status(attr_name,
 | 
						|
                runningattrvalue, 1)
 | 
						|
        else:
 | 
						|
            ifaceobjcurr.update_config_with_status(attr_name,
 | 
						|
                runningattrvalue, 0)
 | 
						|
 | 
						|
    def dict_key_subset(self, a, b):
 | 
						|
        """ returns a list of differing keys """
 | 
						|
        return [x for x in a if x in b]
 | 
						|
 | 
						|
    def get_mod_attrs(self):
 | 
						|
        """ returns list of all module attrs defined in the module _modinfo
 | 
						|
            dict
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            retattrs = []
 | 
						|
            attrsdict = self._modinfo.get('attrs')
 | 
						|
            for attrname, attrvals in attrsdict.items():
 | 
						|
                if not attrvals or attrvals.get('deprecated'):
 | 
						|
                    continue
 | 
						|
                retattrs.append(attrname)
 | 
						|
                if 'aliases' in attrvals:
 | 
						|
                    retattrs.extend(attrvals['aliases'])
 | 
						|
            return retattrs
 | 
						|
        except Exception:
 | 
						|
            return None
 | 
						|
 | 
						|
    def get_mod_attr(self, attrname):
 | 
						|
        """ returns module attr info """
 | 
						|
        try:
 | 
						|
            return self._modinfo.get('attrs', {}).get(attrname)
 | 
						|
        except Exception:
 | 
						|
            return None
 | 
						|
 | 
						|
    def get_mod_subattr(self, attrname, subattrname):
 | 
						|
        """ returns module attrs defined in the module _modinfo dict"""
 | 
						|
        try:
 | 
						|
            return reduce(lambda d, k: d[k], ['attrs', attrname, subattrname],
 | 
						|
                         self._modinfo)
 | 
						|
        except Exception:
 | 
						|
            return None
 | 
						|
 | 
						|
    def get_modinfo(self):
 | 
						|
        """ return module info """
 | 
						|
        try:
 | 
						|
            return self._modinfo
 | 
						|
        except Exception:
 | 
						|
            return {}
 | 
						|
 | 
						|
    def get_attr_default_value(self, attrname):
 | 
						|
        return self.get_modinfo().get('attrs', {}).get(attrname, {}).get('default')
 | 
						|
 | 
						|
    def get_overrides_ifupdown_scripts(self):
 | 
						|
        """ return the ifupdown scripts replaced by the current module """
 | 
						|
        try:
 | 
						|
            return self.overrides_ifupdown_scripts
 | 
						|
        except Exception:
 | 
						|
            return []
 | 
						|
 | 
						|
    def _get_reserved_vlan_range(self):
 | 
						|
        start = end = 0
 | 
						|
        get_resvvlan = '/var/lib/ifupdown2/hooks/get_reserved_vlan_range.sh'
 | 
						|
        if not os.path.exists(get_resvvlan):
 | 
						|
            return (start, end)
 | 
						|
        try:
 | 
						|
            (s, e) = utils.exec_command(get_resvvlan).strip('\n').split('-')
 | 
						|
            start = int(s)
 | 
						|
            end = int(e)
 | 
						|
        except Exception as e:
 | 
						|
            self.logger.debug('%s failed (%s)' %(get_resvvlan, str(e)))
 | 
						|
            # ignore errors
 | 
						|
            pass
 | 
						|
        return (start, end)
 | 
						|
 | 
						|
    def _get_vrf_context(self):
 | 
						|
        vrfid = 'default'
 | 
						|
        try:
 | 
						|
            vrfid = utils.exec_command('/usr/sbin/ip vrf id').strip()
 | 
						|
        except Exception as e:
 | 
						|
            self.logger.debug('failed to get vrf id (%s)' %str(e))
 | 
						|
            # ignore errors
 | 
						|
            vrfid = None
 | 
						|
            pass
 | 
						|
        return vrfid
 | 
						|
 | 
						|
    def _handle_reserved_vlan(self, vlanid, logprefix='', end=-1):
 | 
						|
        """ Helper function to check and warn if the vlanid falls in the
 | 
						|
        reserved vlan range """
 | 
						|
        error = False
 | 
						|
        invalid_vlan = vlanid
 | 
						|
 | 
						|
        if self._resv_vlan_range[0] <= vlanid <= self._resv_vlan_range[1]:
 | 
						|
            error = True
 | 
						|
        elif end > 0:
 | 
						|
            if self._resv_vlan_range[0] <= end <= self._resv_vlan_range[1]:
 | 
						|
                error = True
 | 
						|
                invalid_vlan = end
 | 
						|
            elif vlanid < self._resv_vlan_range[0] and end > self._resv_vlan_range[1]:
 | 
						|
                error = True
 | 
						|
                invalid_vlan = self._resv_vlan_range[0]
 | 
						|
 | 
						|
        if error:
 | 
						|
            raise exceptions.ReservedVlanException('%s: reserved vlan %d being used (reserved vlan range %d-%d)'
 | 
						|
                                                   % (logprefix, invalid_vlan, self._resv_vlan_range[0], self._resv_vlan_range[1]))
 | 
						|
 | 
						|
        return error
 | 
						|
 | 
						|
    def _valid_ethaddr(self, ethaddr):
 | 
						|
        """ Check if address is 00:00:00:00:00:00 """
 | 
						|
        if not ethaddr or re.match('00:00:00:00:00:00', ethaddr):
 | 
						|
            return False
 | 
						|
        return True
 | 
						|
 | 
						|
    def _get_vlan_id_from_ifacename(self, ifacename):
 | 
						|
        if '.' in ifacename:
 | 
						|
            vid_str = ifacename.split('.', 2)
 | 
						|
            vlen = len(vid_str)
 | 
						|
            if vlen == 2:
 | 
						|
                vid_str = vid_str[1]
 | 
						|
            elif vlen == 3:
 | 
						|
                vid_str = vid_str[2]
 | 
						|
        elif ifacename.startswith('vlan'):
 | 
						|
            vid_str = ifacename[4:]
 | 
						|
        else:
 | 
						|
            return -1
 | 
						|
        try:
 | 
						|
            vid = int(vid_str)
 | 
						|
        except Exception:
 | 
						|
            return -1
 | 
						|
        return vid
 | 
						|
 | 
						|
    def _get_vlan_id(self, ifaceobj):
 | 
						|
        """ Derives vlanid from iface name
 | 
						|
 | 
						|
        Example:
 | 
						|
            Returns 1 for ifname vlan0001 returns 1
 | 
						|
            Returns 1 for ifname vlan1
 | 
						|
            Returns 1 for ifname eth0.1
 | 
						|
            Returns 100 for ifname eth0.1.100
 | 
						|
            Returns -1 if vlan id cannot be determined
 | 
						|
        """
 | 
						|
        vid_str = ifaceobj.get_attr_value_first('vlan-id')
 | 
						|
        try:
 | 
						|
            if vid_str: return int(vid_str)
 | 
						|
        except Exception:
 | 
						|
            return -1
 | 
						|
 | 
						|
        return self._get_vlan_id_from_ifacename(ifaceobj.name)
 |