libnm: support wait-activation-delay property

The property wait-activation-delay will delay the activation of an
interface the specified amount of milliseconds. Please notice that it
could be delayed some milliseconds more due to other events in
NetworkManager.

This could be used in multiple scenarios where the user needs to define
an arbitrary delay e.g LACP bond configure where the LACP negotiation
takes a few seconds and traffic is not allowed, so they would like to
use nm-online and a setting configured with this new property to wait
some seconds. Therefore, when nm-online is finished, LACP bond should be
ready to receive traffic.

The delay will happen right before the device is ready to be activated.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1248

https://bugzilla.redhat.com/show_bug.cgi?id=2008337
This commit is contained in:
Fernando Fernandez Mancera 2022-05-27 12:36:29 +02:00
parent c861a7e1d8
commit 8b3bad3136
15 changed files with 833 additions and 576 deletions

View file

@ -393,6 +393,8 @@ typedef struct _NMDevicePrivate {
guint device_link_changed_id;
guint device_ip_link_changed_id;
GSource *delay_activation_source;
NMDeviceState state;
NMDeviceStateReason state_reason;
struct {
@ -12607,7 +12609,8 @@ can_reapply_change(NMDevice *self,
NM_SETTING_CONNECTION_LLDP,
NM_SETTING_CONNECTION_MDNS,
NM_SETTING_CONNECTION_LLMNR,
NM_SETTING_CONNECTION_DNS_OVER_TLS);
NM_SETTING_CONNECTION_DNS_OVER_TLS,
NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY);
}
if (NM_IN_STRSET(setting_name,
@ -13474,27 +13477,69 @@ _dispatcher_cleanup(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
nm_clear_g_source_inst(&priv->delay_activation_source);
if (!priv->dispatcher.call_id)
return FALSE;
nm_dispatcher_call_cancel(g_steal_pointer(&priv->dispatcher.call_id));
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
return TRUE;
}
static void
_queue_dispatcher_post_state(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
nm_device_queue_state(self, priv->dispatcher.post_state, priv->dispatcher.post_state_reason);
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
}
static gboolean
_wait_activation_delay_timeout(gpointer user_data)
{
NMDevice *self = user_data;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
nm_clear_g_source_inst(&priv->delay_activation_source);
_LOGD(LOGD_DEVICE, "finished waiting on activation delay");
_queue_dispatcher_post_state(self);
return G_SOURCE_REMOVE;
}
static void
_dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data)
{
NMDevice *self = NM_DEVICE(user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
NMDevice *self = NM_DEVICE(user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
NMConnection *conn;
NMSettingConnection *s_conn;
gint32 delay_timeout;
g_return_if_fail(call_id == priv->dispatcher.call_id);
nm_assert(!priv->delay_activation_source);
priv->dispatcher.call_id = NULL;
nm_device_queue_state(self, priv->dispatcher.post_state, priv->dispatcher.post_state_reason);
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
conn = nm_device_get_applied_connection(self);
if (conn) {
s_conn = nm_connection_get_setting_connection(conn);
if (s_conn) {
delay_timeout = nm_setting_connection_get_wait_activation_delay(s_conn);
if (delay_timeout > 0) {
priv->delay_activation_source =
nm_g_timeout_add_source(delay_timeout, _wait_activation_delay_timeout, self);
return;
}
}
}
_queue_dispatcher_post_state(self);
}
/*****************************************************************************/

View file

@ -393,6 +393,7 @@ make_connection_setting(const char *file,
const char *v;
gs_free char *stable_id = NULL;
const char *const *iter;
gint32 vint32;
int vint64, i_val;
ifcfg_name = utils_get_ifcfg_name(file, TRUE);
@ -643,6 +644,9 @@ make_connection_setting(const char *file,
PARSE_WARNING("invalid DNS_OVER_TLS setting");
g_object_set(s_con, NM_SETTING_CONNECTION_DNS_OVER_TLS, i_val, NULL);
vint32 = svGetValueInt64(ifcfg, "WAIT_ACTIVATION_DELAY", 10, -1, G_MAXINT32, -1);
g_object_set(s_con, NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, (int) vint32, NULL);
return NM_SETTING(s_con);
}

View file

@ -1062,6 +1062,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
_KEY_TYPE("VLAN_INGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("VRF", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("VRF_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("WAIT_ACTIVATION_DELAY", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("WEP_KEY_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("WPA_ALLOW_WPA", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("WPA_ALLOW_WPA2", NMS_IFCFG_KEY_TYPE_IS_PLAIN),

View file

@ -33,7 +33,7 @@ typedef struct {
NMSIfcfgKeyTypeFlags key_flags;
} NMSIfcfgKeyTypeInfo;
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[254];
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[255];
const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx);

View file

@ -2258,6 +2258,9 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg)
vint = nm_setting_connection_get_auth_retries(s_con);
svSetValueInt64_cond(ifcfg, "AUTH_RETRIES", vint >= 0, vint);
vint32 = nm_setting_connection_get_wait_activation_delay(s_con);
svSetValueInt64_cond(ifcfg, "WAIT_ACTIVATION_DELAY", vint32 >= 0, vint32);
vint32 = nm_setting_connection_get_wait_device_timeout(s_con);
if (vint32 == -1) {
/* pass */

View file

@ -1830,6 +1830,7 @@ global:
libnm_1_40_0 {
global:
nm_setting_connection_get_wait_activation_delay;
nm_setting_ip4_link_local_get_type;
nm_setting_ip6_config_get_mtu;
} libnm_1_38_0;

View file

@ -68,7 +68,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection,
PROP_STABLE_ID,
PROP_AUTH_RETRIES,
PROP_WAIT_DEVICE_TIMEOUT,
PROP_MUD_URL, );
PROP_MUD_URL,
PROP_WAIT_ACTIVATION_DELAY, );
typedef struct {
GArray *permissions;
@ -94,6 +95,7 @@ typedef struct {
gint32 dns_over_tls;
gint32 wait_device_timeout;
gint32 lldp;
gint32 wait_activation_delay;
guint32 gateway_ping_timeout;
bool autoconnect;
bool read_only;
@ -734,6 +736,23 @@ nm_setting_connection_get_wait_device_timeout(NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->wait_device_timeout;
}
/**
* nm_setting_connection_get_wait_activation_delay:
* @setting: the #NMSettingConnection
*
* Returns: the %NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY property with
* the delay in milliseconds. -1 is the default.
*
* Since: 1.40
*/
gint32
nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting)
{
g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), -1);
return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->wait_activation_delay;
}
/**
* nm_setting_connection_get_autoconnect_slaves:
* @setting: the #NMSettingConnection
@ -2530,6 +2549,37 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
NMSettingConnectionPrivate,
mud_url);
/**
* NMSettingConnection:wait-activation-delay:
*
* Time in milliseconds to wait for connection to be considered activated.
* The wait will start after the pre-up dispatcher event.
*
* The value 0 means no wait time. The default value is -1, which
* currently has the same meaning as no wait time.
*
* Since: 1.40
**/
/* ---ifcfg-rh---
* property: wait-activation-delay
* variable: WAIT_ACTIVATION_DELAY(+)
* values: delay in milliseconds.
* description: Time in milliseconds to wait for connection to be considered activated.
* The wait will start after the pre-up dispatcher event.
* example: WAIT_ACTIVATION_DELAY=5000
* ---end---
*/
_nm_setting_property_define_direct_int32(properties_override,
obj_properties,
NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY,
PROP_WAIT_ACTIVATION_DELAY,
-1,
G_MAXINT32,
-1,
NM_SETTING_PARAM_NONE,
NMSettingConnectionPrivate,
wait_activation_delay);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit(setting_class,

View file

@ -3824,6 +3824,7 @@ test_connection_diff_a_only(void)
{NM_SETTING_CONNECTION_DNS_OVER_TLS, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A},
{NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, NM_SETTING_DIFF_RESULT_IN_A},
{NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}}},
{NM_SETTING_WIRED_SETTING_NAME,
{

View file

@ -33,32 +33,33 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX 999
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT 0
#define NM_SETTING_CONNECTION_ID "id"
#define NM_SETTING_CONNECTION_UUID "uuid"
#define NM_SETTING_CONNECTION_STABLE_ID "stable-id"
#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name"
#define NM_SETTING_CONNECTION_TYPE "type"
#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect"
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority"
#define NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES "autoconnect-retries"
#define NM_SETTING_CONNECTION_MULTI_CONNECT "multi-connect"
#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp"
#define NM_SETTING_CONNECTION_READ_ONLY "read-only"
#define NM_SETTING_CONNECTION_PERMISSIONS "permissions"
#define NM_SETTING_CONNECTION_ZONE "zone"
#define NM_SETTING_CONNECTION_MASTER "master"
#define NM_SETTING_CONNECTION_SLAVE_TYPE "slave-type"
#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves"
#define NM_SETTING_CONNECTION_SECONDARIES "secondaries"
#define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout"
#define NM_SETTING_CONNECTION_METERED "metered"
#define NM_SETTING_CONNECTION_LLDP "lldp"
#define NM_SETTING_CONNECTION_AUTH_RETRIES "auth-retries"
#define NM_SETTING_CONNECTION_MDNS "mdns"
#define NM_SETTING_CONNECTION_LLMNR "llmnr"
#define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls"
#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout"
#define NM_SETTING_CONNECTION_MUD_URL "mud-url"
#define NM_SETTING_CONNECTION_ID "id"
#define NM_SETTING_CONNECTION_UUID "uuid"
#define NM_SETTING_CONNECTION_STABLE_ID "stable-id"
#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name"
#define NM_SETTING_CONNECTION_TYPE "type"
#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect"
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority"
#define NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES "autoconnect-retries"
#define NM_SETTING_CONNECTION_MULTI_CONNECT "multi-connect"
#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp"
#define NM_SETTING_CONNECTION_READ_ONLY "read-only"
#define NM_SETTING_CONNECTION_PERMISSIONS "permissions"
#define NM_SETTING_CONNECTION_ZONE "zone"
#define NM_SETTING_CONNECTION_MASTER "master"
#define NM_SETTING_CONNECTION_SLAVE_TYPE "slave-type"
#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves"
#define NM_SETTING_CONNECTION_SECONDARIES "secondaries"
#define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout"
#define NM_SETTING_CONNECTION_METERED "metered"
#define NM_SETTING_CONNECTION_LLDP "lldp"
#define NM_SETTING_CONNECTION_AUTH_RETRIES "auth-retries"
#define NM_SETTING_CONNECTION_MDNS "mdns"
#define NM_SETTING_CONNECTION_LLMNR "llmnr"
#define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls"
#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout"
#define NM_SETTING_CONNECTION_MUD_URL "mud-url"
#define NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY "wait-activation-delay"
/* Types for property values */
/**
@ -218,6 +219,9 @@ NMSettingConnectionDnsOverTls nm_setting_connection_get_dns_over_tls(NMSettingCo
NM_AVAILABLE_IN_1_20
gint32 nm_setting_connection_get_wait_device_timeout(NMSettingConnection *setting);
NM_AVAILABLE_IN_1_40
gint32 nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting);
NM_AVAILABLE_IN_1_26
const char *nm_setting_connection_get_mud_url(NMSettingConnection *setting);

View file

@ -5555,6 +5555,9 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT,
.property_type = &_pt_gobject_int,
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY,
.property_type = &_pt_gobject_int,
),
NULL
};

View file

@ -175,6 +175,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY N_("Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.")
#define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_FLAGS N_("Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4).")

View file

@ -423,6 +423,8 @@
description="If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". The special value "none" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none"." />
<property name="wait-device-timeout"
description="Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time." />
<property name="wait-activation-delay"
description="Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time." />
</setting>
<setting name="dcb" >
<property name="app-fcoe-flags"

View file

@ -502,12 +502,12 @@ NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
<<<
size: 1319
size: 1362
location: src/tests/client/test-client.py:test_002()/23
cmd: $NMCLI c s con-1
lang: C
returncode: 0
stdout: 1191 bytes
stdout: 1234 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -534,14 +534,15 @@ connection.mdns: -1 (default)
connection.llmnr: -1 (default)
connection.dns-over-tls: -1 (default)
connection.wait-device-timeout: -1
connection.wait-activation-delay: -1
<<<
size: 1331
size: 1374
location: src/tests/client/test-client.py:test_002()/24
cmd: $NMCLI c s con-1
lang: pl_PL.UTF-8
returncode: 0
stdout: 1193 bytes
stdout: 1236 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -568,5 +569,6 @@ connection.mdns: -1 (default)
connection.llmnr: -1 (default)
connection.dns-over-tls: -1 (default)
connection.wait-device-timeout: -1
connection.wait-activation-delay: -1
<<<

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff