summary refs log tree commit diff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/devices/nm-device.c71
-rw-r--r--src/core/devices/nm-device.h2
-rw-r--r--src/core/devices/ovs/nm-device-ovs-port.c8
-rw-r--r--src/core/devices/wwan/nm-modem-broadband.c2
-rw-r--r--src/core/dhcp/nm-dhcp-utils.c2
-rw-r--r--src/core/nm-checkpoint.c5
-rw-r--r--src/core/nm-manager.c35
-rw-r--r--src/core/ppp/nm-ppp-manager.c1
-rw-r--r--src/core/settings/nm-settings.c28
9 files changed, 132 insertions, 22 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 35360cee..a11486d5 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"
@@ -483,9 +484,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;
@@ -7666,8 +7670,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);
 }
 
 /**
@@ -15386,6 +15401,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);
@@ -15791,6 +15816,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 cfcd4ade..a7badb86 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -444,6 +444,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/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c
index 8406c364..116f58c4 100644
--- a/src/core/devices/ovs/nm-device-ovs-port.c
+++ b/src/core/devices/ovs/nm-device-ovs-port.c
@@ -188,8 +188,10 @@ del_iface_cb(GError *error, gpointer user_data)
 static void
 release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
 {
-    NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
-    bool slave_removed = nm_device_sys_iface_state_get(slave) == NM_DEVICE_SYS_IFACE_STATE_REMOVED;
+    NMDeviceOvsPort *self              = NM_DEVICE_OVS_PORT(device);
+    bool             slave_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(slave),
+                                        NM_DEVICE_SYS_IFACE_STATE_MANAGED,
+                                        NM_DEVICE_SYS_IFACE_STATE_ASSUME);
 
     _LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave));
 
@@ -197,7 +199,7 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
      * removed and thus we're called with configure=FALSE), we still need
      * to make sure its OVSDB entry is gone.
      */
-    if (configure || slave_removed) {
+    if (configure || slave_not_managed) {
         nm_ovsdb_del_interface(nm_ovsdb_get(),
                                nm_device_get_iface(slave),
                                del_iface_cb,
diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c
index f5336d37..b585652e 100644
--- a/src/core/devices/wwan/nm-modem-broadband.c
+++ b/src/core/devices/wwan/nm-modem-broadband.c
@@ -1032,6 +1032,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho
         l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET),
                                      ifindex,
                                      NM_IP_CONFIG_SOURCE_WWAN);
+        nm_l3_config_data_set_dns_priority(l3cd, AF_INET, 0);
 
         address = (NMPlatformIP4Address){
             .address      = address_network,
@@ -1118,6 +1119,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho
         l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET),
                                      ifindex,
                                      NM_IP_CONFIG_SOURCE_WWAN);
+        nm_l3_config_data_set_dns_priority(l3cd, AF_INET6, 0);
 
         do_auto = TRUE;
 
diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c
index 4a138086..214e94cd 100644
--- a/src/core/dhcp/nm-dhcp-utils.c
+++ b/src/core/dhcp/nm-dhcp-utils.c
@@ -876,7 +876,7 @@ nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData  *l3cd_old,
      * addresses from the same transaction into a single configuration.
      **/
 
-    l3cd_merged = nm_l3_config_data_new_clone(l3cd_old, -1);
+    l3cd_merged = nm_l3_config_data_new_clone(l3cd_old, 0);
 
     nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd_new, &addr)
         nm_l3_config_data_add_address_6(l3cd_merged, addr);
diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c
index 0153af97..5b48f91a 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 b440b224..6c73d237 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -7453,15 +7453,31 @@ impl_manager_checkpoint_create(NMDBusObject                      *obj,
                                GDBusMethodInvocation             *invocation,
                                GVariant                          *parameters)
 {
-    NMManager        *self = NM_MANAGER(obj);
-    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
-    NMAuthChain      *chain;
-    char            **devices;
-    guint32           rollback_timeout;
-    guint32           flags;
+    NMManager         *self = NM_MANAGER(obj);
+    NMManagerPrivate  *priv = NM_MANAGER_GET_PRIVATE(self);
+    NMAuthChain       *chain;
+    gs_strfreev char **devices = NULL;
+    guint32            rollback_timeout;
+    guint32            flags;
 
     G_STATIC_ASSERT_EXPR(sizeof(flags) <= sizeof(NMCheckpointCreateFlags));
 
+    g_variant_get(parameters, "(^aouu)", &devices, &rollback_timeout, &flags);
+
+    if ((NMCheckpointCreateFlags) flags != flags
+        || NM_FLAGS_ANY(flags,
+                        ~((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_NO_PRESERVE_EXTERNAL_PORTS)))) {
+        g_dbus_method_invocation_return_error_literal(invocation,
+                                                      NM_MANAGER_ERROR,
+                                                      NM_MANAGER_ERROR_INVALID_ARGUMENTS,
+                                                      "Invalid flags");
+        return;
+    }
+
     chain = nm_auth_chain_new_context(invocation, checkpoint_auth_done_cb, self);
     if (!chain) {
         g_dbus_method_invocation_return_error_literal(invocation,
@@ -7471,11 +7487,12 @@ impl_manager_checkpoint_create(NMDBusObject                      *obj,
         return;
     }
 
-    g_variant_get(parameters, "(^aouu)", &devices, &rollback_timeout, &flags);
-
     c_list_link_tail(&priv->auth_lst_head, nm_auth_chain_parent_lst_list(chain));
     nm_auth_chain_set_data(chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_CREATE, NULL);
-    nm_auth_chain_set_data(chain, "devices", devices, (GDestroyNotify) g_strfreev);
+    nm_auth_chain_set_data(chain,
+                           "devices",
+                           g_steal_pointer(&devices),
+                           (GDestroyNotify) g_strfreev);
     nm_auth_chain_set_data(chain, "flags", GUINT_TO_POINTER(flags), NULL);
     nm_auth_chain_set_data(chain, "timeout", GUINT_TO_POINTER(rollback_timeout), NULL);
     nm_auth_chain_add_call(chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c
index dd6b1bc7..5761d59d 100644
--- a/src/core/ppp/nm-ppp-manager.c
+++ b/src/core/ppp/nm-ppp-manager.c
@@ -545,6 +545,7 @@ impl_ppp_manager_set_ip4_config(NMDBusObject                      *obj,
                                  NM_IP_CONFIG_SOURCE_PPP);
 
     nm_l3_config_data_set_mtu(l3cd, mtu);
+    nm_l3_config_data_set_dns_priority(l3cd, AF_INET, 0);
 
     address = (NMPlatformIP4Address){
         .plen = 32,
diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c
index da09571b..6619d3e0 100644
--- a/src/core/settings/nm-settings.c
+++ b/src/core/settings/nm-settings.c
@@ -3266,7 +3266,7 @@ add_plugin(NMSettings *self, NMSettingsPlugin *plugin, const char *pname, const
 }
 
 static gboolean
-add_plugin_load_file(NMSettings *self, const char *pname, GError **error)
+add_plugin_load_file(NMSettings *self, const char *pname, gboolean ignore_not_found, GError **error)
 {
     gs_free char                     *full_name = NULL;
     gs_free char                     *path      = NULL;
@@ -3281,10 +3281,12 @@ add_plugin_load_file(NMSettings *self, const char *pname, GError **error)
 
     if (stat(path, &st) != 0) {
         errsv = errno;
-        _LOGW("could not load plugin '%s' from file '%s': %s",
-              pname,
-              path,
-              nm_strerror_native(errsv));
+        if (!ignore_not_found) {
+            _LOGW("could not load plugin '%s' from file '%s': %s",
+                  pname,
+                  path,
+                  nm_strerror_native(errsv));
+        }
         return TRUE;
     }
     if (!S_ISREG(st.st_mode)) {
@@ -3378,7 +3380,7 @@ load_plugins(NMSettings *self, const char *const *plugins, GError **error)
             continue;
         }
 
-        success = add_plugin_load_file(self, pname, error);
+        success = add_plugin_load_file(self, pname, FALSE, error);
         if (!success)
             break;
     }
@@ -3872,8 +3874,18 @@ nm_settings_start(NMSettings *self, GError **error)
     /* Load the plugins; fail if a plugin is not found. */
     plugins = nm_config_data_get_plugins(nm_config_get_data_orig(priv->config), TRUE);
 
-    if (!load_plugins(self, (const char *const *) plugins, error))
-        return FALSE;
+    if (plugins && plugins[0]) {
+        if (!load_plugins(self, (const char *const *) plugins, error))
+            return FALSE;
+    } else {
+        add_plugin_keyfile(self);
+#if WITH_CONFIG_PLUGIN_IFCFG_RH
+        add_plugin_load_file(self, "ifcfg-rh", TRUE, NULL);
+#endif
+#if WITH_CONFIG_PLUGIN_IFUPDOWN
+        add_plugin_load_file(self, "ifupdown", TRUE, NULL);
+#endif
+    }
 
     for (iter = priv->plugins; iter; iter = iter->next) {
         NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN(iter->data);