nm ip: fix ipv4.dhcp-timeout even when ip not desired

When a NM connection holding non-infinity `ipv4.dhcp-timeout`, the
connection will be deactivated on DHCP timeout, when nmstate modifying
this NM connection, it should also fix `ipv4.dhcp-timeout` to make sure
it never been deactivated due to timeout even when ipv4 not mentioned in
desired state.

This patch will always set `ipv4.dhcp-timeout` and `ipv6.dhcp-timeout`
to `i32::MAX` for NM connections we are about to modify.

Integration test case include.

Resolves: https://issues.redhat.com/browse/RHEL-16865

Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
Gris Ge 2023-11-20 12:10:33 +08:00
parent c2809592b8
commit 6b6caeec32
4 changed files with 59 additions and 2 deletions

View File

@ -2,8 +2,9 @@
use super::nm_dbus::{NmActiveConnection, NmConnection};
use super::settings::{
get_exist_profile, iface_to_nm_connections, remove_nm_mptcp_set,
use_uuid_for_controller_reference, use_uuid_for_parent_reference,
fix_ip_dhcp_timeout, get_exist_profile, iface_to_nm_connections,
remove_nm_mptcp_set, use_uuid_for_controller_reference,
use_uuid_for_parent_reference,
};
use crate::{
@ -118,6 +119,8 @@ pub(crate) fn perpare_nm_conns(
}
}
fix_ip_dhcp_timeout(&mut nm_conns_to_update);
use_uuid_for_controller_reference(
&mut nm_conns_to_update,
&merged_state.interfaces,

View File

@ -343,3 +343,17 @@ fn apply_nmstate_wait_ip(
None => (),
}
}
// Even user not desired IP section changes, we should set ipv4.dhcp_timeout
// and ipv6.dhcp_timeout to i32::MAX to make sure NetworkManager never
// deactivate a desired interface
pub(crate) fn fix_ip_dhcp_timeout(nm_conns: &mut [NmConnection]) {
for nm_conn in nm_conns {
if let Some(nm_ip_set) = nm_conn.ipv4.as_mut() {
nm_ip_set.dhcp_timeout = Some(i32::MAX);
}
if let Some(nm_ip_set) = nm_conn.ipv6.as_mut() {
nm_ip_set.dhcp_timeout = Some(i32::MAX);
}
}
}

View File

@ -42,6 +42,7 @@ pub(crate) use self::connection::{
pub(crate) use self::inter_connections::{
use_uuid_for_controller_reference, use_uuid_for_parent_reference,
};
pub(crate) use self::ip::fix_ip_dhcp_timeout;
#[cfg(feature = "query_apply")]
pub(crate) use self::bond::get_bond_balance_slb;

View File

@ -19,6 +19,8 @@ IPV6_ADDRESS1 = "2001:db8:1::1"
IPV6_ADDRESS2 = "2001:db8:1::2"
IPV6_NET1 = "2001:db8:a::/64"
I32_MAX = 0x7FFFFFFF
def test_get_applied_config_for_dhcp_state_with_dhcp_enabeld_on_disk(eth1_up):
iface_state = eth1_up[Interface.KEY][0]
@ -184,3 +186,40 @@ def test_switch_static_gateway_to_dhcp(eth1_up_with_nm_gateway):
cmdlib.exec_cmd("nmcli -g ipv6.gateway c show eth1".split())[1].strip()
== ""
)
@pytest.fixture
def dummy1_with_small_dhcp_timeout():
cmdlib.exec_cmd(
"nmcli c add type dummy ifname dummy1 connection.id dummy1 "
"ipv4.method auto ipv4.dhcp-timeout 5 "
"ipv6.method auto ipv6.dhcp-timeout 5 ".split(),
check=True,
)
yield
cmdlib.exec_cmd("nmcli c del dummy1".split(), check=True)
def test_fix_dhcp_timeout_even_not_desired(dummy1_with_small_dhcp_timeout):
iface_state = {
Interface.NAME: "dummy1",
Interface.DESCRIPTION: "test_only",
}
libnmstate.apply({Interface.KEY: [iface_state]})
assert (
int(
cmdlib.exec_cmd(
"nmcli -g ipv4.dhcp-timeout c show dummy1".split()
)[1].strip()
)
== I32_MAX
)
assert (
int(
cmdlib.exec_cmd(
"nmcli -g ipv6.dhcp-timeout c show dummy1".split()
)[1].strip()
)
== I32_MAX
)