diff options
-rw-r--r-- | src/core/devices/nm-device.c | 71 | ||||
-rw-r--r-- | src/core/devices/nm-device.h | 2 | ||||
-rw-r--r-- | src/core/nm-checkpoint.c | 5 | ||||
-rw-r--r-- | src/core/nm-manager.c | 3 | ||||
-rw-r--r-- | src/libnm-core-public/nm-dbus-interface.h | 16 |
5 files changed, 90 insertions, 7 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6886f3c1ce..b7201dc55c 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -76,6 +76,7 @@ #include "nm-hostname-manager.h" #include "nm-device-generic.h" +#include "nm-device-bridge.h" #include "nm-device-vlan.h" #include "nm-device-vrf.h" #include "nm-device-wireguard.h" @@ -481,9 +482,12 @@ typedef struct _NMDevicePrivate { NMUtilsStableType current_stable_id_type : 3; + bool activation_state_preserve_external_ports : 1; + bool nm_owned : 1; /* whether the device is a device owned and created by NM */ - bool assume_state_guess_assume : 1; + bool assume_state_guess_assume : 1; + char *assume_state_connection_uuid; guint64 udi_id; @@ -7669,8 +7673,19 @@ nm_device_master_release_slaves(NMDevice *self) c_list_for_each_safe (iter, safe, &priv->slaves) { SlaveInfo *info = c_list_entry(iter, SlaveInfo, lst_slave); + if (priv->activation_state_preserve_external_ports + && nm_device_sys_iface_state_is_external(info->slave)) { + _LOGT(LOGD_DEVICE, + "master: preserve external port %s", + nm_device_get_iface(info->slave)); + continue; + } nm_device_master_release_one_slave(self, info->slave, TRUE, FALSE, reason); } + + /* We only need this flag for a short time. It served its purpose. Clear + * it again. */ + nm_device_activation_state_set_preserve_external_ports(self, FALSE); } /** @@ -15389,6 +15404,16 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, if (state > NM_DEVICE_STATE_DISCONNECTED) nm_device_assume_state_reset(self); + if (state < NM_DEVICE_STATE_UNAVAILABLE + || (state >= NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_ACTIVATED)) { + /* preserve-external-ports is used by NMCheckpoint to activate a master + * device, and preserve already attached ports. This means, this state is only + * relevant during the deactivation and the following activation of the + * right profile. Once we are sufficiently far in the activation of the + * intended profile, we clear the state again. */ + nm_device_activation_state_set_preserve_external_ports(self, FALSE); + } + if (state <= NM_DEVICE_STATE_UNAVAILABLE) { if (available_connections_del_all(self)) _notify(self, PROP_AVAILABLE_CONNECTIONS); @@ -15794,6 +15819,50 @@ nm_device_get_state(NMDevice *self) } /*****************************************************************************/ + +/** + * nm_device_activation_state_set_preserve_external_ports: + * @self: the NMDevice. + * @flag: whether to set or clear the the flag. + * + * This sets an internal flag to true, which does something specific. + * For non-master devices, it has no effect. For master devices, this + * will prevent to detach all external ports, until the next activation + * completes. + * + * This is used during checkpoint/rollback. We may want to preserve + * externally attached ports during the restore. NMCheckpoint will + * call this before doing a re-activation. By setting the flag, + * we basically preserve such ports. + * + * Once we reach again ACTIVATED state, the flag gets cleared. This + * only has effect for the next activation cycle. */ +void +nm_device_activation_state_set_preserve_external_ports(NMDevice *self, gboolean flag) +{ + NMDevicePrivate *priv; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (!NM_IS_DEVICE_BRIDGE(self)) { + /* This is actually only implemented for bridge devices. While it might + * make sense for bond/team or OVS, it's not clear that it is actually + * useful or desirable. */ + return; + } + + if (priv->activation_state_preserve_external_ports == flag) + return; + + priv->activation_state_preserve_external_ports = flag; + _LOGD(LOGD_DEVICE, + "activation-state: preserve-external-ports %s", + flag ? "enabled" : "disabled"); +} + +/*****************************************************************************/ /* NMConfigDevice interface related stuff */ const char * diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index d9cfc7e621..80def12511 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -443,6 +443,8 @@ NMDeviceType nm_device_get_device_type(NMDevice *dev); NMLinkType nm_device_get_link_type(NMDevice *dev); NMMetered nm_device_get_metered(NMDevice *dev); +void nm_device_activation_state_set_preserve_external_ports(NMDevice *self, gboolean flag); + guint32 nm_device_get_route_table(NMDevice *self, int addr_family); guint32 nm_device_get_route_metric(NMDevice *dev, int addr_family); diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c index 0153af970d..5b48f91aa5 100644 --- a/src/core/nm-checkpoint.c +++ b/src/core/nm-checkpoint.c @@ -282,6 +282,11 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp * an internal subject. */ if (nm_device_get_state(dev_checkpoint->device) > NM_DEVICE_STATE_DISCONNECTED && nm_device_get_state(dev_checkpoint->device) < NM_DEVICE_STATE_DEACTIVATING) { + if (!NM_FLAGS_HAS(priv->flags, NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS)) { + nm_device_activation_state_set_preserve_external_ports(dev_checkpoint->device, + TRUE); + } + nm_device_state_changed(dev_checkpoint->device, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NEW_ACTIVATION); diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index b585c4b7f2..c2a8f61350 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -7616,7 +7616,8 @@ impl_manager_checkpoint_create(NMDBusObject *obj, ~((guint32) (NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL | NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS | NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES - | NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING)))) { + | NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING + | NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS)))) { g_dbus_method_invocation_return_error_literal(invocation, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index 310dbbb0a3..1881c141ac 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -959,17 +959,23 @@ typedef enum { * overlapping younger checkpoints. This opts-in that the * checkpoint can be automatically destroyed by the rollback * of an older checkpoint. Since: 1.12. + * @NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS: during rollback, + * by default externally added ports attached to bridge devices are preserved. + * With this flag, the rollback detaches all external ports. + * This only has an effect for bridge ports. Before 1.38, this was the default + * behavior. Since: 1.38. * * The flags for CheckpointCreate call * * Since: 1.4 (gi flags generated since 1.12) */ typedef enum /*< flags >*/ { - NM_CHECKPOINT_CREATE_FLAG_NONE = 0, - NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL = 0x01, - NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS = 0x02, - NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES = 0x04, - NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING = 0x08, + NM_CHECKPOINT_CREATE_FLAG_NONE = 0, + NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL = 0x01, + NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS = 0x02, + NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES = 0x04, + NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING = 0x08, + NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS = 0x10, } NMCheckpointCreateFlags; /** |