246 lines
9.0 KiB
Diff
246 lines
9.0 KiB
Diff
|
From 9f505f21b90cf122539fbe9bc3bf78ef170f5c12 Mon Sep 17 00:00:00 2001
|
||
|
From: Gris Ge <fge@redhat.com>
|
||
|
Date: Tue, 6 Jul 2021 11:53:55 +0800
|
||
|
Subject: [PATCH] nm ovs: Fix OVS bridge and interface using the same name
|
||
|
|
||
|
Nmstate will fail on verification when setting ip to OVS interface
|
||
|
sharing the same name with OVS bridge.
|
||
|
|
||
|
This is caused by NM plugin does not index with interface type when
|
||
|
retrieving interface applied configure which lead to OVS bridge or OVS
|
||
|
interface applied configure overlapping each other.
|
||
|
|
||
|
To fix this problem, we use `NetworkManagerPlugin._kernel_nic_applied_configs`
|
||
|
and `NetworkManagerPlugin._userspace_nic_applied_configs()` to
|
||
|
differentiate them. The kernel data is still indexed by interface name,
|
||
|
the user space data is indexed by interface name and type.
|
||
|
|
||
|
Integration test case included as tier 1 as OpenShift need it.
|
||
|
|
||
|
Signed-off-by: Gris Ge <fge@redhat.com>
|
||
|
---
|
||
|
libnmstate/nm/device.py | 8 +++++
|
||
|
libnmstate/nm/plugin.py | 61 ++++++++++++++++++++++++++-------------
|
||
|
libnmstate/nm/profiles.py | 38 ++++++++++++++++++++----
|
||
|
3 files changed, 81 insertions(+), 26 deletions(-)
|
||
|
|
||
|
diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py
|
||
|
index 3c58bae..4c97733 100644
|
||
|
--- a/libnmstate/nm/device.py
|
||
|
+++ b/libnmstate/nm/device.py
|
||
|
@@ -198,3 +198,11 @@ def get_nm_dev(ctx, iface_name, iface_type):
|
||
|
):
|
||
|
return nm_dev
|
||
|
return None
|
||
|
+
|
||
|
+
|
||
|
+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_PORT,
|
||
|
+ )
|
||
|
diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py
|
||
|
index da933b3..9c774e5 100644
|
||
|
--- a/libnmstate/nm/plugin.py
|
||
|
+++ b/libnmstate/nm/plugin.py
|
||
|
@@ -36,6 +36,7 @@ from .common import NM
|
||
|
from .context import NmContext
|
||
|
from .device import get_device_common_info
|
||
|
from .device import get_iface_type
|
||
|
+from .device import is_kernel_iface
|
||
|
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
|
||
|
@@ -63,7 +64,8 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
def __init__(self):
|
||
|
self._ctx = None
|
||
|
self._checkpoint = None
|
||
|
- self.__applied_configs = None
|
||
|
+ self.__kernel_nic_applied_configs = None
|
||
|
+ self.__userspace_nic_applied_configs = None
|
||
|
|
||
|
@property
|
||
|
def priority(self):
|
||
|
@@ -79,10 +81,28 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
self._ctx = None
|
||
|
|
||
|
@property
|
||
|
- def _applied_configs(self):
|
||
|
- if self.__applied_configs is None:
|
||
|
- self.__applied_configs = get_all_applied_configs(self.context)
|
||
|
- return self.__applied_configs
|
||
|
+ def _kernel_nic_applied_configs(self):
|
||
|
+ if (
|
||
|
+ self.__kernel_nic_applied_configs is None
|
||
|
+ or self.__userspace_nic_applied_configs is None
|
||
|
+ ):
|
||
|
+ (
|
||
|
+ self.__kernel_nic_applied_configs,
|
||
|
+ self.__userspace_nic_applied_configs,
|
||
|
+ ) = get_all_applied_configs(self.context)
|
||
|
+ return self.__kernel_nic_applied_configs
|
||
|
+
|
||
|
+ @property
|
||
|
+ def _userspace_nic_applied_configs(self):
|
||
|
+ if (
|
||
|
+ self.__kernel_nic_applied_configs is None
|
||
|
+ or self.__userspace_nic_applied_configs is None
|
||
|
+ ):
|
||
|
+ (
|
||
|
+ self.__kernel_nic_applied_configs,
|
||
|
+ self.__userspace_nic_applied_configs,
|
||
|
+ ) = get_all_applied_configs(self.context)
|
||
|
+ return self.__userspace_nic_applied_configs
|
||
|
|
||
|
@property
|
||
|
def checkpoint(self):
|
||
|
@@ -120,8 +140,6 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
def get_interfaces(self):
|
||
|
info = []
|
||
|
|
||
|
- applied_configs = self._applied_configs
|
||
|
-
|
||
|
devices_info = [
|
||
|
(dev, get_device_common_info(dev))
|
||
|
for dev in list_devices(self.client)
|
||
|
@@ -131,6 +149,16 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
if not dev.get_managed():
|
||
|
# Skip unmanaged interface
|
||
|
continue
|
||
|
+ if is_kernel_iface(dev):
|
||
|
+ applied_config = self._kernel_nic_applied_configs.get(
|
||
|
+ dev.get_iface()
|
||
|
+ )
|
||
|
+ else:
|
||
|
+ iface_type = get_iface_type(dev)
|
||
|
+ applied_config = self._userspace_nic_applied_configs.get(
|
||
|
+ f"{dev.get_iface()}{iface_type}"
|
||
|
+ )
|
||
|
+
|
||
|
nm_ac = dev.get_active_connection()
|
||
|
if (
|
||
|
nm_ac
|
||
|
@@ -140,7 +168,6 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
continue
|
||
|
|
||
|
iface_info = Nm2Api.get_common_device_info(devinfo)
|
||
|
- applied_config = applied_configs.get(iface_info[Interface.NAME])
|
||
|
|
||
|
act_con = dev.get_active_connection()
|
||
|
iface_info[Interface.IPV4] = get_ipv4_info(act_con, applied_config)
|
||
|
@@ -193,11 +220,14 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
def get_dns_client_config(self):
|
||
|
return {
|
||
|
DNS.RUNNING: get_dns_running(self.client),
|
||
|
- DNS.CONFIG: get_dns_running_config(self._applied_configs),
|
||
|
+ DNS.CONFIG: get_dns_running_config(
|
||
|
+ self._kernel_nic_applied_configs
|
||
|
+ ),
|
||
|
}
|
||
|
|
||
|
def refresh_content(self):
|
||
|
- self.__applied_configs = None
|
||
|
+ self.__kernel_nic_applied_configs = None
|
||
|
+ self.__userspace_nic_applied_configs = None
|
||
|
|
||
|
def apply_changes(self, net_state, save_to_disk):
|
||
|
NmProfiles(self.context).apply_config(net_state, save_to_disk)
|
||
|
@@ -278,7 +308,7 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||
|
nm_dev
|
||
|
and nm_dev.get_iface()
|
||
|
and not nm_dev.get_managed()
|
||
|
- and _is_kernel_iface(nm_dev)
|
||
|
+ and is_kernel_iface(nm_dev)
|
||
|
):
|
||
|
ignored_ifaces.add(nm_dev.get_iface())
|
||
|
return list(ignored_ifaces)
|
||
|
@@ -298,12 +328,3 @@ 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/nm/profiles.py b/libnmstate/nm/profiles.py
|
||
|
index 905a6c8..90e0e70 100644
|
||
|
--- a/libnmstate/nm/profiles.py
|
||
|
+++ b/libnmstate/nm/profiles.py
|
||
|
@@ -27,7 +27,9 @@ from libnmstate.schema import InterfaceType
|
||
|
from .common import NM
|
||
|
from .device import is_externally_managed
|
||
|
from .device import list_devices
|
||
|
+from .device import get_iface_type
|
||
|
from .device import get_nm_dev
|
||
|
+from .device import is_kernel_iface
|
||
|
from .dns import get_dns_config_iface_names
|
||
|
from .ipv4 import acs_and_ip_profiles as acs_and_ip4_profiles
|
||
|
from .ipv6 import acs_and_ip_profiles as acs_and_ip6_profiles
|
||
|
@@ -129,7 +131,13 @@ def _append_nm_ovs_port_iface(net_state):
|
||
|
|
||
|
|
||
|
def get_all_applied_configs(context):
|
||
|
- applied_configs = {}
|
||
|
+ """
|
||
|
+ Return two dictionaries.
|
||
|
+ First one for kernel interface with interface name as key.
|
||
|
+ Second one for user space interface with interface name and type as key.
|
||
|
+ """
|
||
|
+ kernel_nic_applied_configs = {}
|
||
|
+ userspace_nic_applid_configs = {}
|
||
|
for nm_dev in list_devices(context.client):
|
||
|
if (
|
||
|
nm_dev.get_state()
|
||
|
@@ -150,19 +158,37 @@ def get_all_applied_configs(context):
|
||
|
flags=0,
|
||
|
cancellable=context.cancellable,
|
||
|
callback=_get_applied_config_callback,
|
||
|
- user_data=(iface_name, action, applied_configs, context),
|
||
|
+ user_data=(
|
||
|
+ iface_name,
|
||
|
+ action,
|
||
|
+ kernel_nic_applied_configs,
|
||
|
+ userspace_nic_applid_configs,
|
||
|
+ context,
|
||
|
+ ),
|
||
|
)
|
||
|
context.wait_all_finish()
|
||
|
- return applied_configs
|
||
|
+ return kernel_nic_applied_configs, userspace_nic_applid_configs
|
||
|
|
||
|
|
||
|
def _get_applied_config_callback(nm_dev, result, user_data):
|
||
|
- iface_name, action, applied_configs, context = user_data
|
||
|
+ (
|
||
|
+ iface_name,
|
||
|
+ action,
|
||
|
+ kernel_nic_applied_configs,
|
||
|
+ userspace_nic_applid_configs,
|
||
|
+ context,
|
||
|
+ ) = user_data
|
||
|
context.finish_async(action)
|
||
|
try:
|
||
|
+ iface_name = nm_dev.get_iface()
|
||
|
remote_conn, _ = nm_dev.get_applied_connection_finish(result)
|
||
|
- # TODO: We should use both interface name and type as key below.
|
||
|
- applied_configs[nm_dev.get_iface()] = remote_conn
|
||
|
+ if is_kernel_iface(nm_dev):
|
||
|
+ kernel_nic_applied_configs[iface_name] = remote_conn
|
||
|
+ else:
|
||
|
+ iface_type = get_iface_type(nm_dev)
|
||
|
+ userspace_nic_applid_configs[
|
||
|
+ f"{iface_name}{iface_type}"
|
||
|
+ ] = remote_conn
|
||
|
except Exception as e:
|
||
|
logging.warning(
|
||
|
"Failed to retrieve applied config for device "
|
||
|
--
|
||
|
2.32.0
|
||
|
|