|
Packit Service |
0535c1 |
#
|
|
Packit Service |
0535c1 |
# Copyright (c) 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 logging
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
from libnmstate.error import NmstateKernelIntegerRoundedError
|
|
Packit Service |
0535c1 |
from libnmstate.error import NmstateValueError
|
|
Packit Service |
0535c1 |
from libnmstate.error import NmstateVerificationError
|
|
Packit Service |
0535c1 |
from libnmstate.prettystate import format_desired_current_state_diff
|
|
Packit Service |
0535c1 |
from libnmstate.schema import Interface
|
|
Packit Service |
0535c1 |
from libnmstate.schema import InterfaceType
|
|
Packit Service |
0535c1 |
from libnmstate.schema import InterfaceState
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
from .base_iface import BaseIface
|
|
Packit Service |
0535c1 |
from .bond import BondIface
|
|
Packit Service |
0535c1 |
from .dummy import DummyIface
|
|
Packit Service |
0535c1 |
from .ethernet import EthernetIface
|
|
Packit Service |
0535c1 |
from .linux_bridge import LinuxBridgeIface
|
|
Packit Service |
0535c1 |
from .ovs import OvsBridgeIface
|
|
Packit Service |
0535c1 |
from .ovs import OvsInternalIface
|
|
Packit Service |
0535c1 |
from .team import TeamIface
|
|
Packit Service |
0535c1 |
from .vlan import VlanIface
|
|
Packit Service |
0535c1 |
from .vxlan import VxlanIface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
class Ifaces:
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
The Ifaces class hold both desired state(optional) and current state.
|
|
Packit Service |
0535c1 |
When desire state been provided, will perpare the state for backend plugin
|
|
Packit Service |
0535c1 |
to apply with:
|
|
Packit Service |
0535c1 |
* Validating on original desire state.
|
|
Packit Service |
0535c1 |
* Merging state.
|
|
Packit Service |
0535c1 |
* Generating metadata.
|
|
Packit Service |
0535c1 |
The class itself is focusing on tasks related to inter-interfaces changes:
|
|
Packit Service |
0535c1 |
* Mater/slave interfaces.
|
|
Packit Service |
0535c1 |
* Parent/Child interfaces.
|
|
Packit Service |
0535c1 |
The class is maitnaing a list of BaseIface(or its child classes) which does
|
|
Packit Service |
0535c1 |
not know desire state and current state difference. Hence this class is
|
|
Packit Service |
0535c1 |
also responsible to handle desire vs current state related tasks.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def __init__(self, des_iface_infos, cur_iface_infos, save_to_disk=True):
|
|
Packit Service |
0535c1 |
self._save_to_disk = save_to_disk
|
|
Packit Service |
0535c1 |
self._des_iface_infos = des_iface_infos
|
|
Packit Service |
0535c1 |
self._cur_ifaces = {}
|
|
Packit Service |
0535c1 |
self._ifaces = {}
|
|
Packit Service |
0535c1 |
if cur_iface_infos:
|
|
Packit Service |
0535c1 |
for iface_info in cur_iface_infos:
|
|
Packit Service |
0535c1 |
cur_iface = _to_specific_iface_obj(iface_info, save_to_disk)
|
|
Packit Service |
0535c1 |
self._ifaces[cur_iface.name] = cur_iface
|
|
Packit Service |
0535c1 |
self._cur_ifaces[cur_iface.name] = cur_iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
if des_iface_infos:
|
|
Packit Service |
0535c1 |
for iface_info in des_iface_infos:
|
|
Packit Service |
0535c1 |
iface = BaseIface(iface_info, save_to_disk)
|
|
Packit Service |
0535c1 |
cur_iface = self._ifaces.get(iface.name)
|
|
Packit Service |
0535c1 |
if cur_iface and cur_iface.is_desired:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Duplicate interfaces names detected: {iface.name}"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
if iface_info.get(Interface.TYPE) is None:
|
|
Packit Service |
0535c1 |
if cur_iface:
|
|
Packit Service |
0535c1 |
iface_info[Interface.TYPE] = cur_iface.type
|
|
Packit Service |
0535c1 |
elif iface.is_up:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} has no type defined "
|
|
Packit Service |
0535c1 |
"neither in desire state nor current state"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
iface = _to_specific_iface_obj(iface_info, save_to_disk)
|
|
Packit Service |
0535c1 |
if (
|
|
Packit Service |
0535c1 |
iface.type == InterfaceType.UNKNOWN
|
|
Packit Service |
0535c1 |
# Allowing deletion of down profiles
|
|
Packit Service |
0535c1 |
and not iface.is_absent
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
# Ignore interface with unknown type
|
|
Packit Service |
0535c1 |
continue
|
|
Packit Service |
0535c1 |
if cur_iface:
|
|
Packit Service |
0535c1 |
iface.merge(cur_iface)
|
|
Packit Service |
0535c1 |
iface.mark_as_desired()
|
|
Packit Service |
0535c1 |
self._ifaces[iface.name] = iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
self._create_virtual_slaves()
|
|
Packit Service |
cc849d |
self._create_sriov_vfs_when_changed()
|
|
Packit Service |
0535c1 |
self._validate_unknown_slaves()
|
|
Packit Service |
f44fb0 |
self._mark_vf_interface_as_absent_when_sriov_vf_decrease()
|
|
Packit Service |
0535c1 |
self._validate_unknown_parent()
|
|
Packit Service |
b504c8 |
self._apply_copy_mac_from()
|
|
Packit Service |
0535c1 |
self._gen_metadata()
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
iface.pre_edit_validation_and_cleanup()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
self._pre_edit_validation_and_cleanup()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
b504c8 |
def _apply_copy_mac_from(self):
|
|
Packit Service |
b504c8 |
for iface in self._ifaces.values():
|
|
Packit Service |
b504c8 |
if iface.type not in (
|
|
Packit Service |
b504c8 |
InterfaceType.LINUX_BRIDGE,
|
|
Packit Service |
b504c8 |
InterfaceType.BOND,
|
|
Packit Service |
b504c8 |
):
|
|
Packit Service |
b504c8 |
continue
|
|
Packit Service |
b504c8 |
if not iface.copy_mac_from:
|
|
Packit Service |
b504c8 |
continue
|
|
Packit Service |
b504c8 |
|
|
Packit Service |
b504c8 |
if iface.copy_mac_from not in iface.slaves:
|
|
Packit Service |
b504c8 |
raise NmstateValueError(
|
|
Packit Service |
b504c8 |
f"The interface {iface.name} is holding invalid "
|
|
Packit Service |
b504c8 |
f"{Interface.COPY_MAC_FROM} property "
|
|
Packit Service |
b504c8 |
f"as {iface.copy_mac_from} is not in the port "
|
|
Packit Service |
b504c8 |
f"list: {iface.port}"
|
|
Packit Service |
b504c8 |
)
|
|
Packit Service |
b504c8 |
port_iface = self._ifaces.get(iface.copy_mac_from)
|
|
Packit Service |
b504c8 |
# TODO: bridge/bond might refering the mac from new veth in the
|
|
Packit Service |
b504c8 |
# same desire state, it too complex to support that.
|
|
Packit Service |
b504c8 |
if not port_iface:
|
|
Packit Service |
b504c8 |
raise NmstateValueError(
|
|
Packit Service |
b504c8 |
f"The interface {iface.name} is holding invalid "
|
|
Packit Service |
b504c8 |
f"{Interface.COPY_MAC_FROM} property "
|
|
Packit Service |
b504c8 |
f"as the port {iface.copy_mac_from} does not exists yet"
|
|
Packit Service |
b504c8 |
)
|
|
Packit Service |
b504c8 |
|
|
Packit Service |
b504c8 |
iface.apply_copy_mac_from(port_iface.mac)
|
|
Packit Service |
b504c8 |
|
|
Packit Service |
0535c1 |
def _create_virtual_slaves(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Certain master interface could have virtual slaves which does not
|
|
Packit Service |
0535c1 |
defined in desired state. Create it before generating metadata.
|
|
Packit Service |
0535c1 |
For example, OVS bridge could have slave defined as OVS internal
|
|
Packit Service |
0535c1 |
interface which could be created without defining in desire state but
|
|
Packit Service |
0535c1 |
only in slave list of OVS bridge.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
new_ifaces = []
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.is_up and iface.is_master:
|
|
Packit Service |
0535c1 |
for slave_name in iface.slaves:
|
|
Packit Service |
0535c1 |
if slave_name not in self._ifaces.keys():
|
|
Packit Service |
0535c1 |
new_slave = iface.create_virtual_slave(slave_name)
|
|
Packit Service |
0535c1 |
if new_slave:
|
|
Packit Service |
0535c1 |
new_ifaces.append(new_slave)
|
|
Packit Service |
0535c1 |
for iface in new_ifaces:
|
|
Packit Service |
0535c1 |
self._ifaces[iface.name] = iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
cc849d |
def _create_sriov_vfs_when_changed(self):
|
|
Packit Service |
cc849d |
"""
|
|
Packit Service |
cc849d |
When plugin set the TOTAL_VFS of PF, it might take 1 seconds or
|
|
Packit Service |
cc849d |
more to have the VFs to be ready.
|
|
Packit Service |
cc849d |
Nmstate should use verification retry to make sure VFs are full ready.
|
|
Packit Service |
cc849d |
To do that, we include VFs into desire state.
|
|
Packit Service |
cc849d |
"""
|
|
Packit Service |
cc849d |
new_ifaces = []
|
|
Packit Service |
cc849d |
for iface in self._ifaces.values():
|
|
Packit Service |
cc849d |
if (
|
|
Packit Service |
cc849d |
iface.is_up
|
|
Packit Service |
cc849d |
and (iface.is_desired or iface.is_changed)
|
|
Packit Service |
cc849d |
and iface.type == InterfaceType.ETHERNET
|
|
Packit Service |
cc849d |
and iface.sriov_total_vfs > 0
|
|
Packit Service |
cc849d |
):
|
|
Packit Service |
cc849d |
for new_iface in iface.create_sriov_vf_ifaces():
|
|
Packit Service |
cc849d |
if new_iface.name not in self._ifaces:
|
|
Packit Service |
cc849d |
new_iface.mark_as_desired()
|
|
Packit Service |
10f5ae |
new_iface.mark_as_new_sr_iov_vf()
|
|
Packit Service |
cc849d |
new_ifaces.append(new_iface)
|
|
Packit Service |
57b08e |
else:
|
|
Packit Service |
57b08e |
# When the VFs are being modified, all VFs link are
|
|
Packit Service |
57b08e |
# being removed from kernel and created again. Nmstate
|
|
Packit Service |
57b08e |
# must verify they have been created.
|
|
Packit Service |
57b08e |
self._ifaces[new_iface.name].mark_as_desired()
|
|
Packit Service |
cc849d |
for new_iface in new_ifaces:
|
|
Packit Service |
cc849d |
self._ifaces[new_iface.name] = new_iface
|
|
Packit Service |
cc849d |
|
|
Packit Service |
f44fb0 |
def _mark_vf_interface_as_absent_when_sriov_vf_decrease(self):
|
|
Packit Service |
f44fb0 |
"""
|
|
Packit Service |
f44fb0 |
When SRIOV TOTAL_VFS decreased, we should mark certain VF interfaces
|
|
Packit Service |
f44fb0 |
as absent and also remove the entry in `Ethernet.SRIOV.VFS_SUBTREE`.
|
|
Packit Service |
f44fb0 |
"""
|
|
Packit Service |
f44fb0 |
for iface_name, iface in self._ifaces.items():
|
|
Packit Service |
f44fb0 |
if iface.type != InterfaceType.ETHERNET or not iface.is_up:
|
|
Packit Service |
f44fb0 |
continue
|
|
Packit Service |
f44fb0 |
if iface_name not in self.current_ifaces:
|
|
Packit Service |
f44fb0 |
continue
|
|
Packit Service |
f44fb0 |
cur_iface = self.current_ifaces[iface_name]
|
|
Packit Service |
f44fb0 |
if (
|
|
Packit Service |
f44fb0 |
cur_iface.sriov_total_vfs != 0
|
|
Packit Service |
f44fb0 |
and iface.sriov_total_vfs < cur_iface.sriov_total_vfs
|
|
Packit Service |
f44fb0 |
):
|
|
Packit Service |
f44fb0 |
iface.remove_vfs_entry_when_total_vfs_decreased()
|
|
Packit Service |
f44fb0 |
for vf_name in iface.get_delete_vf_interface_names(
|
|
Packit Service |
f44fb0 |
cur_iface.sriov_total_vfs
|
|
Packit Service |
f44fb0 |
):
|
|
Packit Service |
f44fb0 |
vf_iface = self._ifaces.get(vf_name)
|
|
Packit Service |
f44fb0 |
if vf_iface:
|
|
Packit Service |
f44fb0 |
vf_iface.mark_as_absent_by_desire()
|
|
Packit Service |
f44fb0 |
|
|
Packit Service |
0535c1 |
def _pre_edit_validation_and_cleanup(self):
|
|
Packit Service |
0535c1 |
self._validate_over_booked_slaves()
|
|
Packit Service |
0535c1 |
self._validate_vlan_mtu()
|
|
Packit Service |
0535c1 |
self._handle_master_slave_list_change()
|
|
Packit Service |
0535c1 |
self._match_child_iface_state_with_parent()
|
|
Packit Service |
0535c1 |
self._mark_orphen_as_absent()
|
|
Packit Service |
0535c1 |
self._bring_slave_up_if_not_in_desire()
|
|
Packit Service |
0535c1 |
self._validate_ovs_patch_peers()
|
|
Packit Service |
0535c1 |
self._remove_unknown_type_interfaces()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _bring_slave_up_if_not_in_desire(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
When slave been included in master, automactially set it as state UP
|
|
Packit Service |
0535c1 |
if not defiend in desire state
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
c66a53 |
if iface.is_desired and iface.is_up and iface.is_master:
|
|
Packit Service |
4c3ded |
cur_iface = self.current_ifaces.get(iface.name)
|
|
Packit Service |
0535c1 |
for slave_name in iface.slaves:
|
|
Packit Service |
4c3ded |
if cur_iface and slave_name in cur_iface.slaves:
|
|
Packit Service |
4c3ded |
# Nmstate should not touch the port interface which has
|
|
Packit Service |
4c3ded |
# already been included in current interface.
|
|
Packit Service |
4c3ded |
continue
|
|
Packit Service |
0535c1 |
slave_iface = self._ifaces[slave_name]
|
|
Packit Service |
0535c1 |
if not slave_iface.is_desired and not slave_iface.is_up:
|
|
Packit Service |
0535c1 |
slave_iface.mark_as_up()
|
|
Packit Service |
0535c1 |
slave_iface.mark_as_changed()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _validate_ovs_patch_peers(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
When OVS patch peer does not exist or is down, raise an error.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.type == InterfaceType.OVS_INTERFACE and iface.is_up:
|
|
Packit Service |
0535c1 |
if iface.peer:
|
|
Packit Service |
0535c1 |
peer_iface = self._ifaces.get(iface.peer)
|
|
Packit Service |
0535c1 |
if not peer_iface or not peer_iface.is_up:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"OVS patch port peer {iface.peer} must exist and "
|
|
Packit Service |
0535c1 |
"be up"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
elif (
|
|
Packit Service |
0535c1 |
not peer_iface.type == InterfaceType.OVS_INTERFACE
|
|
Packit Service |
0535c1 |
or not peer_iface.is_patch_port
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"OVS patch port peer {iface.peer} must be an OVS"
|
|
Packit Service |
0535c1 |
" patch port"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _validate_vlan_mtu(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Validate that mtu of vlan or vxlan is less than
|
|
Packit Service |
0535c1 |
or equal to it's base interface's MTU
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
If base MTU is not present, set same as vlan MTU
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
if (
|
|
Packit Service |
0535c1 |
iface.type in [InterfaceType.VLAN, InterfaceType.VXLAN]
|
|
Packit Service |
0535c1 |
and iface.is_up
|
|
Packit Service |
0535c1 |
and iface.mtu
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
base_iface = self._ifaces.get(iface.parent)
|
|
Packit Service |
0535c1 |
if not base_iface.mtu:
|
|
Packit Service |
0535c1 |
base_iface.mtu = iface.mtu
|
|
Packit Service |
0535c1 |
if iface.mtu > base_iface.mtu:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} has bigger "
|
|
Packit Service |
0535c1 |
f"MTU({iface.mtu}) "
|
|
Packit Service |
0535c1 |
f"than its base interface: {iface.parent} "
|
|
Packit Service |
0535c1 |
f"MTU({base_iface.mtu})"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _handle_master_slave_list_change(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
* Mark slave interface as changed if master removed.
|
|
Packit Service |
0535c1 |
* Mark slave interface as changed if slave list of master changed.
|
|
Packit Service |
0535c1 |
* Mark slave interface as changed if slave config changed when master
|
|
Packit Service |
0535c1 |
said so.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if not iface.is_desired or not iface.is_master:
|
|
Packit Service |
0535c1 |
continue
|
|
Packit Service |
0535c1 |
des_slaves = set(iface.slaves)
|
|
Packit Service |
0535c1 |
if iface.is_absent:
|
|
Packit Service |
0535c1 |
des_slaves = set()
|
|
Packit Service |
0535c1 |
cur_iface = self._cur_ifaces.get(iface.name)
|
|
Packit Service |
0535c1 |
cur_slaves = set(cur_iface.slaves) if cur_iface else set()
|
|
Packit Service |
0535c1 |
if des_slaves != cur_slaves:
|
|
Packit Service |
0535c1 |
changed_slaves = (des_slaves | cur_slaves) - (
|
|
Packit Service |
0535c1 |
des_slaves & cur_slaves
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
for iface_name in changed_slaves:
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].mark_as_changed()
|
|
Packit Service |
0535c1 |
if cur_iface:
|
|
Packit Service |
0535c1 |
for slave_name in iface.config_changed_slaves(cur_iface):
|
|
Packit Service |
ff21db |
if slave_name in self._ifaces:
|
|
Packit Service |
ff21db |
self._ifaces[slave_name].mark_as_changed()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _match_child_iface_state_with_parent(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Handles these use cases:
|
|
Packit Service |
0535c1 |
* When changed/desired parent interface is up, child is not
|
|
Packit Service |
0535c1 |
desired to be any state, set child as UP.
|
|
Packit Service |
0535c1 |
* When changed/desired parent interface is marked as down or
|
|
Packit Service |
0535c1 |
absent, child state should sync with parent.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.parent and self._ifaces.get(iface.parent):
|
|
Packit Service |
0535c1 |
parent_iface = self._ifaces[iface.parent]
|
|
Packit Service |
0535c1 |
if parent_iface.is_desired or parent_iface.is_changed:
|
|
Packit Service |
0535c1 |
if (
|
|
Packit Service |
0535c1 |
Interface.STATE not in iface.original_dict
|
|
Packit Service |
0535c1 |
or parent_iface.is_down
|
|
Packit Service |
0535c1 |
or parent_iface.is_absent
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
iface.state = parent_iface.state
|
|
Packit Service |
0535c1 |
iface.mark_as_changed()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _mark_orphen_as_absent(self):
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
cd157a |
if (
|
|
Packit Service |
cd157a |
iface.need_parent
|
|
Packit Service |
cd157a |
and (not iface.parent or not self._ifaces.get(iface.parent))
|
|
Packit Service |
cd157a |
and (iface.is_desired or iface.is_changed)
|
|
Packit Service |
0535c1 |
):
|
|
Packit Service |
0535c1 |
iface.mark_as_changed()
|
|
Packit Service |
0535c1 |
iface.state = InterfaceState.ABSENT
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def get(self, iface_name):
|
|
Packit Service |
0535c1 |
return self._ifaces.get(iface_name)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def __getitem__(self, iface_name):
|
|
Packit Service |
0535c1 |
return self._ifaces[iface_name]
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def __setitem__(self, iface_name, iface):
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name] = iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _gen_metadata(self):
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
# Generate metadata for all interface in case any of them
|
|
Packit Service |
0535c1 |
# been marked as changed by DNS/Route/RouteRule.
|
|
Packit Service |
0535c1 |
iface.gen_metadata(self)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def keys(self):
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.keys():
|
|
Packit Service |
0535c1 |
yield iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def values(self):
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
yield iface
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
@property
|
|
Packit Service |
0535c1 |
def current_ifaces(self):
|
|
Packit Service |
0535c1 |
return self._cur_ifaces
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
@property
|
|
Packit Service |
05efbf |
def all_ifaces(self):
|
|
Packit Service |
05efbf |
return self._ifaces
|
|
Packit Service |
05efbf |
|
|
Packit Service |
05efbf |
@property
|
|
Packit Service |
0535c1 |
def state_to_edit(self):
|
|
Packit Service |
0535c1 |
return [
|
|
Packit Service |
0535c1 |
iface.to_dict()
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values()
|
|
Packit Service |
0535c1 |
if iface.is_changed or iface.is_desired
|
|
Packit Service |
0535c1 |
]
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
@property
|
|
Packit Service |
0535c1 |
def cur_ifaces(self):
|
|
Packit Service |
0535c1 |
return self._cur_ifaces
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
bf9017 |
def _remove_unknown_interface_type_slaves(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
c66a53 |
When master containing slaves with unknown interface type or down
|
|
Packit Service |
c66a53 |
state, they should be removed from master slave list before verifying.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.is_up and iface.is_master and iface.slaves:
|
|
Packit Service |
0535c1 |
for slave_name in iface.slaves:
|
|
Packit Service |
0535c1 |
slave_iface = self._ifaces[slave_name]
|
|
Packit Service |
c66a53 |
if (
|
|
Packit Service |
c66a53 |
slave_iface.type == InterfaceType.UNKNOWN
|
|
Packit Service |
c66a53 |
or slave_iface.state != InterfaceState.UP
|
|
Packit Service |
c66a53 |
):
|
|
Packit Service |
0535c1 |
iface.remove_slave(slave_name)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def verify(self, cur_iface_infos):
|
|
Packit Service |
0535c1 |
cur_ifaces = Ifaces(
|
|
Packit Service |
0535c1 |
des_iface_infos=None,
|
|
Packit Service |
0535c1 |
cur_iface_infos=cur_iface_infos,
|
|
Packit Service |
0535c1 |
save_to_disk=self._save_to_disk,
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
bf9017 |
cur_ifaces._remove_unknown_interface_type_slaves()
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.is_desired:
|
|
Packit Service |
0535c1 |
if iface.is_virtual and iface.original_dict.get(
|
|
Packit Service |
0535c1 |
Interface.STATE
|
|
Packit Service |
0535c1 |
) in (InterfaceState.DOWN, InterfaceState.ABSENT):
|
|
Packit Service |
0535c1 |
cur_iface = cur_ifaces.get(iface.name)
|
|
Packit Service |
0535c1 |
if cur_iface:
|
|
Packit Service |
0535c1 |
raise NmstateVerificationError(
|
|
Packit Service |
0535c1 |
format_desired_current_state_diff(
|
|
Packit Service |
0535c1 |
iface.original_dict,
|
|
Packit Service |
0535c1 |
cur_iface.state_for_verify(),
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
elif iface.is_up or (iface.is_down and not iface.is_virtual):
|
|
Packit Service |
0535c1 |
cur_iface = cur_ifaces.get(iface.name)
|
|
Packit Service |
0535c1 |
if not cur_iface:
|
|
Packit Service |
0535c1 |
raise NmstateVerificationError(
|
|
Packit Service |
0535c1 |
format_desired_current_state_diff(
|
|
Packit Service |
0535c1 |
iface.original_dict, {}
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
elif not iface.match(cur_iface):
|
|
Packit Service |
0535c1 |
if iface.type == InterfaceType.LINUX_BRIDGE:
|
|
Packit Service |
0535c1 |
(
|
|
Packit Service |
0535c1 |
key,
|
|
Packit Service |
0535c1 |
value,
|
|
Packit Service |
0535c1 |
cur_value,
|
|
Packit Service |
0535c1 |
) = LinuxBridgeIface.is_integer_rounded(
|
|
Packit Service |
0535c1 |
iface, cur_iface
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
if key:
|
|
Packit Service |
0535c1 |
raise NmstateKernelIntegerRoundedError(
|
|
Packit Service |
0535c1 |
"Linux kernel configured with 250 HZ "
|
|
Packit Service |
0535c1 |
"will round up/down the integer in linux "
|
|
Packit Service |
0535c1 |
f"bridge {iface.name} option '{key}' "
|
|
Packit Service |
0535c1 |
f"from {value} to {cur_value}."
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
raise NmstateVerificationError(
|
|
Packit Service |
0535c1 |
format_desired_current_state_diff(
|
|
Packit Service |
0535c1 |
iface.state_for_verify(),
|
|
Packit Service |
0535c1 |
cur_iface.state_for_verify(),
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
57b08e |
elif (
|
|
Packit Service |
57b08e |
iface.type == InterfaceType.ETHERNET and iface.is_sriov
|
|
Packit Service |
57b08e |
):
|
|
Packit Service |
57b08e |
if not cur_iface.check_total_vfs_matches_vf_list(
|
|
Packit Service |
57b08e |
iface.sriov_total_vfs
|
|
Packit Service |
57b08e |
):
|
|
Packit Service |
57b08e |
raise NmstateVerificationError(
|
|
Packit Service |
57b08e |
"The NIC exceeded the waiting time for "
|
|
Packit Service |
57b08e |
"verification and it is failing because "
|
|
Packit Service |
57b08e |
"the `total_vfs` does not match the VF "
|
|
Packit Service |
57b08e |
"list length."
|
|
Packit Service |
57b08e |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def gen_dns_metadata(self, dns_state, route_state):
|
|
Packit Service |
0535c1 |
iface_metadata = dns_state.gen_metadata(self, route_state)
|
|
Packit Service |
0535c1 |
for iface_name, dns_metadata in iface_metadata.items():
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].store_dns_metadata(dns_metadata)
|
|
Packit Service |
0535c1 |
if dns_state.config_changed:
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].mark_as_changed()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def gen_route_metadata(self, route_state):
|
|
Packit Service |
0535c1 |
iface_metadata = route_state.gen_metadata(self)
|
|
Packit Service |
0535c1 |
for iface_name, route_metadata in iface_metadata.items():
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].store_route_metadata(route_metadata)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def gen_route_rule_metadata(self, route_rule_state, route_state):
|
|
Packit Service |
0535c1 |
iface_metadata = route_rule_state.gen_metadata(route_state)
|
|
Packit Service |
0535c1 |
for iface_name, route_rule_metadata in iface_metadata.items():
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].store_route_rule_metadata(
|
|
Packit Service |
0535c1 |
route_rule_metadata
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
if route_rule_state.config_changed:
|
|
Packit Service |
0535c1 |
self._ifaces[iface_name].mark_as_changed()
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _validate_unknown_slaves(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Check the existance of slave interface
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
for slave_name in iface.slaves:
|
|
Packit Service |
0535c1 |
if not self._ifaces.get(slave_name):
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} has unknown slave: "
|
|
Packit Service |
0535c1 |
f"{slave_name}"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _validate_unknown_parent(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Check the existance of parent interface
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
0535c1 |
if iface.parent and not self._ifaces.get(iface.parent):
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} has unknown parent: "
|
|
Packit Service |
0535c1 |
f"{iface.parent}"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _remove_unknown_type_interfaces(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Remove unknown type interfaces that are set as up.
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
for iface in list(self._ifaces.values()):
|
|
Packit Service |
0535c1 |
if iface.type == InterfaceType.UNKNOWN and iface.is_up:
|
|
Packit Service |
0535c1 |
self._ifaces.pop(iface.name, None)
|
|
Packit Service |
0535c1 |
logging.debug(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} is type {iface.type} and "
|
|
Packit Service |
0535c1 |
"will be ignored during the activation"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _validate_over_booked_slaves(self):
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
Check whether any slave is used by more than one master
|
|
Packit Service |
0535c1 |
"""
|
|
Packit Service |
0535c1 |
slave_master_map = {}
|
|
Packit Service |
0535c1 |
for iface in self._ifaces.values():
|
|
Packit Service |
99fff9 |
if not (iface.is_changed or iface.is_desired) or not iface.is_up:
|
|
Packit Service |
99fff9 |
continue
|
|
Packit Service |
0535c1 |
for slave_name in iface.slaves:
|
|
Packit Service |
0535c1 |
cur_master = slave_master_map.get(slave_name)
|
|
Packit Service |
0535c1 |
if cur_master:
|
|
Packit Service |
0535c1 |
cur_master_iface = self._ifaces.get(cur_master)
|
|
Packit Service |
0535c1 |
if cur_master_iface and not cur_master_iface.is_absent:
|
|
Packit Service |
0535c1 |
raise NmstateValueError(
|
|
Packit Service |
0535c1 |
f"Interface {iface.name} slave {slave_name} is "
|
|
Packit Service |
0535c1 |
f"already enslaved by interface {cur_master}"
|
|
Packit Service |
0535c1 |
)
|
|
Packit Service |
0535c1 |
else:
|
|
Packit Service |
0535c1 |
slave_master_map[slave_name] = iface.name
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
|
|
Packit Service |
0535c1 |
def _to_specific_iface_obj(info, save_to_disk):
|
|
Packit Service |
0535c1 |
iface_type = info.get(Interface.TYPE, InterfaceType.UNKNOWN)
|
|
Packit Service |
0535c1 |
if iface_type == InterfaceType.ETHERNET:
|
|
Packit Service |
0535c1 |
return EthernetIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.BOND:
|
|
Packit Service |
0535c1 |
return BondIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.DUMMY:
|
|
Packit Service |
0535c1 |
return DummyIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.LINUX_BRIDGE:
|
|
Packit Service |
0535c1 |
return LinuxBridgeIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.OVS_BRIDGE:
|
|
Packit Service |
0535c1 |
return OvsBridgeIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.OVS_INTERFACE:
|
|
Packit Service |
0535c1 |
return OvsInternalIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.VLAN:
|
|
Packit Service |
0535c1 |
return VlanIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.VXLAN:
|
|
Packit Service |
0535c1 |
return VxlanIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
elif iface_type == InterfaceType.TEAM:
|
|
Packit Service |
0535c1 |
return TeamIface(info, save_to_disk)
|
|
Packit Service |
0535c1 |
else:
|
|
Packit Service |
0535c1 |
return BaseIface(info, save_to_disk)
|