about summary refs log tree commit diff
path: root/src/libnm-core-impl/nm-setting-connection.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2025-02-12 13:46:50 +0100
committerMichael Biebl <biebl@debian.org>2025-02-12 13:46:50 +0100
commit8bdf070ff046f482f6eb5e2b15ebc216f5d1e3da (patch)
treef706478d189d54c6532e8863d4b0d5ff5575af60 /src/libnm-core-impl/nm-setting-connection.c
parent818258cf34b83fbc754633295e1052d4752d7b15 (diff)
New upstream version 1.51.90 upstream/1.51.90
Diffstat (limited to 'src/libnm-core-impl/nm-setting-connection.c')
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c422
1 files changed, 421 insertions, 1 deletions
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index 33d088bb..4a910c7f 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -63,6 +63,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection,
                              PROP_AUTOCONNECT_PORTS,
                              PROP_SECONDARIES,
                              PROP_GATEWAY_PING_TIMEOUT,
+                             PROP_IP_PING_TIMEOUT,
+                             PROP_IP_PING_ADDRESSES,
+                             PROP_IP_PING_ADDRESSES_REQUIRE_ALL,
                              PROP_METERED,
                              PROP_LLDP,
                              PROP_MDNS,
@@ -91,6 +94,7 @@ typedef struct {
     guint64     timestamp;
     int         autoconnect_ports;
     int         down_on_poweroff;
+    int         ip_ping_addresses_require_all;
     int         metered;
     gint32      autoconnect_priority;
     gint32      autoconnect_retries;
@@ -104,6 +108,8 @@ typedef struct {
     gint32      wait_activation_delay;
     guint32     mptcp_flags;
     guint32     gateway_ping_timeout;
+    NMValueStrv ip_ping_addresses;
+    guint32     ip_ping_timeout;
     bool        autoconnect;
     bool        read_only;
 } NMSettingConnectionPrivate;
@@ -139,7 +145,7 @@ _permission_set_stale(Permission *permission, PermType ptype, char *item_take)
 
     /* we don't inspect (clear) permission before setting. It takes a
      * stale instance. */
-    *permission = (Permission){
+    *permission = (Permission) {
         .ptype = ptype,
         .item  = item_take,
     };
@@ -1037,6 +1043,172 @@ nm_setting_connection_get_gateway_ping_timeout(NMSettingConnection *setting)
     return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->gateway_ping_timeout;
 }
 
+GArray *
+_nm_setting_connection_get_ip_ping_addresses(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NULL);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses.arr;
+}
+
+/**
+ * nm_setting_connection_get_ip_ping_address:
+ * @setting: the #NMSettingConnection
+ * @idx: the zero-based index of the ip-ping-addresses entry.
+ *
+ * Returns: the ip address string at index @idx or
+ *   %NULL if @idx is the number of ip-ping-addresses.
+ *
+ * Since: 1.52
+ **/
+const char *
+nm_setting_connection_get_ip_ping_address(NMSettingConnection *setting, guint32 idx)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NULL);
+
+    return nm_strvarray_get_idxnull_or_greturn(
+        NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses.arr,
+        idx);
+}
+
+/**
+ * nm_setting_connection_add_ip_ping_address:
+ * @setting: the #NMSettingConnection
+ * @address: the IP address string to add
+ *
+ * Adds a new IP address string to the ip-ping-addresses.
+ *
+ * Returns: %TRUE if the new IP address was added; %FALSE if the IP address
+ * was already present
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_setting_connection_add_ip_ping_address(NMSettingConnection *setting, const char *address)
+{
+    NMSettingConnectionPrivate *priv;
+
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE);
+    g_return_val_if_fail(address, FALSE);
+
+    priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
+
+    if (!nm_strvarray_ensure_and_add_unique(&priv->ip_ping_addresses.arr, address))
+        return FALSE;
+
+    _notify(setting, PROP_IP_PING_ADDRESSES);
+    return TRUE;
+}
+
+/**
+ * nm_setting_connection_remove_ip_ping_address:
+ * @setting: the #NMSettingConnection
+ * @idx: index number of the IP address
+ *
+ * Removes the IP address at index @idx.
+ *
+ * Since: 1.52
+ **/
+void
+nm_setting_connection_remove_ip_ping_address(NMSettingConnection *setting, guint32 idx)
+{
+    NMSettingConnectionPrivate *priv;
+
+    g_return_if_fail(NM_IS_SETTING_CONNECTION(setting));
+
+    priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
+
+    g_return_if_fail(idx < nm_g_array_len(priv->ip_ping_addresses.arr));
+
+    nm_strvarray_remove_index(priv->ip_ping_addresses.arr, idx);
+    _notify(setting, PROP_IP_PING_ADDRESSES);
+}
+
+/**
+ * nm_setting_connection_remove_ip_ping_address_by_value:
+ * @setting: the #NMSettingConnection
+ * @address: the IP address to remove
+ *
+ * Removes the IP address @address from ip-ping-addresses.
+ *
+ * Returns: %TRUE if the IP address was found and removed; %FALSE if it was not.
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_setting_connection_remove_ip_ping_address_by_value(NMSettingConnection *setting,
+                                                      const char          *address)
+{
+    NMSettingConnectionPrivate *priv;
+
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE);
+    g_return_val_if_fail(address, FALSE);
+
+    priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
+
+    if (!nm_strvarray_remove_first(priv->ip_ping_addresses.arr, address))
+        return FALSE;
+
+    _notify(setting, PROP_IP_PING_ADDRESSES);
+    return TRUE;
+}
+
+/**
+ * nm_setting_connection_clear_ip_ping_addresses:
+ * @setting: the #NMSettingConnection
+ *
+ * Removes all configured ip-ping-addresses.
+ *
+ * Since: 1.52
+ **/
+void
+nm_setting_connection_clear_ip_ping_addresses(NMSettingConnection *setting)
+{
+    NMSettingConnectionPrivate *priv;
+
+    g_return_if_fail(NM_IS_SETTING_CONNECTION(setting));
+
+    priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting);
+
+    if (nm_strvarray_clear(&priv->ip_ping_addresses.arr))
+        _notify(setting, PROP_IP_PING_ADDRESSES);
+}
+
+/**
+ * nm_setting_connection_get_ip_ping_timeout:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns: the value contained in the #NMSettingConnection:ip-ping-timeout
+ * property.
+ *
+ * Since: 1.52
+ **/
+guint32
+nm_setting_connection_get_ip_ping_timeout(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), 0);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_timeout;
+}
+
+/**
+ * nm_setting_connection_get_ip_ping_addresses_require_all:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns the #NMSettingConnection:ip-ping-addresses-require-all property of the connection.
+ *
+ * Returns: whether all the ip ping addresses pass the connectivity check.
+ *
+ * Since: 1.52
+ **/
+NMTernary
+nm_setting_connection_get_ip_ping_addresses_require_all(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_TERNARY_DEFAULT);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->ip_ping_addresses_require_all;
+}
+
 /**
  * nm_setting_connection_get_metered:
  * @setting: the #NMSettingConnection
@@ -1610,6 +1782,176 @@ after_interface_name:
         }
     }
 
+    if (priv->ip_ping_timeout != 0
+        && (!priv->ip_ping_addresses.arr || priv->ip_ping_addresses.arr->len == 0)) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("can only be set if %s.%s is set"),
+                    NM_SETTING_CONNECTION_SETTING_NAME,
+                    NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_CONNECTION_SETTING_NAME,
+                       NM_SETTING_CONNECTION_IP_PING_TIMEOUT);
+        return FALSE;
+    }
+
+    if (priv->ip_ping_addresses.arr && priv->ip_ping_addresses.arr->len > 0) {
+        guint i;
+
+        if (priv->ip_ping_timeout == 0) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("can only be set if %s.%s is set"),
+                        NM_SETTING_CONNECTION_SETTING_NAME,
+                        NM_SETTING_CONNECTION_IP_PING_TIMEOUT);
+            g_prefix_error(error,
+                           "%s.%s: ",
+                           NM_SETTING_CONNECTION_SETTING_NAME,
+                           NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+            return FALSE;
+        }
+
+        if (priv->gateway_ping_timeout != 0 && priv->ip_ping_timeout != 0) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("is incompatible with '%s'"),
+                        NM_SETTING_CONNECTION_IP_PING_TIMEOUT);
+            g_prefix_error(error,
+                           "%s.%s: ",
+                           NM_SETTING_CONNECTION_SETTING_NAME,
+                           NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT);
+            return FALSE;
+        }
+
+        for (i = 0; i < priv->ip_ping_addresses.arr->len; i++) {
+            const char *address = nm_g_array_index(priv->ip_ping_addresses.arr, const char *, i);
+            int         addr_family = _get_ip_address_family(address);
+
+            if (addr_family == AF_INET) {
+                NMSettingIPConfig *s_ip4;
+
+                if (connection) {
+                    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+
+                    if (s_ip4) {
+                        const char *method = nm_setting_ip_config_get_method(s_ip4);
+                        if (nm_streq0(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+                            g_set_error(error,
+                                        NM_CONNECTION_ERROR,
+                                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                        _("contains IPv4 address '%s', %s.%s cannot be 'disabled'"),
+                                        address,
+                                        NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                        NM_SETTING_IP_CONFIG_METHOD);
+                            g_prefix_error(error,
+                                           "%s.%s: ",
+                                           NM_SETTING_CONNECTION_SETTING_NAME,
+                                           NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                            return FALSE;
+                        }
+                        if (nm_setting_ip_config_get_may_fail(s_ip4)) {
+                            g_set_error(error,
+                                        NM_CONNECTION_ERROR,
+                                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                        _("contains IPv4 address '%s', %s.%s cannot be 'true'"),
+                                        address,
+                                        NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                        NM_SETTING_IP_CONFIG_MAY_FAIL);
+                            g_prefix_error(error,
+                                           "%s.%s: ",
+                                           NM_SETTING_CONNECTION_SETTING_NAME,
+                                           NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                            return FALSE;
+                        }
+                    } else {
+                        g_set_error(error,
+                                    NM_CONNECTION_ERROR,
+                                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                    _("contains IPv4 address '%s', %s.%s must be set to 'false' "
+                                      "explicitly"),
+                                    address,
+                                    NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                    NM_SETTING_IP_CONFIG_MAY_FAIL);
+                        g_prefix_error(error,
+                                       "%s.%s: ",
+                                       NM_SETTING_CONNECTION_SETTING_NAME,
+                                       NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                        return FALSE;
+                    }
+                }
+            } else if (addr_family == AF_INET6) {
+                NMSettingIPConfig *s_ip6;
+
+                if (connection) {
+                    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+                    if (s_ip6) {
+                        const char *method = nm_setting_ip_config_get_method(s_ip6);
+                        if (NM_IN_STRSET(method,
+                                         NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+                                         NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) {
+                            g_set_error(error,
+                                        NM_CONNECTION_ERROR,
+                                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                        _("contains IPv6 address '%s', %s.%s cannot be '%s'"),
+                                        address,
+                                        NM_SETTING_IP6_CONFIG_SETTING_NAME,
+                                        NM_SETTING_IP_CONFIG_METHOD,
+                                        method);
+                            g_prefix_error(error,
+                                           "%s.%s: ",
+                                           NM_SETTING_CONNECTION_SETTING_NAME,
+                                           NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                            return FALSE;
+                        }
+                        if (nm_setting_ip_config_get_may_fail(s_ip6)) {
+                            g_set_error(error,
+                                        NM_CONNECTION_ERROR,
+                                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                        _("contains IPv6 address '%s', %s.%s cannot be 'true'"),
+                                        address,
+                                        NM_SETTING_IP6_CONFIG_SETTING_NAME,
+                                        NM_SETTING_IP_CONFIG_MAY_FAIL);
+                            g_prefix_error(error,
+                                           "%s.%s: ",
+                                           NM_SETTING_CONNECTION_SETTING_NAME,
+                                           NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                            return FALSE;
+                        }
+                    } else {
+                        g_set_error(error,
+                                    NM_CONNECTION_ERROR,
+                                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                    _("contains IPv6 address '%s', %s.%s must be set to 'false' "
+                                      "explicitly"),
+                                    address,
+                                    NM_SETTING_IP6_CONFIG_SETTING_NAME,
+                                    NM_SETTING_IP_CONFIG_MAY_FAIL);
+                        g_prefix_error(error,
+                                       "%s.%s: ",
+                                       NM_SETTING_CONNECTION_SETTING_NAME,
+                                       NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                        return FALSE;
+                    }
+                }
+            } else {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("has an invalid IP address '%s'"),
+                            address);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_CONNECTION_SETTING_NAME,
+                               NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+                return FALSE;
+            }
+        }
+    }
+
     /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
 
     if (!priv->uuid) {
@@ -1711,6 +2053,20 @@ after_interface_name:
     if (!_nm_setting_connection_verify_secondaries(priv->secondaries.arr, error))
         return NM_SETTING_VERIFY_NORMALIZABLE;
 
+    if (priv->ip_ping_addresses.arr && priv->ip_ping_addresses.arr->len > 0
+        && !_nm_setting_connection_verify_no_duplicate_addresses(priv->ip_ping_addresses.arr,
+                                                                 error)) {
+        g_set_error_literal(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("has duplicate addresses"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_CONNECTION_SETTING_NAME,
+                       NM_SETTING_CONNECTION_IP_PING_ADDRESSES);
+        return NM_SETTING_VERIFY_NORMALIZABLE;
+    }
+
     if (priv->read_only) {
         g_set_error_literal(error,
                             NM_CONNECTION_ERROR,
@@ -2763,6 +3119,70 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                             secondaries);
 
     /**
+     * NMSettingConnection:ip-ping-addresses:
+     *
+     * The property specifies a list of target IP addresses for pinging.
+     * When multiple targets are set, NetworkManager will start multiple ping processes
+     * in parallel. This property can only be set if connection.ip-ping-timeout is
+     * set. The ip-ping-timeout is used to delay the success of IP addressing until
+     * either the specified timeout (in seconds) is reached, or an target IP address replies
+     * to a ping. Configuring #NMSettingConnection:ip-ping-addresses may delay reaching the
+     * systemd's network-online.target due to waiting for the ping operations to complete or timeout.
+     *
+     * Since: 1.52
+     **/
+    _nm_setting_property_define_direct_strv(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_CONNECTION_IP_PING_ADDRESSES,
+                                            PROP_IP_PING_ADDRESSES,
+                                            NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
+                                            NMSettingConnectionPrivate,
+                                            ip_ping_addresses);
+
+    /**
+     * NMSettingConnection:ip-ping-addresses-require-all:
+     *
+     * The property determines whether it is sufficient for any ping check
+     * to succeed among #NMSettingConnection:ip-ping-addresses, or if all
+     * ping checks must succeed for #NMSettingConnection:ip-ping-addresses.
+     *
+     * Since: 1.52
+     **/
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_CONNECTION_IP_PING_ADDRESSES_REQUIRE_ALL,
+                                            PROP_IP_PING_ADDRESSES_REQUIRE_ALL,
+                                            NM_TYPE_TERNARY,
+                                            NM_TERNARY_DEFAULT,
+                                            NM_SETTING_PARAM_NONE,
+                                            NULL,
+                                            NMSettingConnectionPrivate,
+                                            ip_ping_addresses_require_all);
+
+    /**
+     * NMSettingConnection:ip-ping-timeout:
+     *
+     * If greater than zero, delay success of IP addressing until either the specified
+     * timeout (in seconds) is reached, or a target IP address replies to a ping. The
+     * property specifies the timeout for the #NMSettingConnection:ip-ping-addresses.
+     * This property is incompatible with #NMSettingConnection:gateway-ping-timeout,
+     * you cannot set these two properties at the same time.
+     *
+     * Since: 1.52
+     **/
+    _nm_setting_property_define_direct_uint32(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_CONNECTION_IP_PING_TIMEOUT,
+                                              PROP_IP_PING_TIMEOUT,
+                                              0,
+                                              600,
+                                              0,
+                                              NM_SETTING_PARAM_NONE,
+                                              NMSettingConnectionPrivate,
+                                              ip_ping_timeout);
+
+    /**
      * NMSettingConnection:gateway-ping-timeout:
      *
      * If greater than zero, delay success of IP addressing until either the