|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# Copyright (c) 2019-2020 Red Hat, Inc.
|
|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# This file is part of nmstate
|
|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# This program is free software: you can redistribute it and/or modify
|
|
Packit Service |
0535c1 |
# it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
0535c1 |
# the Free Software Foundation, either version 2.1 of the License, or
|
|
Packit Service |
0535c1 |
# (at your option) any later version.
|
|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# This program is distributed in the hope that it will be useful,
|
|
Packit Service |
0535c1 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
0535c1 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
0535c1 |
# GNU Lesser General Public License for more details.
|
|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
0535c1 |
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
import re
|
|
Packit Service |
0535c1 |
import subprocess
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
from libnmstate.error import NmstateNotSupportedError
|
|
Packit Service |
0535c1 |
from libnmstate.schema import Ethernet
|
|
Packit Service |
0535c1 |
from libnmstate.schema import Interface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
from .common import NM
|
|
Packit Service |
0535c1 |
from .common import GLib
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
SRIOV_NMSTATE_TO_NM_MAP = {
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MAC_ADDRESS: (
|
|
Packit Service |
0535c1 |
NM.SRIOV_VF_ATTRIBUTE_MAC,
|
|
Packit Service |
0535c1 |
GLib.Variant.new_string,
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.SPOOF_CHECK: (
|
|
Packit Service |
0535c1 |
NM.SRIOV_VF_ATTRIBUTE_SPOOF_CHECK,
|
|
Packit Service |
0535c1 |
GLib.Variant.new_boolean,
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.TRUST: (
|
|
Packit Service |
0535c1 |
NM.SRIOV_VF_ATTRIBUTE_TRUST,
|
|
Packit Service |
0535c1 |
GLib.Variant.new_boolean,
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MIN_TX_RATE: (
|
|
Packit Service |
0535c1 |
NM.SRIOV_VF_ATTRIBUTE_MIN_TX_RATE,
|
|
Packit Service |
0535c1 |
GLib.Variant.new_uint32,
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MAX_TX_RATE: (
|
|
Packit Service |
0535c1 |
NM.SRIOV_VF_ATTRIBUTE_MAX_TX_RATE,
|
|
Packit Service |
0535c1 |
GLib.Variant.new_uint32,
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
SRIOV_NMSTATE_TO_REGEX = {
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MAC_ADDRESS: re.compile(
|
|
Packit Service |
0535c1 |
r"[a-fA-F0-9:]{17}|[a-fA-F0-9]{12}"
|
|
Packit Service |
0535c1 |
),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.SPOOF_CHECK: re.compile(r"checking (on|off)"),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.TRUST: re.compile(r"trust (on|off)"),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MIN_TX_RATE: re.compile(r"min_tx_rate ([0-9]+)"),
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV.VFS.MAX_TX_RATE: re.compile(r"max_tx_rate ([0-9]+)"),
|
|
Packit Service |
0535c1 |
}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def create_setting(context, iface_state, base_con_profile):
|
|
Packit Service |
0535c1 |
sriov_setting = None
|
|
Packit Service |
0535c1 |
ifname = iface_state[Interface.NAME]
|
|
Packit Service |
0535c1 |
sriov_config = iface_state.get(Ethernet.CONFIG_SUBTREE, {}).get(
|
|
Packit Service |
0535c1 |
Ethernet.SRIOV_SUBTREE
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
if sriov_config:
|
|
Packit Service |
0535c1 |
if not _has_sriov_capability(context, ifname):
|
|
Packit Service |
0535c1 |
raise NmstateNotSupportedError(
|
|
Packit Service |
0535c1 |
f"Interface '{ifname}' does not support SR-IOV"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
sriov_setting = base_con_profile.get_setting_duplicate(
|
|
Packit Service |
0535c1 |
NM.SETTING_SRIOV_SETTING_NAME
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
if not sriov_setting:
|
|
Packit Service |
0535c1 |
sriov_setting = NM.SettingSriov.new()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
vfs_config = sriov_config.get(Ethernet.SRIOV.VFS_SUBTREE, [])
|
|
Packit Service |
0535c1 |
vf_object_ids = {vf.get_index() for vf in sriov_setting.props.vfs}
|
|
Packit Service |
0535c1 |
vf_config_ids = {
|
|
Packit Service |
0535c1 |
vf_config[Ethernet.SRIOV.VFS.ID] for vf_config in vfs_config
|
|
Packit Service |
0535c1 |
}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
# As the user must do full edit of vfs, nmstate is deleting all the vfs
|
|
Packit Service |
0535c1 |
# and then adding all the vfs from the config.
|
|
Packit Service |
0535c1 |
for vf_id in _remove_sriov_vfs_in_setting(
|
|
Packit Service |
0535c1 |
vfs_config, sriov_setting, vf_object_ids
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
sriov_setting.remove_vf_by_index(vf_id)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
for vf_object in _create_sriov_vfs_from_config(
|
|
Packit Service |
0535c1 |
vfs_config, sriov_setting, vf_config_ids
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
sriov_setting.add_vf(vf_object)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
sriov_setting.props.total_vfs = sriov_config[Ethernet.SRIOV.TOTAL_VFS]
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
return sriov_setting
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _create_sriov_vfs_from_config(vfs_config, sriov_setting, vf_ids_to_add):
|
|
Packit Service |
0535c1 |
vfs_config_to_add = (
|
|
Packit Service |
0535c1 |
vf_config
|
|
Packit Service |
0535c1 |
for vf_config in vfs_config
|
|
Packit Service |
0535c1 |
if vf_config[Ethernet.SRIOV.VFS.ID] in vf_ids_to_add
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
for vf_config in vfs_config_to_add:
|
|
Packit Service |
0535c1 |
vf_id = vf_config.pop(Ethernet.SRIOV.VFS.ID)
|
|
Packit Service |
0535c1 |
vf_object = NM.SriovVF.new(vf_id)
|
|
Packit Service |
0535c1 |
for key, val in vf_config.items():
|
|
Packit Service |
0535c1 |
_set_nm_attribute(vf_object, key, val)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
yield vf_object
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _set_nm_attribute(vf_object, key, value):
|
|
Packit Service |
0535c1 |
nm_attr, nm_variant = SRIOV_NMSTATE_TO_NM_MAP[key]
|
|
Packit Service |
0535c1 |
vf_object.set_attribute(nm_attr, nm_variant(value))
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _remove_sriov_vfs_in_setting(vfs_config, sriov_setting, vf_ids_to_remove):
|
|
Packit Service |
0535c1 |
for vf_id in vf_ids_to_remove:
|
|
Packit Service |
0535c1 |
yield vf_id
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _has_sriov_capability(context, ifname):
|
|
Packit Service |
0535c1 |
dev = context.get_nm_dev(ifname)
|
|
Packit Service |
0535c1 |
return dev and (NM.DeviceCapabilities.SRIOV & dev.props.capabilities)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def get_info(device):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Provide the current active SR-IOV runtime values
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
sriov_running_info = {}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
ifname = device.get_iface()
|
|
Packit Service |
0535c1 |
numvf_path = f"/sys/class/net/{ifname}/device/sriov_numvfs"
|
|
Packit Service |
0535c1 |
try:
|
|
Packit Service |
0535c1 |
with open(numvf_path) as f:
|
|
Packit Service |
0535c1 |
sriov_running_info[Ethernet.SRIOV.TOTAL_VFS] = int(f.read())
|
|
Packit Service |
0535c1 |
except FileNotFoundError:
|
|
Packit Service |
0535c1 |
return sriov_running_info
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
if sriov_running_info[Ethernet.SRIOV.TOTAL_VFS]:
|
|
Packit Service |
0535c1 |
sriov_running_info[Ethernet.SRIOV.VFS_SUBTREE] = _get_sriov_vfs_info(
|
|
Packit Service |
0535c1 |
ifname
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
else:
|
|
Packit Service |
0535c1 |
sriov_running_info[Ethernet.SRIOV.VFS_SUBTREE] = []
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
return {Ethernet.SRIOV_SUBTREE: sriov_running_info}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _get_sriov_vfs_info(ifname):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
This is a workaround to get the VFs configuration from runtime.
|
|
Packit Service |
0535c1 |
Ref: https://bugzilla.redhat.com/1777520
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
proc = subprocess.run(
|
|
Packit Service |
0535c1 |
("ip", "link", "show", ifname),
|
|
Packit Service |
0535c1 |
stdout=subprocess.PIPE,
|
|
Packit Service |
0535c1 |
encoding="utf-8",
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
iplink_output = proc.stdout
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
# This is ignoring the first two line of the ip link output because they
|
|
Packit Service |
0535c1 |
# are about the PF and we don't need them.
|
|
Packit Service |
0535c1 |
vfs = iplink_output.splitlines(False)[2:]
|
|
Packit Service |
0535c1 |
vfs_config = [
|
|
Packit Service |
0535c1 |
vf_config for vf_config in _parse_ip_link_output_for_vfs(vfs)
|
|
Packit Service |
0535c1 |
]
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
return vfs_config
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _parse_ip_link_output_for_vfs(vfs):
|
|
Packit Service |
0535c1 |
for vf_id, vf in enumerate(vfs):
|
|
Packit Service |
0535c1 |
vf_config = _parse_ip_link_output_options_for_vf(vf)
|
|
Packit Service |
0535c1 |
vf_config[Ethernet.SRIOV.VFS.ID] = vf_id
|
|
Packit Service |
0535c1 |
yield vf_config
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _parse_ip_link_output_options_for_vf(vf):
|
|
Packit Service |
0535c1 |
vf_options = {}
|
|
Packit Service |
0535c1 |
for option, expr in SRIOV_NMSTATE_TO_REGEX.items():
|
|
Packit Service |
0535c1 |
match_expr = expr.search(vf)
|
|
Packit Service |
0535c1 |
if match_expr:
|
|
Packit Service |
0535c1 |
if option == Ethernet.SRIOV.VFS.MAC_ADDRESS:
|
|
Packit Service |
0535c1 |
value = match_expr.group(0).upper()
|
|
Packit Service |
0535c1 |
else:
|
|
Packit Service |
0535c1 |
value = match_expr.group(1)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
if value.isdigit():
|
|
Packit Service |
0535c1 |
value = int(value)
|
|
Packit Service |
0535c1 |
elif value == "on":
|
|
Packit Service |
0535c1 |
value = True
|
|
Packit Service |
0535c1 |
elif value == "off":
|
|
Packit Service |
0535c1 |
value = False
|
|
Packit Service |
0535c1 |
vf_options[option] = value
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
return vf_options
|