Blame libnmstate/nm/wired.py

Packit b9ca78
#
Packit b9ca78
# Copyright (c) 2018-2020 Red Hat, Inc.
Packit b9ca78
#
Packit b9ca78
# This file is part of nmstate
Packit b9ca78
#
Packit b9ca78
# This program is free software: you can redistribute it and/or modify
Packit b9ca78
# it under the terms of the GNU Lesser General Public License as published by
Packit b9ca78
# the Free Software Foundation, either version 2.1 of the License, or
Packit b9ca78
# (at your option) any later version.
Packit b9ca78
#
Packit b9ca78
# This program is distributed in the hope that it will be useful,
Packit b9ca78
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b9ca78
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b9ca78
# GNU Lesser General Public License for more details.
Packit b9ca78
#
Packit b9ca78
# You should have received a copy of the GNU Lesser General Public License
Packit b9ca78
# along with this program. If not, see <https://www.gnu.org/licenses/>.
Packit b9ca78
#
Packit b9ca78
Packit b9ca78
from libnmstate.ethtool import minimal_ethtool
Packit b9ca78
from libnmstate.nm import sriov
Packit b9ca78
from libnmstate.schema import Ethernet
Packit b9ca78
from libnmstate.schema import Interface
Packit b9ca78
from .common import NM
Packit b9ca78
Packit b9ca78
Packit b9ca78
ZEROED_MAC = "00:00:00:00:00:00"
Packit b9ca78
Packit b9ca78
Packit b9ca78
class WiredSetting:
Packit b9ca78
    def __init__(self, state):
Packit b9ca78
        self.mtu = state.get(Interface.MTU)
Packit b9ca78
        self.mac = state.get(Interface.MAC)
Packit b9ca78
Packit b9ca78
        ethernet = state.get(Ethernet.CONFIG_SUBTREE, {})
Packit b9ca78
        self.speed = ethernet.get(Ethernet.SPEED)
Packit b9ca78
        self.duplex = ethernet.get(Ethernet.DUPLEX)
Packit b9ca78
        self.auto_negotiation = ethernet.get(Ethernet.AUTO_NEGOTIATION)
Packit b9ca78
Packit b9ca78
    def __hash__(self):
Packit b9ca78
        return hash(self.__key())
Packit b9ca78
Packit b9ca78
    def __eq__(self, other):
Packit b9ca78
        return self is other or self.__key() == other.__key()
Packit b9ca78
Packit b9ca78
    def __ne__(self, other):
Packit b9ca78
        return not self.__eq__(other)
Packit b9ca78
Packit b9ca78
    def __bool__(self):
Packit b9ca78
        return bool(
Packit b9ca78
            self.mac
Packit b9ca78
            or self.mtu
Packit b9ca78
            or self.speed
Packit b9ca78
            or self.duplex
Packit b9ca78
            or (self.auto_negotiation is not None)
Packit b9ca78
        )
Packit b9ca78
Packit b9ca78
    def __key(self):
Packit b9ca78
        return (
Packit b9ca78
            self.mtu,
Packit b9ca78
            self.mac,
Packit b9ca78
            self.speed,
Packit b9ca78
            self.duplex,
Packit b9ca78
            self.auto_negotiation,
Packit b9ca78
        )
Packit b9ca78
Packit b9ca78
Packit b9ca78
def create_setting(iface_state, base_con_profile):
Packit b9ca78
    setting = WiredSetting(iface_state)
Packit b9ca78
Packit b9ca78
    nm_wired_setting = None
Packit b9ca78
    if base_con_profile:
Packit b9ca78
        nm_wired_setting = base_con_profile.get_setting_wired()
Packit b9ca78
        if nm_wired_setting:
Packit b9ca78
            nm_wired_setting = nm_wired_setting.duplicate()
Packit b9ca78
Packit b9ca78
    if not setting:
Packit b9ca78
        return nm_wired_setting
Packit b9ca78
Packit b9ca78
    if not nm_wired_setting:
Packit b9ca78
        nm_wired_setting = NM.SettingWired.new()
Packit b9ca78
Packit b9ca78
    if setting.mac:
Packit b9ca78
        nm_wired_setting.props.cloned_mac_address = setting.mac
Packit b9ca78
Packit b9ca78
    if setting.mtu:
Packit b9ca78
        nm_wired_setting.props.mtu = setting.mtu
Packit b9ca78
Packit b9ca78
    if setting.auto_negotiation:
Packit b9ca78
        nm_wired_setting.props.auto_negotiate = True
Packit b9ca78
        if not setting.speed and not setting.duplex:
Packit b9ca78
            nm_wired_setting.props.speed = 0
Packit b9ca78
            nm_wired_setting.props.duplex = None
Packit b9ca78
Packit b9ca78
        elif not setting.speed:
Packit b9ca78
            ethtool_results = minimal_ethtool(str(iface_state[Interface.NAME]))
Packit b9ca78
            setting.speed = ethtool_results[Ethernet.SPEED]
Packit b9ca78
        elif not setting.duplex:
Packit b9ca78
            ethtool_results = minimal_ethtool(str(iface_state[Interface.NAME]))
Packit b9ca78
            setting.duplex = ethtool_results[Ethernet.DUPLEX]
Packit b9ca78
Packit b9ca78
    elif setting.auto_negotiation is False:
Packit b9ca78
        nm_wired_setting.props.auto_negotiate = False
Packit b9ca78
        ethtool_results = minimal_ethtool(str(iface_state[Interface.NAME]))
Packit b9ca78
        if not setting.speed:
Packit b9ca78
            setting.speed = ethtool_results[Ethernet.SPEED]
Packit b9ca78
        if not setting.duplex:
Packit b9ca78
            setting.duplex = ethtool_results[Ethernet.DUPLEX]
Packit b9ca78
Packit b9ca78
    if setting.speed:
Packit b9ca78
        nm_wired_setting.props.speed = setting.speed
Packit b9ca78
Packit b9ca78
    if setting.duplex in [Ethernet.HALF_DUPLEX, Ethernet.FULL_DUPLEX]:
Packit b9ca78
        nm_wired_setting.props.duplex = setting.duplex
Packit b9ca78
Packit b9ca78
    return nm_wired_setting
Packit b9ca78
Packit b9ca78
Packit b9ca78
def get_info(device):
Packit b9ca78
    """
Packit b9ca78
    Provides the current active values for a device
Packit b9ca78
    """
Packit b9ca78
    info = {}
Packit b9ca78
Packit b9ca78
    iface = device.get_iface()
Packit b9ca78
    try:
Packit bcc2b9
        mtu = int(device.get_mtu())
Packit bcc2b9
        if mtu:
Packit bcc2b9
            info[Interface.MTU] = mtu
Packit b9ca78
    except AttributeError:
Packit b9ca78
        pass
Packit b9ca78
Packit b9ca78
    mac = device.get_hw_address()
Packit b9ca78
    if not mac:
Packit b9ca78
        mac = _get_mac_address_from_sysfs(iface)
Packit b9ca78
Packit b9ca78
    # A device may not have a MAC or it may not yet be "realized" (zeroed mac).
Packit b9ca78
    if mac and mac != ZEROED_MAC:
Packit b9ca78
        info[Interface.MAC] = mac
Packit b9ca78
Packit b9ca78
    if device.get_device_type() == NM.DeviceType.ETHERNET:
Packit b9ca78
        ethernet = _get_ethernet_info(device, iface)
Packit b9ca78
        if ethernet:
Packit b9ca78
            info[Ethernet.CONFIG_SUBTREE] = ethernet
Packit b9ca78
Packit b9ca78
    return info
Packit b9ca78
Packit b9ca78
Packit b9ca78
def _get_mac_address_from_sysfs(ifname):
Packit b9ca78
    """
Packit b9ca78
    Fetch the mac address of an interface from sysfs.
Packit b9ca78
    This is a workaround for https://bugzilla.redhat.com/1786937.
Packit b9ca78
    """
Packit b9ca78
    mac = None
Packit b9ca78
    sysfs_path = f"/sys/class/net/{ifname}/address"
Packit b9ca78
    try:
Packit b9ca78
        with open(sysfs_path) as f:
Packit b9ca78
            mac = f.read().rstrip("\n").upper()
Packit b9ca78
    except FileNotFoundError:
Packit b9ca78
        pass
Packit b9ca78
    return mac
Packit b9ca78
Packit b9ca78
Packit b9ca78
def _get_ethernet_info(device, iface):
Packit b9ca78
    ethernet = {}
Packit b9ca78
    try:
Packit b9ca78
        speed = int(device.get_speed())
Packit b9ca78
        if speed > 0:
Packit b9ca78
            ethernet[Ethernet.SPEED] = speed
Packit b9ca78
        else:
Packit b9ca78
            return None
Packit b9ca78
    except AttributeError:
Packit b9ca78
        return None
Packit b9ca78
Packit b9ca78
    ethtool_results = minimal_ethtool(iface)
Packit b9ca78
    auto_setting = ethtool_results[Ethernet.AUTO_NEGOTIATION]
Packit b9ca78
    if auto_setting is True:
Packit b9ca78
        ethernet[Ethernet.AUTO_NEGOTIATION] = True
Packit b9ca78
    elif auto_setting is False:
Packit b9ca78
        ethernet[Ethernet.AUTO_NEGOTIATION] = False
Packit b9ca78
    else:
Packit b9ca78
        return None
Packit b9ca78
Packit b9ca78
    duplex_setting = ethtool_results[Ethernet.DUPLEX]
Packit b9ca78
    if duplex_setting in [Ethernet.HALF_DUPLEX, Ethernet.FULL_DUPLEX]:
Packit b9ca78
        ethernet[Ethernet.DUPLEX] = duplex_setting
Packit b9ca78
    else:
Packit b9ca78
        return None
Packit b9ca78
Packit b9ca78
    sriov_info = sriov.get_info(device)
Packit b9ca78
    if sriov_info:
Packit b9ca78
        ethernet.update(sriov_info)
Packit b9ca78
Packit b9ca78
    return ethernet