224 lines
8.3 KiB
Diff
224 lines
8.3 KiB
Diff
From ccdcd8f86544a6364109a0c0142d05a5afacf64e Mon Sep 17 00:00:00 2001
|
|
From: Gris Ge <fge@redhat.com>
|
|
Date: Tue, 2 Mar 2021 15:31:20 +0800
|
|
Subject: [PATCH] nm: Don't touch unmanaged interface unless desired
|
|
|
|
We should ignore NetworkManager unmanaged interface when applying and
|
|
verifying unless certain interface listed in desired state explicitly.
|
|
|
|
Introduced new plugin interface
|
|
`NmstatePlugin.get_ignored_kernel_interface_names()` where plugin may
|
|
include a list of interface names which should be ignored during
|
|
verification stage.
|
|
|
|
Integration test case added to simulate CNV usage on partial editing
|
|
a linux bridge holding NM unmanaged interface.
|
|
|
|
Signed-off-by: Gris Ge <fge@redhat.com>
|
|
---
|
|
libnmstate/ifaces/base_iface.py | 3 ++
|
|
libnmstate/ifaces/ifaces.py | 26 ++++++++--------
|
|
libnmstate/netapplier.py | 6 ++++
|
|
libnmstate/nispor/plugin.py | 6 +++-
|
|
libnmstate/nm/plugin.py | 25 ++++++++++++++++
|
|
libnmstate/plugin.py | 7 +++++
|
|
tests/integration/linux_bridge_test.py | 8 +----
|
|
tests/integration/nm/linux_bridge_test.py | 36 ++++++++++++++++++++++-
|
|
8 files changed, 95 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
|
|
index 227c1d20..e3f2a1ca 100644
|
|
--- a/libnmstate/ifaces/base_iface.py
|
|
+++ b/libnmstate/ifaces/base_iface.py
|
|
@@ -322,6 +322,9 @@ class BaseIface:
|
|
def mark_as_up(self):
|
|
self.raw[Interface.STATE] = InterfaceState.UP
|
|
|
|
+ def mark_as_ignored(self):
|
|
+ self.raw[Interface.STATE] = InterfaceState.IGNORE
|
|
+
|
|
@property
|
|
def is_controller(self):
|
|
return False
|
|
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
|
index 6c94a986..efa24aa3 100644
|
|
--- a/libnmstate/ifaces/ifaces.py
|
|
+++ b/libnmstate/ifaces/ifaces.py
|
|
@@ -95,7 +95,6 @@ class Ifaces:
|
|
self._kernel_ifaces = {}
|
|
self._user_space_ifaces = _UserSpaceIfaces()
|
|
self._cur_user_space_ifaces = _UserSpaceIfaces()
|
|
- self._ignored_ifaces = set()
|
|
if cur_iface_infos:
|
|
for iface_info in cur_iface_infos:
|
|
cur_iface = _to_specific_iface_obj(iface_info, save_to_disk)
|
|
@@ -143,10 +142,6 @@ class Ifaces:
|
|
):
|
|
# Ignore interface with unknown type
|
|
continue
|
|
- if iface.is_ignore:
|
|
- self._ignored_ifaces.add(
|
|
- (iface.name, iface.type, iface.is_user_space_only)
|
|
- )
|
|
if cur_iface:
|
|
iface.merge(cur_iface)
|
|
iface.mark_as_desired()
|
|
@@ -169,6 +164,10 @@ class Ifaces:
|
|
|
|
self._pre_edit_validation_and_cleanup()
|
|
|
|
+ @property
|
|
+ def _ignored_ifaces(self):
|
|
+ return [iface for iface in self.all_ifaces() if iface.is_ignore]
|
|
+
|
|
def _apply_copy_mac_from(self):
|
|
for iface in self.all_kernel_ifaces.values():
|
|
if iface.type not in (
|
|
@@ -284,7 +283,7 @@ class Ifaces:
|
|
if not defiend in desire state
|
|
"""
|
|
for iface in self.all_ifaces():
|
|
- if iface.is_up and iface.is_controller:
|
|
+ if iface.is_desired and iface.is_up and iface.is_controller:
|
|
for port_name in iface.port:
|
|
port_iface = self._kernel_ifaces[port_name]
|
|
if not port_iface.is_desired and not port_iface.is_up:
|
|
@@ -550,13 +549,14 @@ class Ifaces:
|
|
return None
|
|
|
|
def _remove_iface(self, iface_name, iface_type):
|
|
- cur_iface = self._cur_kernel_ifaces.get(iface_name, iface_type)
|
|
+ cur_iface = self._user_space_ifaces.get(iface_name, iface_type)
|
|
if cur_iface:
|
|
self._user_space_ifaces.remove(cur_iface)
|
|
else:
|
|
cur_iface = self._kernel_ifaces.get(iface_name)
|
|
if (
|
|
- iface_type
|
|
+ cur_iface
|
|
+ and iface_type
|
|
and iface_type != InterfaceType.UNKNOWN
|
|
and iface_type == cur_iface.type
|
|
):
|
|
@@ -813,14 +813,14 @@ class Ifaces:
|
|
port_controller_map[port_name] = iface.name
|
|
|
|
def _remove_ignore_interfaces(self, ignored_ifaces):
|
|
- for iface_name, iface_type, _ in ignored_ifaces:
|
|
- self._remove_iface(iface_name, iface_type)
|
|
+ for iface in ignored_ifaces:
|
|
+ self._remove_iface(iface.name, iface.type)
|
|
|
|
# Only kernel interface can be used as port
|
|
ignored_kernel_iface_names = set(
|
|
- iface_name
|
|
- for iface_name, _, is_user_space_only in ignored_ifaces
|
|
- if not is_user_space_only
|
|
+ iface.name
|
|
+ for iface in ignored_ifaces
|
|
+ if not iface.is_user_space_only
|
|
)
|
|
|
|
# Remove ignored port
|
|
diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py
|
|
index 3c5759b4..a020f003 100644
|
|
--- a/libnmstate/netapplier.py
|
|
+++ b/libnmstate/netapplier.py
|
|
@@ -107,8 +107,14 @@ def rollback(*, checkpoint=None):
|
|
|
|
|
|
def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk):
|
|
+ for plugin in plugins:
|
|
+ for iface_name in plugin.get_ignored_kernel_interface_names():
|
|
+ iface = net_state.ifaces.all_kernel_ifaces.get(iface_name)
|
|
+ if iface and not iface.is_desired:
|
|
+ iface.mark_as_ignored()
|
|
for plugin in plugins:
|
|
plugin.apply_changes(net_state, save_to_disk)
|
|
+
|
|
verified = False
|
|
if verify_change:
|
|
if _net_state_contains_sriov_interface(net_state):
|
|
diff --git a/libnmstate/nispor/plugin.py b/libnmstate/nispor/plugin.py
|
|
index dc0ea760..19b21d56 100644
|
|
--- a/libnmstate/nispor/plugin.py
|
|
+++ b/libnmstate/nispor/plugin.py
|
|
@@ -159,7 +159,11 @@ class NisporPlugin(NmstatePlugin):
|
|
np_state = NisporNetState.retrieve()
|
|
logging.debug(f"Nispor: current network state {np_state}")
|
|
for iface in net_state.ifaces.all_ifaces():
|
|
- if iface.is_desired:
|
|
+ if iface.is_ignore:
|
|
+ logging.debug(
|
|
+ f"Nispor: Interface {iface.name} {iface.type} ignored"
|
|
+ )
|
|
+ elif iface.is_desired:
|
|
logging.debug(
|
|
f"Nispor: desired network state {iface.to_dict()}"
|
|
)
|
|
diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py
|
|
index 302b4cca..335d93c7 100644
|
|
--- a/libnmstate/nm/plugin.py
|
|
+++ b/libnmstate/nm/plugin.py
|
|
@@ -36,6 +36,7 @@ from .checkpoint import get_checkpoints
|
|
from .common import NM
|
|
from .context import NmContext
|
|
from .device import get_device_common_info
|
|
+from .device import get_iface_type
|
|
from .device import list_devices
|
|
from .dns import get_running as get_dns_running
|
|
from .dns import get_running_config as get_dns_running_config
|
|
@@ -268,6 +269,21 @@ class NetworkManagerPlugin(NmstatePlugin):
|
|
)
|
|
return NmProfiles(None).generate_config_strings(net_state)
|
|
|
|
+ def get_ignored_kernel_interface_names(self):
|
|
+ """
|
|
+ Return a list of unmanged kernel interface names.
|
|
+ """
|
|
+ ignored_ifaces = set()
|
|
+ for nm_dev in list_devices(self.client):
|
|
+ if (
|
|
+ nm_dev
|
|
+ and nm_dev.get_iface()
|
|
+ and not nm_dev.get_managed()
|
|
+ and _is_kernel_iface(nm_dev)
|
|
+ ):
|
|
+ ignored_ifaces.add(nm_dev.get_iface())
|
|
+ return list(ignored_ifaces)
|
|
+
|
|
|
|
def _remove_ovs_bridge_unsupported_entries(iface_info):
|
|
"""
|
|
@@ -283,3 +299,12 @@ def _remove_ovs_bridge_unsupported_entries(iface_info):
|
|
|
|
def _nm_utils_decode_version():
|
|
return f"{NM.MAJOR_VERSION}.{NM.MINOR_VERSION}.{NM.MICRO_VERSION}"
|
|
+
|
|
+
|
|
+def _is_kernel_iface(nm_dev):
|
|
+ iface_type = get_iface_type(nm_dev)
|
|
+ return iface_type != InterfaceType.UNKNOWN and iface_type not in (
|
|
+ InterfaceType.OVS_BRIDGE,
|
|
+ InterfaceType.OVS_INTERFACE,
|
|
+ InterfaceType.OVS_PORT,
|
|
+ )
|
|
diff --git a/libnmstate/plugin.py b/libnmstate/plugin.py
|
|
index ef3874ff..e1d9ad58 100644
|
|
--- a/libnmstate/plugin.py
|
|
+++ b/libnmstate/plugin.py
|
|
@@ -128,3 +128,10 @@ class NmstatePlugin(metaclass=ABCMeta):
|
|
persistently.
|
|
"""
|
|
return []
|
|
+
|
|
+ def get_ignored_kernel_interface_names(self):
|
|
+ """
|
|
+ Return a list of kernel interface names which should be ignored
|
|
+ during verification stage.
|
|
+ """
|
|
+ return []
|
|
--
|
|
2.29.2
|
|
|