nmstate/SOURCES/BZ_1979220_static_ip_on_ovs...

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