import nmstate-1.0.2-14.el8_4

This commit is contained in:
CentOS Sources 2021-08-10 08:02:42 -04:00 committed by Andrew Lukoshko
parent 238501763b
commit 1bb48d27a3
5 changed files with 573 additions and 1 deletions

View File

@ -0,0 +1,245 @@
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

View File

@ -0,0 +1,125 @@
From 61e775a19652ff1b17581e53367f05921304edfb Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Thu, 10 Jun 2021 14:55:33 +0200
Subject: [PATCH 1/2] SR-IOV: Fix BCM57416 failure when creating VFs
Currently there is not a way to see the relation between a SR-IOV PF and
its VFs. Broadcom BCM57416 follows a different name pattern for PF and
VF, therefore it needs to be parsed if present.
PF name: ens2f0np0
VF name: ens2f0v0
The different name pattern is due to:
1. The `n` is for `multi-port PCI device` support.
2. The `p*` is `phys_port_name` provided by the BCM driver `bnxt_en`.
Ref: https://bugzilla.redhat.com/1959679
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
libnmstate/ifaces/ethernet.py | 38 ++++++++++++++++++++++++++++++++---
libnmstate/nm/profiles.py | 8 ++++++++
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
index 55772ce..a47a718 100644
--- a/libnmstate/ifaces/ethernet.py
+++ b/libnmstate/ifaces/ethernet.py
@@ -25,6 +25,11 @@ from libnmstate.schema import InterfaceState
from .base_iface import BaseIface
+BNXT_DRIVER_PHYS_PORT_PREFIX = "p"
+MULTIPORT_PCI_DEVICE_PREFIX = "n"
+IS_GENERATED_VF_METADATA = "_is_generated_vf"
+
+
class EthernetIface(BaseIface):
def __init__(self, info, save_to_disk=True):
super().__init__(info, save_to_disk)
@@ -80,21 +85,48 @@ class EthernetIface(BaseIface):
)
def create_sriov_vf_ifaces(self):
- return [
+ # Currently there is not a way to see the relation between a SR-IOV PF
+ # and its VFs. Broadcom BCM57416 follows a different name pattern for
+ # PF and VF, therefore it needs to be parsed if present.
+ #
+ # PF name: ens2f0np0
+ # VF name: ens2f0v0
+ #
+ # The different name pattern is due to:
+ # 1. The `n` is for `multi-port PCI device` support.
+ # 2. The `p*` is `phys_port_name` provided by the BCM driver
+ # `bnxt_en`.
+ #
+ # If the NIC is following the standard pattern "pfname+v+vfid", this
+ # split will not touch it and the vf_pattern will be the PF name.
+ # Ref: https://bugzilla.redhat.com/1959679
+ vf_pattern = self.name
+ multiport_pattern = (
+ MULTIPORT_PCI_DEVICE_PREFIX + BNXT_DRIVER_PHYS_PORT_PREFIX
+ )
+ if len(self.name.split(multiport_pattern)) == 2:
+ vf_pattern = self.name.split(multiport_pattern)[0]
+
+ vf_ifaces = [
EthernetIface(
{
# According to manpage of systemd.net-naming-scheme(7),
# SRIOV VF interface will have v{slot} in device name.
# Currently, nmstate has no intention to support
# user-defined udev rule on SRIOV interface naming policy.
- Interface.NAME: f"{self.name}v{i}",
+ Interface.NAME: f"{vf_pattern}v{i}",
Interface.TYPE: InterfaceType.ETHERNET,
- # VF will be in DOWN state initialy.
+ # VF will be in DOWN state initialy
Interface.STATE: InterfaceState.DOWN,
}
)
for i in range(0, self.sriov_total_vfs)
]
+ # The generated vf metadata cannot be part of the original dict.
+ for vf in vf_ifaces:
+ vf._info[IS_GENERATED_VF_METADATA] = True
+
+ return vf_ifaces
def remove_vfs_entry_when_total_vfs_decreased(self):
vfs_count = len(
diff --git a/libnmstate/nm/profiles.py b/libnmstate/nm/profiles.py
index 90e0e70..ec3ef70 100644
--- a/libnmstate/nm/profiles.py
+++ b/libnmstate/nm/profiles.py
@@ -40,6 +40,9 @@ from .veth import create_iface_for_nm_veth_peer
from .veth import is_nm_veth_supported
+IS_GENERATED_VF_METADATA = "_is_generated_vf"
+
+
class NmProfiles:
def __init__(self, context):
self._ctx = context
@@ -63,6 +66,7 @@ class NmProfiles:
all_profiles = [
NmProfile(self._ctx, iface)
for iface in net_state.ifaces.all_ifaces()
+ if not _is_only_for_verify(iface)
]
for profile in all_profiles:
@@ -409,3 +413,7 @@ def _nm_ovs_port_has_child(nm_profile, ovs_bridge_iface, net_state):
):
return True
return False
+
+
+def _is_only_for_verify(iface):
+ return iface.to_dict().get(IS_GENERATED_VF_METADATA)
--
2.31.1

View File

@ -0,0 +1,103 @@
From 55d5092c04a974985c4db8609c73d6b92a674cae Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Thu, 8 Jul 2021 15:49:48 +0800
Subject: [PATCH 2/2] ovs: Regenerate iface metadata after RouteRule metadata
generation
When desire state only contain route rule for OVS interface route table
ID, NetworkManager will complains:
A connection with a 'ovs-interface' setting must have a master.
The root cause is because interface metadata is not generated if desire
state has no interface at all.
The fix is regenerate interface metadata on changed/desired interface
after route rule metadata generation.
Integration test case added and marked as tier1 due to RHV requirement.
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/ifaces/base_iface.py | 5 ++--
libnmstate/ifaces/ifaces.py | 4 ++--
libnmstate/ifaces/linux_bridge.py | 8 +++++--
libnmstate/net_state.py | 3 +++
tests/integration/ovs_test.py | 40 +++++++++++++++++++++++++++++++
5 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
index e3f2a1c..a76491e 100644
--- a/libnmstate/ifaces/base_iface.py
+++ b/libnmstate/ifaces/base_iface.py
@@ -350,8 +350,9 @@ class BaseIface:
def gen_metadata(self, ifaces):
if self.is_controller and not self.is_absent:
for port_name in self.port:
- port_iface = ifaces.all_kernel_ifaces[port_name]
- port_iface.set_controller(self.name, self.type)
+ port_iface = ifaces.all_kernel_ifaces.get(port_name)
+ if port_iface:
+ port_iface.set_controller(self.name, self.type)
def update(self, info):
self._info.update(info)
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
index efa24aa..c240abd 100644
--- a/libnmstate/ifaces/ifaces.py
+++ b/libnmstate/ifaces/ifaces.py
@@ -158,7 +158,7 @@ class Ifaces:
self._validate_infiniband_as_bridge_port()
self._validate_infiniband_as_bond_port()
self._apply_copy_mac_from()
- self._gen_metadata()
+ self.gen_metadata()
for iface in self.all_ifaces():
iface.pre_edit_validation_and_cleanup()
@@ -569,7 +569,7 @@ class Ifaces:
else:
self._kernel_ifaces[iface.name] = iface
- def _gen_metadata(self):
+ def gen_metadata(self):
for iface in self.all_ifaces():
# Generate metadata for all interface in case any of them
# been marked as changed by DNS/Route/RouteRule.
diff --git a/libnmstate/ifaces/linux_bridge.py b/libnmstate/ifaces/linux_bridge.py
index bc7768f..09d68cb 100644
--- a/libnmstate/ifaces/linux_bridge.py
+++ b/libnmstate/ifaces/linux_bridge.py
@@ -125,9 +125,13 @@ class LinuxBridgeIface(BridgeIface):
super().gen_metadata(ifaces)
if not self.is_absent:
for port_config in self.port_configs:
- ifaces.all_kernel_ifaces[
+ port_iface = ifaces.all_kernel_ifaces.get(
port_config[LinuxBridge.Port.NAME]
- ].update({BridgeIface.BRPORT_OPTIONS_METADATA: port_config})
+ )
+ if port_iface:
+ port_iface.update(
+ {BridgeIface.BRPORT_OPTIONS_METADATA: port_config}
+ )
def remove_port(self, port_name):
if self._bridge_config:
diff --git a/libnmstate/net_state.py b/libnmstate/net_state.py
index 713b7dc..780981c 100644
--- a/libnmstate/net_state.py
+++ b/libnmstate/net_state.py
@@ -72,6 +72,9 @@ class NetState:
self._ifaces.gen_dns_metadata(self._dns, self._route)
self._ifaces.gen_route_metadata(self._route)
self._ifaces.gen_route_rule_metadata(self._route_rule, self._route)
+ # DND/Route/RouteRule might introduced new changed interface
+ # Regnerate interface metadata
+ self._ifaces.gen_metadata()
def _mark_ignored_kernel_ifaces(self, ignored_ifnames):
for iface_name in ignored_ifnames:
--
2.31.1

View File

@ -0,0 +1,85 @@
From ab55d90e31a121f1cb18d79582a8f4d2a138df91 Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Mon, 26 Jul 2021 16:13:15 +0200
Subject: [PATCH] nispor: fix show of empty next_hop_address and destination
The correct way of representing an empty next_hop_address is using
"0.0.0.0" for IPv4 and "::" for IPv6. This configuration is valid
because an user should be able to specify the following routes:
```
---
routes:
config:
- destination: 0.0.0.0/0
next-hop-address: 0.0.0.0
next-hop-interface: dummy
- destination: ::/0
next-hop-address: "::"
next-hop-interface: dummy
```
That means each of the hosts within the range of the route are
considered to be directly connected through that interface.
For example, using iproute2 the user should introduce the following
command:
`ip route 0.0.0.0 0.0.0.0 dummy`
Integration test case added.
Ref: https://bugzilla.redhat.com/1985879
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
libnmstate/nispor/route.py | 13 +++++++++----
tests/integration/route_test.py | 30 +++++++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/libnmstate/nispor/route.py b/libnmstate/nispor/route.py
index 510ddc3..9852ba5 100644
--- a/libnmstate/nispor/route.py
+++ b/libnmstate/nispor/route.py
@@ -23,6 +23,9 @@ from libnmstate.schema import Route
IPV4_DEFAULT_GATEWAY_DESTINATION = "0.0.0.0/0"
IPV6_DEFAULT_GATEWAY_DESTINATION = "::/0"
+IPV4_EMPTY_NEXT_HOP_ADDRESS = "0.0.0.0"
+IPV6_EMPTY_NEXT_HOP_ADDRESS = "::"
+
LOCAL_ROUTE_TABLE = 255
@@ -50,21 +53,23 @@ def nispor_route_state_to_nmstate_static(np_routes):
def _nispor_route_to_nmstate(np_rt):
if np_rt.dst:
destination = np_rt.dst
- elif np_rt.gateway:
+ else:
destination = (
IPV6_DEFAULT_GATEWAY_DESTINATION
if np_rt.address_family == "ipv6"
else IPV4_DEFAULT_GATEWAY_DESTINATION
)
- else:
- destination = ""
if np_rt.via:
next_hop = np_rt.via
elif np_rt.gateway:
next_hop = np_rt.gateway
else:
- next_hop = ""
+ next_hop = (
+ IPV6_EMPTY_NEXT_HOP_ADDRESS
+ if np_rt.address_family == "ipv6"
+ else IPV4_EMPTY_NEXT_HOP_ADDRESS
+ )
return {
Route.TABLE_ID: np_rt.table,
--
2.31.1

View File

@ -4,7 +4,7 @@
Name: nmstate
Version: 1.0.2
Release: 11%{?dist}
Release: 14%{?dist}
Summary: Declarative network manager API
License: LGPLv2+
URL: https://github.com/%{srcname}/%{srcname}
@ -21,6 +21,10 @@ Patch7: BZ_1964440-nm-ipv4-Deactivate-profile-when-route-removed.patch
Patch8: BZ_1966379_fix_bond_opt_tlb_dynamic_lb.patch
Patch9: BZ_1966457_Fix_bond_fail_over_mac.patch
Patch10: BZ_1966457_only_validate_desired_bond.patch
Patch11: BZ_1979220_static_ip_on_ovs_same_name.patch
Patch12: BZ_1979515-SR-IOV-Fix-BCM57416-failure-when-creating-VFs.patch
Patch13: BZ_1979943-ovs-Regenerate-iface-metadata-after-RouteRule-metada.patch
Patch14: BZ_1986285-nispor-fix-show-of-empty-next_hop_address-and-destin.patch
BuildArch: noarch
BuildRequires: python3-devel
BuildRequires: python3-setuptools
@ -93,6 +97,16 @@ gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0}
%{python3_sitelib}/%{libname}/plugins/__pycache__/nmstate_plugin_ovsdb*
%changelog
* Wed Jul 28 2021 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.0.2-14
- Fix showing routes without next-hop-address or destination. RHBZ#1986285
* Thu Jul 08 2021 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.0.2-13
- Fix SR-IOV BCM57416 failure when creating VFs. RHBZ#1979515
- Fix applying route rule changes over ovs interface. RHBZ#1979943
* Tue Jul 06 2021 Gris Ge <fge@redhat.com> - 1.0.2-12
- Fix setting IP on ovs interface sharing the same name with bridge. RHBZ#1979220
* Thu Jun 03 2021 Gris Ge <fge@redhat.com> - 1.0.2-11
- Only validate desired bone interface. RHBZ#1966457