|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# Copyright (c) 2018-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 contextlib
|
|
Packit Service |
0535c1 |
import os
|
|
Packit Service |
0535c1 |
import glob
|
|
Packit Service |
0535c1 |
import re
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
from libnmstate.error import NmstateValueError
|
|
Packit Service |
0535c1 |
from libnmstate.ifaces.bond import BondIface
|
|
Packit Service |
0535c1 |
from libnmstate.schema import Bond
|
|
Packit Service |
0535c1 |
from .common import NM
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
BOND_TYPE = "bond"
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
SYSFS_EMPTY_VALUE = ""
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
NM_SUPPORTED_BOND_OPTIONS = NM.SettingBond.get_valid_options(
|
|
Packit Service |
0535c1 |
NM.SettingBond.new()
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
SYSFS_BOND_OPTION_FOLDER_FMT = "/sys/class/net/{ifname}/bonding"
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
c7b39a |
BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC = "00:00:00:00:00:00"
|
|
Packit Service |
c7b39a |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def create_setting(options, wired_setting):
|
|
Packit Service |
0535c1 |
bond_setting = NM.SettingBond.new()
|
|
Packit Service |
0535c1 |
_fix_bond_option_arp_interval(options)
|
|
Packit Service |
0535c1 |
for option_name, option_value in options.items():
|
|
Packit Service |
0535c1 |
if wired_setting and BondIface.is_mac_restricted_mode(
|
|
Packit Service |
0535c1 |
options.get(Bond.MODE), options
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
# When in MAC restricted mode, MAC address should be unset.
|
|
Packit Service |
0535c1 |
wired_setting.props.cloned_mac_address = None
|
|
Packit Service |
c7b39a |
if (
|
|
Packit Service |
c7b39a |
option_name == "ad_actor_system"
|
|
Packit Service |
c7b39a |
and option_value == BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC
|
|
Packit Service |
c7b39a |
):
|
|
Packit Service |
c7b39a |
# The all zero ad_actor_system is the kernel default value
|
|
Packit Service |
c7b39a |
# And it is invalid to set as all zero
|
|
Packit Service |
c7b39a |
continue
|
|
Packit Service |
0535c1 |
if option_value != SYSFS_EMPTY_VALUE:
|
|
Packit Service |
0535c1 |
success = bond_setting.add_option(option_name, str(option_value))
|
|
Packit Service |
0535c1 |
if not success:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
"Invalid bond option: '{}'='{}'".format(
|
|
Packit Service |
0535c1 |
option_name, option_value
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
return bond_setting
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def is_bond_type_id(type_id):
|
|
Packit Service |
0535c1 |
return type_id == NM.DeviceType.BOND
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def get_bond_info(nm_device):
|
|
Packit Service |
0535c1 |
slaves = get_slaves(nm_device)
|
|
Packit Service |
0535c1 |
options = _get_options(nm_device)
|
|
Packit Service |
0535c1 |
if slaves or options:
|
|
Packit Service |
0535c1 |
return {"slaves": slaves, "options": options}
|
|
Packit Service |
0535c1 |
else:
|
|
Packit Service |
0535c1 |
return {}
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _get_options(nm_device):
|
|
Packit Service |
0535c1 |
ifname = nm_device.get_iface()
|
|
Packit Service |
0535c1 |
bond_option_names_in_profile = get_bond_option_names_in_profile(nm_device)
|
|
Packit Service |
0535c1 |
if (
|
|
Packit Service |
0535c1 |
"miimon" in bond_option_names_in_profile
|
|
Packit Service |
0535c1 |
or "arp_interval" in bond_option_names_in_profile
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
bond_option_names_in_profile.add("arp_interval")
|
|
Packit Service |
0535c1 |
bond_option_names_in_profile.add("miimon")
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
# Mode is required
|
|
Packit Service |
0535c1 |
sysfs_folder = SYSFS_BOND_OPTION_FOLDER_FMT.format(ifname=ifname)
|
|
Packit Service |
0535c1 |
mode = _read_sysfs_file(f"{sysfs_folder}/mode")
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
bond_setting = NM.SettingBond.new()
|
|
Packit Service |
0535c1 |
bond_setting.add_option(Bond.MODE, mode)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
options = {Bond.MODE: mode}
|
|
Packit Service |
0535c1 |
for sysfs_file in glob.iglob(f"{sysfs_folder}/*"):
|
|
Packit Service |
0535c1 |
option = os.path.basename(sysfs_file)
|
|
Packit Service |
0535c1 |
if option in NM_SUPPORTED_BOND_OPTIONS:
|
|
Packit Service |
0535c1 |
value = _read_sysfs_file(sysfs_file)
|
|
Packit Service |
0535c1 |
# When default_value is None, it means this option is invalid
|
|
Packit Service |
0535c1 |
# under this bond mode
|
|
Packit Service |
0535c1 |
default_value = bond_setting.get_option_default(option)
|
|
Packit Service |
0535c1 |
if (
|
|
Packit Service |
0535c1 |
(default_value and value != default_value)
|
|
Packit Service |
0535c1 |
# Always include bond options which are explicitly defined in
|
|
Packit Service |
0535c1 |
# on-disk profile.
|
|
Packit Service |
0535c1 |
or option in bond_option_names_in_profile
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
if option == "arp_ip_target":
|
|
Packit Service |
0535c1 |
value = value.replace(" ", ",")
|
|
Packit Service |
0535c1 |
options[option] = value
|
|
Packit Service |
0535c1 |
# Workaround of https://bugzilla.redhat.com/show_bug.cgi?id=1806549
|
|
Packit Service |
0535c1 |
if "miimon" not in options:
|
|
Packit Service |
0535c1 |
options["miimon"] = bond_setting.get_option_default("miimon")
|
|
Packit Service |
0535c1 |
return options
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _read_sysfs_file(file_path):
|
|
Packit Service |
0535c1 |
with open(file_path) as fd:
|
|
Packit Service |
0535c1 |
return _strip_sysfs_name_number_value(fd.read().rstrip("\n"))
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _strip_sysfs_name_number_value(value):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
In sysfs/kernel, the value of some are shown with both human friendly
|
|
Packit Service |
0535c1 |
string and integer. For example, bond mode in sysfs is shown as
|
|
Packit Service |
0535c1 |
'balance-rr 0'. This function only return the human friendly string.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
return re.sub(" [0-9]$", "", value)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def get_slaves(nm_device):
|
|
Packit Service |
0535c1 |
return nm_device.get_slaves()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def get_bond_option_names_in_profile(nm_device):
|
|
Packit Service |
0535c1 |
ac = nm_device.get_active_connection()
|
|
Packit Service |
0535c1 |
with contextlib.suppress(AttributeError):
|
|
Packit Service |
0535c1 |
bond_setting = ac.get_connection().get_setting_bond()
|
|
Packit Service |
0535c1 |
return {
|
|
Packit Service |
0535c1 |
bond_setting.get_option(i)[1]
|
|
Packit Service |
0535c1 |
for i in range(0, bond_setting.get_num_options())
|
|
Packit Service |
0535c1 |
}
|
|
Packit Service |
0535c1 |
return set()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _fix_bond_option_arp_interval(bond_options):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Due to bug https://bugzilla.redhat.com/show_bug.cgi?id=1806549
|
|
Packit Service |
0535c1 |
NM 1.22.8 treat 'arp_interval 0' as arp_interval enabled(0 actual means
|
|
Packit Service |
0535c1 |
disabled), which then conflict with 'miimon'.
|
|
Packit Service |
0535c1 |
The workaround is remove 'arp_interval 0' when 'miimon' > 0.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
if "miimon" in bond_options and "arp_interval" in bond_options:
|
|
Packit Service |
0535c1 |
try:
|
|
Packit Service |
0535c1 |
miimon = int(bond_options["miimon"])
|
|
Packit Service |
0535c1 |
arp_interval = int(bond_options["arp_interval"])
|
|
Packit Service |
0535c1 |
except ValueError as e:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(f"Invalid bond option: {e}")
|
|
Packit Service |
0535c1 |
if miimon > 0 and arp_interval == 0:
|
|
Packit Service |
0535c1 |
bond_options.pop("arp_interval")
|
|
Packit Service |
0535c1 |
bond_options.pop("arp_ip_target", None)
|