52975f6a1a
Add sanity_check that 'ip link' command supports VF management and link state changes of VF by parsing 'ip link help' command output. Co-authored-by: Samer Deeb <samerd@mellanox.com> Closes bug: 1349302 Change-Id: I5a72a9061a76c39960076f078905371f07069431
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
# Copyright 2014 Mellanox Technologies, Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import re
|
|
|
|
from neutron.agent.linux import utils
|
|
from neutron.common import exceptions as n_exc
|
|
from neutron.openstack.common.gettextutils import _LE
|
|
from neutron.openstack.common import log as logging
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class IpLinkSupportError(n_exc.NeutronException):
|
|
pass
|
|
|
|
|
|
class UnsupportedIpLinkCommand(IpLinkSupportError):
|
|
message = _("ip link command is not supported: %(reason)s")
|
|
|
|
|
|
class InvalidIpLinkCapability(IpLinkSupportError):
|
|
message = _("ip link capability %(capability)s is not supported")
|
|
|
|
|
|
class IpLinkConstants(object):
|
|
IP_LINK_CAPABILITY_STATE = "state"
|
|
IP_LINK_CAPABILITY_VLAN = "vlan"
|
|
IP_LINK_CAPABILITY_RATE = "rate"
|
|
IP_LINK_CAPABILITY_SPOOFCHK = "spoofchk"
|
|
IP_LINK_SUB_CAPABILITY_QOS = "qos"
|
|
|
|
|
|
class IpLinkSupport(object):
|
|
VF_BLOCK_REGEX = "\[ vf NUM(?P<vf_block>.*) \] \]"
|
|
|
|
CAPABILITY_REGEX = "\[ %s (.*)"
|
|
SUB_CAPABILITY_REGEX = "\[ %(cap)s (.*) \[ %(subcap)s (.*)"
|
|
|
|
@classmethod
|
|
def get_vf_mgmt_section(cls, root_helper=None):
|
|
"""Parses ip link help output, and gets vf block
|
|
|
|
:param root_helper: root permission helper
|
|
|
|
"""
|
|
output = cls._get_ip_link_output(root_helper)
|
|
vf_block_pattern = re.search(cls.VF_BLOCK_REGEX,
|
|
output,
|
|
re.DOTALL | re.MULTILINE)
|
|
if vf_block_pattern:
|
|
return vf_block_pattern.group("vf_block")
|
|
|
|
@classmethod
|
|
def vf_mgmt_capability_supported(cls, vf_section, capability,
|
|
subcapability=None):
|
|
"""Validate vf capability support
|
|
|
|
Checks if given vf capability (and sub capability
|
|
if given) supported
|
|
:param vf_section: vf Num block content
|
|
:param capability: for example: vlan, rate, spoofchk, state
|
|
:param subcapability: for example: qos
|
|
"""
|
|
if not vf_section:
|
|
return False
|
|
if subcapability:
|
|
regex = cls.SUB_CAPABILITY_REGEX % {"cap": capability,
|
|
"subcap": subcapability}
|
|
else:
|
|
regex = cls.CAPABILITY_REGEX % capability
|
|
pattern_match = re.search(regex, vf_section,
|
|
re.DOTALL | re.MULTILINE)
|
|
return pattern_match is not None
|
|
|
|
@classmethod
|
|
def _get_ip_link_output(cls, root_helper):
|
|
"""Gets the output of the ip link help command
|
|
|
|
Runs ip link help command and stores its output
|
|
Note: ip link help return error and writes its output to stderr
|
|
so we get the output from there. however, if this issue
|
|
will be solved and the command will write to stdout, we
|
|
will get the output from there too.
|
|
"""
|
|
try:
|
|
ip_cmd = ['ip', 'link', 'help']
|
|
_stdout, _stderr = utils.execute(
|
|
ip_cmd, root_helper,
|
|
check_exit_code=False,
|
|
return_stderr=True,
|
|
log_fail_as_error=False)
|
|
except Exception as e:
|
|
LOG.exception(_LE("Failed executing ip command"))
|
|
raise UnsupportedIpLinkCommand(reason=e)
|
|
return _stdout or _stderr
|