summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/NetworkManager.conf.xml6
-rw-r--r--src/core/devices/nm-device.c117
2 files changed, 123 insertions, 0 deletions
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index df85e6413b..3ef5d3dc5a 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -869,6 +869,9 @@ ipv6.ip6-privacy=0
and 100 for other profiles.</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>ipv4.required-timeout</varname></term>
+ </varlistentry>
+ <varlistentry>
<term><varname>ipv4.route-metric</varname></term>
</varlistentry>
<varlistentry>
@@ -911,6 +914,9 @@ ipv6.ip6-privacy=0
</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>ipv6.required-timeout</varname></term>
+ </varlistentry>
+ <varlistentry>
<term><varname>ipv6.route-metric</varname></term>
</varlistentry>
<varlistentry>
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 1dd998badd..3ac985af84 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -499,8 +499,18 @@ typedef struct _NMDevicePrivate {
NMDeviceStageState stage1_sriov_state : 3;
+ bool ip_config_started : 1;
+
char *current_stable_id;
+ union {
+ struct {
+ GSource *ip_req_timeout_source_6;
+ GSource *ip_req_timeout_source_4;
+ };
+ GSource *ip_req_timeout_source_x[2];
+ };
+
/* Proxy Configuration */
NMProxyConfig * proxy_config;
NMPacrunnerConfId *pacrunner_conf_id;
@@ -766,6 +776,7 @@ static void sriov_op_cb(GError *error, gpointer user_data);
static void device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice *self);
static gboolean device_link_changed(NMDevice *self);
+static void check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update);
/*****************************************************************************/
@@ -1364,6 +1375,40 @@ out:
return timeout;
}
+static guint32
+_prop_get_ipvx_required_timeout(NMDevice *self, int addr_family)
+{
+ NMConnection * connection;
+ NMSettingIPConfig *s_ip;
+ int timeout;
+
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert_addr_family(addr_family);
+
+ connection = nm_device_get_applied_connection(self);
+ if (!connection)
+ return 0;
+
+ s_ip = nm_connection_get_setting_ip_config(connection, addr_family);
+ if (!s_ip)
+ return 0;
+
+ timeout = nm_setting_ip_config_get_required_timeout(s_ip);
+ nm_assert(timeout >= -1);
+
+ if (timeout > -1)
+ return (guint32) timeout;
+
+ return nm_config_data_get_connection_default_int64(
+ NM_CONFIG_GET_DATA,
+ NM_IS_IPv4(addr_family) ? NM_CON_DEFAULT("ipv4.required-timeout")
+ : NM_CON_DEFAULT("ipv6.required-timeout"),
+ self,
+ 0,
+ G_MAXINT32,
+ 0);
+}
+
/**
* _prop_get_ipvx_dhcp_iaid:
* @self: the #NMDevice
@@ -2787,14 +2832,72 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities)
/*****************************************************************************/
+static gboolean
+ip_required_timeout_x(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
+ _LOGD(LOGD_CORE,
+ "required-timeout expired for IPv%c",
+ nm_utils_addr_family_to_char(addr_family));
+ nm_clear_g_source_inst(&priv->ip_req_timeout_source_x[NM_IS_IPv4(addr_family)]);
+ check_ip_state(self, FALSE, TRUE);
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+ip_required_timeout_4(gpointer data)
+{
+ return ip_required_timeout_x(data, AF_INET);
+}
+
+static gboolean
+ip_required_timeout_6(gpointer data)
+{
+ return ip_required_timeout_x(data, AF_INET6);
+}
+
static void
_set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ guint timeout_msec;
+ int v4;
nm_assert_addr_family(addr_family);
+ if (new_state == NM_DEVICE_IP_STATE_CONF && !priv->ip_config_started) {
+ /* Start the required-timeout timers when one of IPv4/IPv6
+ * enters the CONF state. This means that if there is no carrier and
+ * ipv4.method=auto,ipv6.method=manual, the timeout for IPv4 will
+ * start as soon as connection is activated, even if DHCPv4 did not
+ * start yet.
+ */
+ priv->ip_config_started = TRUE;
+
+ for (v4 = 1; v4 >= 0; v4--) {
+ char buf[32];
+
+ nm_assert(!priv->ip_req_timeout_source_x[v4]);
+ if ((timeout_msec = _prop_get_ipvx_required_timeout(self, v4 ? AF_INET : AF_INET6))) {
+ _LOGD(LOGD_CORE,
+ "required-timeout in %s msec for IPv%c",
+ timeout_msec == G_MAXINT32 ? "∞" : nm_sprintf_buf(buf, "%u", timeout_msec),
+ v4 ? '4' : '6');
+
+ if (timeout_msec == G_MAXINT32) {
+ priv->ip_req_timeout_source_x[v4] = g_source_ref(nm_g_source_sentinel_get(0));
+ } else {
+ priv->ip_req_timeout_source_x[v4] =
+ nm_g_timeout_add_source(timeout_msec,
+ v4 ? ip_required_timeout_4 : ip_required_timeout_6,
+ self);
+ }
+ }
+ }
+ }
+
if (priv->ip_state_x[IS_IPv4] == new_state)
return;
@@ -6578,6 +6681,7 @@ check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update)
gboolean ip4_disabled = FALSE, ip6_disabled = FALSE;
NMSettingIPConfig *s_ip4, *s_ip6;
NMDeviceState state;
+ int IS_IPv4;
if (full_state_update && nm_device_get_state(self) != NM_DEVICE_STATE_IP_CONFIG)
return;
@@ -6607,6 +6711,13 @@ check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update)
return;
}
+ for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
+ if (priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_CONF
+ && priv->ip_req_timeout_source_x[IS_IPv4]) {
+ return;
+ }
+ }
+
if ((priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL
|| (ip4_disabled && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE))
&& (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL
@@ -11812,6 +11923,8 @@ activate_stage5_ip_config_result_x(NMDevice *self, int addr_family)
req = nm_device_get_act_request(self);
g_assert(req);
+ nm_clear_g_source_inst(&priv->ip_req_timeout_source_x[IS_IPv4]);
+
/* Interface must be IFF_UP before IP config can be applied */
ip_ifindex = nm_device_get_ip_ifindex(self);
g_return_if_fail(ip_ifindex);
@@ -15779,6 +15892,10 @@ _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type)
_cleanup_ip_pre(self, AF_INET, cleanup_type);
_cleanup_ip_pre(self, AF_INET6, cleanup_type);
+
+ priv->ip_config_started = FALSE;
+ nm_clear_g_source_inst(&priv->ip_req_timeout_source_4);
+ nm_clear_g_source_inst(&priv->ip_req_timeout_source_6);
}
static void