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-hsr.c36
-rw-r--r--src/core/devices/nm-device-utils.c6
-rw-r--r--src/core/devices/nm-device.c265
-rw-r--r--src/core/devices/nm-device.h23
-rw-r--r--src/core/devices/ovs/nm-ovsdb.c32
-rw-r--r--src/core/nm-manager.c110
-rw-r--r--src/core/nm-manager.h4
-rw-r--r--src/core/nm-policy.c97
8 files changed, 349 insertions, 224 deletions
diff --git a/src/core/devices/nm-device-hsr.c b/src/core/devices/nm-device-hsr.c
index 59454ee3..e3368a5b 100644
--- a/src/core/devices/nm-device-hsr.c
+++ b/src/core/devices/nm-device-hsr.c
@@ -116,29 +116,51 @@ create_and_realize(NMDevice              *device,
                    const NMPlatformLink **out_plink,
                    GError               **error)
 {
-    const char      *iface = nm_device_get_iface(device);
-    NMSettingHsr    *s_hsr;
-    NMPlatformLnkHsr lnk = {};
-    int              r;
+    const char        *iface   = nm_device_get_iface(device);
+    nm_auto_free char *err_msg = NULL;
+    NMSettingHsr      *s_hsr;
+    NMPlatformLnkHsr   lnk = {};
+    int                r   = 0;
 
     s_hsr = _nm_connection_get_setting(connection, NM_TYPE_SETTING_HSR);
+
     nm_assert(s_hsr);
 
     if (nm_setting_hsr_get_port1(s_hsr) != NULL)
         lnk.port1 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port1(s_hsr));
     if (nm_setting_hsr_get_port2(s_hsr) != NULL)
         lnk.port2 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port2(s_hsr));
-    lnk.multicast_spec = nm_setting_hsr_get_multicast_spec(s_hsr);
-    lnk.prp            = nm_setting_hsr_get_prp(s_hsr);
+    if (nm_setting_hsr_get_interlink(s_hsr) != NULL) {
+        const char *ifname  = nm_setting_hsr_get_interlink(s_hsr);
+        int         ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, ifname);
+
+        if (ifindex <= 0) {
+            err_msg = g_strdup_printf("interlink port '%s' does not exist", ifname);
+            goto out;
+        }
+
+        lnk.interlink = ifindex;
+    }
+
+    lnk.multicast_spec   = nm_setting_hsr_get_multicast_spec(s_hsr);
+    lnk.prp              = nm_setting_hsr_get_prp(s_hsr);
+    lnk.protocol_version = nm_setting_hsr_get_protocol_version(s_hsr);
+
     r = nm_platform_link_hsr_add(nm_device_get_platform(device), iface, &lnk, out_plink);
+
     if (r < 0) {
+        err_msg = g_strdup(nm_strerror(r) ?: "unknown");
+    }
+
+out:
+    if (err_msg) {
         g_set_error(error,
                     NM_DEVICE_ERROR,
                     NM_DEVICE_ERROR_CREATION_FAILED,
                     "Failed to create HSR interface '%s' for '%s': %s",
                     iface,
                     nm_connection_get_id(connection),
-                    nm_strerror(r));
+                    err_msg);
         return FALSE;
     }
 
diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c
index 9fd7ac9d..a78499fb 100644
--- a/src/core/devices/nm-device-utils.c
+++ b/src/core/devices/nm-device-utils.c
@@ -135,13 +135,15 @@ NM_UTILS_LOOKUP_STR_DEFINE(
     NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT,
                              "unmanaged-link-not-init"),
     NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING, "unmanaged-quitting"),
-    NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING, "unmanaged-sleeping"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED,
+                             "unmanaged-nm-disabled"),
     NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF, "unmanaged-user-conf"),
     NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT,
                              "unmanaged-user-explicit"),
     NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS,
                              "unmanaged-user-settings"),
-    NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"), );
+    NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NETWORKING_OFF, "networking-off"), );
 
 NM_UTILS_LOOKUP_STR_DEFINE(nm_device_mtu_source_to_string,
                            NMDeviceMtuSource,
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 79b1076d..6bba982a 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -692,6 +692,8 @@ typedef struct _NMDevicePrivate {
 
     IPDevStateData ipdev_data_unspec;
 
+    gulong sharing_ipv4_changed_id;
+
     struct {
         /* If we set the addrgenmode6, this records the previously set value. */
         guint8 previous_mode_val;
@@ -779,7 +781,6 @@ typedef struct _NMDevicePrivate {
     char     *prop_ip_iface; /* IP interface D-Bus property */
     GList    *ping_operations;
     GSource  *ping_timeout;
-    bool      refresh_forwarding_done : 1;
 } NMDevicePrivate;
 
 G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT)
@@ -867,6 +868,8 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self);
 
 static void _dev_ipshared6_start(NMDevice *self);
 
+static void _dev_ipforwarding4_start(NMDevice *self, int addr_family);
+
 static void
 _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp);
 
@@ -2131,8 +2134,8 @@ _prop_get_ipvx_dhcp_send_hostname(NMDevice *self, int addr_family)
     return send_hostname_v2;
 }
 
-NMSettingIPConfigForwarding
-nm_device_get_ipv4_forwarding(NMDevice *self)
+static NMSettingIPConfigForwarding
+_prop_get_ipv4_forwarding(NMDevice *self)
 {
     NMSettingIPConfig          *s_ip;
     NMSettingIPConfigForwarding forwarding;
@@ -3778,7 +3781,7 @@ nm_device_assume_state_reset(NMDevice *self)
 
 /*****************************************************************************/
 
-char *
+static char *
 nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property)
 {
     const char *ifname;
@@ -6645,7 +6648,7 @@ concheck_update_state(NMDevice           *self,
     }
 }
 
-const char *
+static const char *
 nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family)
 {
     NMDeviceClass *klass;
@@ -8639,6 +8642,8 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error)
 
     g_object_thaw_notify(G_OBJECT(self));
 
+    nm_device_managed_type_set(self, NM_DEVICE_MANAGED_TYPE_REMOVED);
+
     nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
 
     nm_device_set_unmanaged_flags(self,
@@ -10394,6 +10399,43 @@ sriov_params_cb(GError *error, gpointer user_data)
     nm_device_activate_schedule_stage1_device_prepare(self, FALSE);
 }
 
+static gboolean
+sriov_gen_platform_vfs(NMDevice       *self,
+                       NMSettingSriov *s_sriov,
+                       NMPlatformVF ***plat_vfs_out,
+                       GError        **error)
+{
+    nm_auto_freev NMPlatformVF **plat_vfs = NULL;
+    guint                        num;
+
+    nm_assert(s_sriov);
+    nm_assert(plat_vfs_out && !*plat_vfs_out);
+
+    num      = nm_setting_sriov_get_num_vfs(s_sriov);
+    plat_vfs = g_new0(NMPlatformVF *, num + 1);
+
+    for (int i = 0; i < num; i++) {
+        NMSriovVF            *vf    = nm_setting_sriov_get_vf(s_sriov, i);
+        gs_free_error GError *local = NULL;
+
+        plat_vfs[i] = sriov_vf_config_to_platform(self, vf, &local);
+
+        if (!plat_vfs[i]) {
+            g_set_error(error,
+                        local->domain,
+                        local->code,
+                        "VF '%s' is invalid: %s",
+                        nm_utils_sriov_vf_to_str(vf, FALSE, NULL),
+                        local->message);
+            return FALSE;
+        }
+    }
+
+    *plat_vfs_out = g_steal_pointer(&plat_vfs);
+
+    return TRUE;
+}
+
 /*
  * activate_stage1_device_prepare
  *
@@ -10440,10 +10482,7 @@ activate_stage1_device_prepare(NMDevice *self)
         if (s_sriov && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)) {
             nm_auto_freev NMPlatformVF **plat_vfs = NULL;
             gs_free_error GError        *error    = NULL;
-            NMSriovVF                   *vf;
             NMTernary                    autoprobe;
-            guint                        num;
-            guint                        i;
 
             autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov);
             if (autoprobe == NM_TERNARY_DEFAULT) {
@@ -10456,21 +10495,12 @@ activate_stage1_device_prepare(NMDevice *self)
                     NM_OPTION_BOOL_TRUE);
             }
 
-            num      = nm_setting_sriov_get_num_vfs(s_sriov);
-            plat_vfs = g_new0(NMPlatformVF *, num + 1);
-            for (i = 0; i < num; i++) {
-                vf          = nm_setting_sriov_get_vf(s_sriov, i);
-                plat_vfs[i] = sriov_vf_config_to_platform(self, vf, &error);
-                if (!plat_vfs[i]) {
-                    _LOGE(LOGD_DEVICE,
-                          "failed to apply SR-IOV VF '%s': %s",
-                          nm_utils_sriov_vf_to_str(vf, FALSE, NULL),
-                          error->message);
-                    nm_device_state_changed(self,
-                                            NM_DEVICE_STATE_FAILED,
-                                            NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED);
-                    return;
-                }
+            if (!sriov_gen_platform_vfs(self, s_sriov, &plat_vfs, &error)) {
+                _LOGE(LOGD_DEVICE, "cannot parse the VF list: %s", error->message);
+                nm_device_state_changed(self,
+                                        NM_DEVICE_STATE_FAILED,
+                                        NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED);
+                return;
             }
 
             /* When changing the number of VFs the kernel can block
@@ -13139,17 +13169,12 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family)
         goto out_devip;
 
     if (IS_IPv4) {
-        NMSettingIPConfigForwarding ipv4_forwarding = nm_device_get_ipv4_forwarding(self);
-
-        if (NM_IN_SET(ipv4_forwarding,
-                      NM_SETTING_IP_CONFIG_FORWARDING_NO,
-                      NM_SETTING_IP_CONFIG_FORWARDING_YES)) {
-            nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", ipv4_forwarding ? "1" : "0");
-        }
         priv->ipll_data_4.v4.mode = _prop_get_ipv4_link_local(self);
         if (priv->ipll_data_4.v4.mode == NM_SETTING_IP4_LL_ENABLED)
             _dev_ipll4_start(self);
 
+        _dev_ipforwarding4_start(self, addr_family);
+
         if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
             _dev_ipdhcpx_start(self, AF_INET);
         else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
@@ -13469,15 +13494,21 @@ nm_device_activate_schedule_stage3_ip_config(NMDevice *self, gboolean do_sync)
 static void
 _dev_ipsharedx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state)
 {
-    NMDevicePrivate *priv    = NM_DEVICE_GET_PRIVATE(self);
-    const int        IS_IPv4 = NM_IS_IPv4(addr_family);
+    NMDevicePrivate *priv      = NM_DEVICE_GET_PRIVATE(self);
+    const int        IS_IPv4   = NM_IS_IPv4(addr_family);
+    NMDeviceIPState  old_state = priv->ipshared_data_x[IS_IPv4].state;
 
-    if (priv->ipshared_data_x[IS_IPv4].state != state) {
+    if (old_state != state) {
         _LOGD_ipshared(addr_family,
                        "set state %s (was %s)",
                        nm_device_ip_state_to_string(state),
-                       nm_device_ip_state_to_string(priv->ipshared_data_x[IS_IPv4].state));
+                       nm_device_ip_state_to_string(old_state));
         priv->ipshared_data_x[IS_IPv4].state = state;
+
+        if (old_state == NM_DEVICE_IP_STATE_READY || state == NM_DEVICE_IP_STATE_READY)
+            nm_manager_update_shared_connection(NM_MANAGER_GET,
+                                                addr_family,
+                                                state == NM_DEVICE_IP_STATE_READY);
     }
 }
 
@@ -13772,6 +13803,106 @@ _dev_ipshared6_start(NMDevice *self)
 
 /*****************************************************************************/
 
+/**
+ * Set the device's forwarding to the specified value. If %NM_TERNARY_DEFAULT is specified,
+ * it's set to the kernel's default, otherwise it's set to the specific value.
+ */
+static void
+_dev_ipforwarding4_set(NMDevice *self, NMTernary val)
+{
+    gs_free const char *default_forwarding = NULL;
+    gs_free const char *current_forwarding = NULL;
+    const char         *val_str;
+
+    if (val != NM_TERNARY_DEFAULT) {
+        val_str = val ? "1" : "0";
+    } else {
+        default_forwarding = nm_platform_sysctl_get(
+            nm_device_get_platform(self),
+            NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"));
+
+        if (!default_forwarding) {
+            _LOGW(LOGD_DEVICE,
+                  "error setting IPv4 forwarding: can't read default forwarding value: %s",
+                  nm_strerror_native(errno));
+            return; /* Non fatal */
+        }
+
+        val_str = default_forwarding;
+    }
+
+    current_forwarding = nm_device_sysctl_ip_conf_get(self, AF_INET, "forwarding");
+    if (nm_streq0(current_forwarding, val_str))
+        return;
+
+    if (!nm_device_sysctl_ip_conf_set(self, AF_INET, "forwarding", val_str))
+        _LOGW(LOGD_DEVICE,
+              "error setting IPv4 forwarding to '%s': %s",
+              val_str,
+              nm_strerror_native(errno));
+}
+
+static void
+_dev_ipforwarding4_auto_cb(NMManager *manager, gboolean sharing_ipv4, gpointer data)
+{
+    NMDevice *self = NM_DEVICE(data);
+
+    _dev_ipforwarding4_set(self, sharing_ipv4 ? NM_TERNARY_TRUE : NM_TERNARY_DEFAULT);
+}
+
+static void
+_dev_ipforwarding4_start(NMDevice *self, int addr_family)
+{
+    NMDevicePrivate            *priv            = NM_DEVICE_GET_PRIVATE(self);
+    NMSettingIPConfigForwarding ipv4_forwarding = _prop_get_ipv4_forwarding(self);
+    NMTernary                   new_forwarding  = NM_TERNARY_DEFAULT;
+
+    /* IPv6 per-interface forwarding not supported yet */
+    if (addr_family != AF_INET)
+        return;
+
+    if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
+        new_forwarding = NM_TERNARY_TRUE;
+    } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_YES) {
+        new_forwarding = NM_TERNARY_TRUE;
+    } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_NO) {
+        new_forwarding = NM_TERNARY_FALSE;
+    } else if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO) {
+        if (nm_manager_get_sharing_ipv4(NM_MANAGER_GET))
+            new_forwarding = NM_TERNARY_TRUE;
+        else
+            new_forwarding = NM_TERNARY_DEFAULT;
+
+        if (!priv->sharing_ipv4_changed_id)
+            priv->sharing_ipv4_changed_id = g_signal_connect(NM_MANAGER_GET,
+                                                             NM_MANAGER_SHARING_IPV4_CHANGED,
+                                                             G_CALLBACK(_dev_ipforwarding4_auto_cb),
+                                                             self);
+    } else {
+        nm_assert_not_reached();
+    }
+
+    _dev_ipforwarding4_set(self, new_forwarding);
+}
+
+static void
+_dev_ipforwarding_cleanup(NMDevice *self, int addr_family, CleanupType cleanup_type)
+{
+    NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
+    if (!NM_IS_IPv4(addr_family))
+        return;
+
+    nm_clear_g_signal_handler(NM_MANAGER_GET, &priv->sharing_ipv4_changed_id);
+
+    if (NM_IN_SET(cleanup_type, CLEANUP_TYPE_DECONFIGURE, CLEANUP_TYPE_KEEP_REAPPLY)) {
+        /* Deconfigure by restoring kernel's default */
+        _dev_ipforwarding4_set(self, NM_TERNARY_DEFAULT);
+    }
+}
+
+/*****************************************************************************/
+
 static void
 act_request_set(NMDevice *self, NMActRequest *act_request)
 {
@@ -13884,6 +14015,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool
     NMDevicePrivate *priv         = NM_DEVICE_GET_PRIVATE(self);
     gboolean         keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY);
 
+    _dev_ipforwarding_cleanup(self, addr_family, cleanup_type);
+
     _dev_ipsharedx_cleanup(self, addr_family);
 
     _dev_ipdev_cleanup(self, AF_UNSPEC);
@@ -14066,7 +14199,8 @@ can_reapply_change(NMDevice   *self,
         return nm_device_hash_check_invalid_keys(diffs,
                                                  NM_SETTING_SRIOV_SETTING_NAME,
                                                  error,
-                                                 NM_SETTING_SRIOV_PRESERVE_ON_DOWN);
+                                                 NM_SETTING_SRIOV_PRESERVE_ON_DOWN,
+                                                 NM_SETTING_SRIOV_VFS);
     }
 
 out_fail:
@@ -14244,9 +14378,35 @@ check_and_reapply_connection(NMDevice            *self,
 
     nm_device_link_properties_set(self, TRUE);
 
-    if (priv->state >= NM_DEVICE_STATE_CONFIG)
+    if (priv->state >= NM_DEVICE_STATE_CONFIG) {
+        GHashTable *sriov_diff;
+
         lldp_setup(self, NM_TERNARY_DEFAULT);
 
+        sriov_diff = nm_g_hash_table_lookup(diffs, NM_SETTING_SRIOV_SETTING_NAME);
+
+        if (sriov_diff && nm_g_hash_table_lookup(sriov_diff, NM_SETTING_SRIOV_VFS)) {
+            nm_auto_freev NMPlatformVF **plat_vfs = NULL;
+            NMSettingSriov              *s_sriov;
+
+            s_sriov = (NMSettingSriov *) nm_connection_get_setting(applied, NM_TYPE_SETTING_SRIOV);
+
+            if (s_sriov) {
+                gs_free_error GError *local = NULL;
+
+                if (!sriov_gen_platform_vfs(self, s_sriov, &plat_vfs, &local)
+                    || !nm_platform_link_set_sriov_vfs(nm_device_get_platform(self),
+                                                       priv->ifindex,
+                                                       (const NMPlatformVF *const *) plat_vfs)) {
+                    _LOGE(LOGD_DEVICE,
+                          "failed to reapply SRIOV VFs%s%s",
+                          local ? ": " : "",
+                          local ? local->message : "");
+                }
+            }
+        }
+    }
+
     if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) {
         /* Allow reapply of MTU */
         priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE;
@@ -15613,7 +15773,7 @@ nm_device_get_firmware_missing(NMDevice *self)
 
 NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str,
                           NMUnmanagedFlags,
-                          NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"),
+                          NM_UTILS_FLAGS2STR(NM_UNMANAGED_MANAGER_DISABLED, "nm-disabled"),
                           NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"),
                           NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
                           NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
@@ -15677,8 +15837,8 @@ unmanaged_flags_to_reason(NMUnmanagedFlags flags)
     /* Even if there are multiple flags, we can only return one reason.
      * Return the most important reason.
      */
-    if (NM_FLAGS_HAS(flags, NM_UNMANAGED_SLEEPING))
-        return NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING;
+    if (NM_FLAGS_HAS(flags, NM_UNMANAGED_MANAGER_DISABLED))
+        return NM_DEVICE_STATE_REASON_UNMANAGED_MANAGER_DISABLED;
     if (NM_FLAGS_HAS(flags, NM_UNMANAGED_QUITTING))
         return NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING;
     if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_SETTINGS))
@@ -16923,8 +17083,6 @@ _cleanup_generic_post(NMDevice *self, NMDeviceStateReason reason, CleanupType cl
     priv->v4_route_table_all_sync_before = FALSE;
     priv->v6_route_table_all_sync_before = FALSE;
 
-    priv->refresh_forwarding_done = FALSE;
-
     priv->mtu_force_set_done = FALSE;
 
     priv->needs_ip6_subnet = FALSE;
@@ -16970,7 +17128,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
     NMDevicePrivate *priv;
     NMDeviceClass   *klass = NM_DEVICE_GET_CLASS(self);
     int              ifindex;
-    gint32           default_forwarding_v4;
 
     g_return_if_fail(NM_IS_DEVICE(self));
 
@@ -16993,17 +17150,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
         nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0");
     }
 
-    /* Restoring the device's forwarding to the sysctl default is necessary because
-     * `refresh_forwarding()` only updates forwarding on activated devices. */
-    default_forwarding_v4 = nm_platform_sysctl_get_int32(
-        nm_device_get_platform(self),
-        NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"),
-        0);
-    nm_device_sysctl_ip_conf_set(self,
-                                 AF_INET,
-                                 "forwarding",
-                                 default_forwarding_v4 == 1 ? "1" : "0");
-
     /* Call device type-specific deactivation */
     if (klass->deactivate)
         klass->deactivate(self);
@@ -18947,19 +19093,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean
     return nm_assert_unreachable_val(NULL);
 }
 
-gboolean
-nm_device_get_refresh_forwarding_done(NMDevice *self)
-{
-    return NM_DEVICE_GET_PRIVATE(self)->refresh_forwarding_done;
-}
-
-void
-nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done)
-{
-    NMDevicePrivate *priv         = NM_DEVICE_GET_PRIVATE(self);
-    priv->refresh_forwarding_done = is_refresh_forwarding_done;
-}
-
 /*****************************************************************************/
 
 static const char *
diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h
index 9a663c2a..8632944a 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -581,7 +581,8 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device);
 /**
  * NMUnmanagedFlags:
  * @NM_UNMANAGED_NONE: placeholder value
- * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
+ * @NM_UNMANAGED_MANAGER_DISABLED: %TRUE when unmanaged because NM is disabled.
+ *   Currently, this happens when sleeping or with networking disabled.
  * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
  * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
  *   yet initialized. Unrealized device are also unmanaged for this reason.
@@ -610,11 +611,11 @@ typedef enum {
 
     /* these flags are authoritative. If one of them is set,
      * the device cannot be managed. */
-    NM_UNMANAGED_SLEEPING      = (1LL << 0),
-    NM_UNMANAGED_QUITTING      = (1LL << 1),
-    NM_UNMANAGED_PLATFORM_INIT = (1LL << 2),
-    NM_UNMANAGED_USER_EXPLICIT = (1LL << 3),
-    NM_UNMANAGED_USER_SETTINGS = (1LL << 4),
+    NM_UNMANAGED_MANAGER_DISABLED = (1LL << 0),
+    NM_UNMANAGED_QUITTING         = (1LL << 1),
+    NM_UNMANAGED_PLATFORM_INIT    = (1LL << 2),
+    NM_UNMANAGED_USER_EXPLICIT    = (1LL << 3),
+    NM_UNMANAGED_USER_SETTINGS    = (1LL << 4),
 
     /* These flags can be non-effective and be overwritten
      * by other flags. */
@@ -852,14 +853,4 @@ void nm_routing_rules_sync(NMConnection *applied_connection,
                            NMDevice *self,
                            NMNetns  *netns);
 
-NMSettingIPConfigForwarding nm_device_get_ipv4_forwarding(NMDevice *self);
-
-const char *nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family);
-
-char *nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property);
-
-gboolean nm_device_get_refresh_forwarding_done(NMDevice *self);
-
-void nm_device_set_refresh_forwarding_done(NMDevice *self, gboolean is_refresh_forwarding_done);
-
 #endif /* __NETWORKMANAGER_DEVICE_H__ */
diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c
index 164bfd35..1c9484c4 100644
--- a/src/core/devices/ovs/nm-ovsdb.c
+++ b/src/core/devices/ovs/nm-ovsdb.c
@@ -1460,40 +1460,42 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
                 json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid));
             }
 
-            if (num_nm_interfaces == 0) {
-                /* The port no longer has any NM interface. Don't add it to "new_ports" and set
-                 * ports_changed=TRUE, so that it will be deleted. */
+            if (interfaces_changed && num_nm_interfaces == 0) {
+                /* We are deleting the last nm-interface of this port. Don't add it to "new_ports"
+                 * and set ports_changed=TRUE, so that it will be deleted. */
                 ports_changed = TRUE;
             } else {
+                /* Keep this port: it's still alive, or it's unrelated to the deleted interface */
+                json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid));
+                if (ovs_port->connection_uuid)
+                    num_nm_ports++;
+
                 if (interfaces_changed) {
-                    /* An interface needs to be deleted from this port */
+                    /* This port is still alive, but an interface needs to be deleted from it */
                     _expect_port_interfaces(params, ovs_port->name, interfaces);
                     _set_port_interfaces(params, ovs_port->name, new_interfaces);
                 }
-                /* The port is still alive */
-                json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid));
-                if (ovs_port->connection_uuid)
-                    num_nm_ports++;
             }
         }
 
-        if (num_nm_ports == 0) {
-            /* The bridge no longer has any NM port. Don't add it to "new_bridges" and set
-             * bridges_changed=TRUE, so that it will be deleted. */
+        if (ports_changed && num_nm_ports == 0) {
+            /* We are deleting the last nm-port of this bridge. Don't add it to "new_bridges"
+             * and set bridges_changed=TRUE, so that it will be deleted. */
             bridges_changed = TRUE;
         } else {
+            /* Keep this bridge: it's still alive, or it's unrelated to the deleted interface */
+            json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
+
             if (ports_changed) {
-                /* A port needs to be deleted from this bridge */
+                /* This bridge is still alive, but a port needs to be deleted from it */
                 _expect_bridge_ports(params, ovs_bridge->name, ports);
                 _set_bridge_ports(params, ovs_bridge->name, new_ports);
             }
-            /* The bridge is still alive */
-            json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
         }
     }
 
     if (bridges_changed) {
-        /* A port needs to be deleted from this bridge */
+        /* A bridge needs to be deleted */
         _expect_ovs_bridges(params, priv->db_uuid, bridges);
         _set_ovs_bridges(params, priv->db_uuid, new_bridges);
     }
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 9dc7bc01..87dde2c3 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -136,6 +136,7 @@ enum {
     ACTIVE_CONNECTION_REMOVED,
     CONFIGURE_QUIT,
     DEVICE_IFINDEX_CHANGED,
+    SHARING_IPV4_CHANGED,
 
     LAST_SIGNAL
 };
@@ -238,6 +239,8 @@ typedef struct {
 
     guint8 device_state_prune_ratelimit_count;
 
+    guint shared_connections_ip4_count;
+
     bool startup : 1;
     bool devices_inited : 1;
 
@@ -1960,7 +1963,7 @@ find_device_by_iface(NMManager    *self,
 }
 
 static gboolean
-manager_sleeping(NMManager *self)
+manager_is_disabled(NMManager *self)
 {
     NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
 
@@ -1973,8 +1976,8 @@ static const char *
 _nm_state_to_string(NMState state)
 {
     switch (state) {
-    case NM_STATE_ASLEEP:
-        return "ASLEEP";
+    case NM_STATE_DISABLED:
+        return "DISABLED";
     case NM_STATE_DISCONNECTED:
         return "DISCONNECTED";
     case NM_STATE_DISCONNECTING:
@@ -2078,15 +2081,18 @@ nm_manager_update_state(NMManager *self)
 {
     NMManagerPrivate *priv;
     NMState           new_state = NM_STATE_DISCONNECTED;
+    const char       *detail    = "";
 
     g_return_if_fail(NM_IS_MANAGER(self));
 
     priv = NM_MANAGER_GET_PRIVATE(self);
 
-    if (manager_sleeping(self))
-        new_state = NM_STATE_ASLEEP;
-    else
+    if (manager_is_disabled(self)) {
+        new_state = NM_STATE_DISABLED;
+        detail    = priv->sleeping ? " (ASLEEP)" : " (NETWORKING OFF)";
+    } else {
         new_state = find_best_device_state(self);
+    }
 
     if (new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) {
         new_state = NM_STATE_CONNECTED_GLOBAL;
@@ -2097,7 +2103,7 @@ nm_manager_update_state(NMManager *self)
 
     priv->state = new_state;
 
-    _LOGI(LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string(new_state));
+    _LOGI(LOGD_CORE, "NetworkManager state is now %s%s", _nm_state_to_string(new_state), detail);
 
     _notify(self, PROP_STATE);
     nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self),
@@ -2956,7 +2962,7 @@ _rfkill_update_devices(NMManager *self, NMRfkillType rtype, gboolean enabled)
     _notify(self, _rfkill_type_desc[rtype].prop_id);
 
     /* Don't touch devices if asleep/networking disabled */
-    if (manager_sleeping(self))
+    if (manager_is_disabled(self))
         return;
 
     /* enable/disable wireless devices as required */
@@ -3120,7 +3126,7 @@ _rfkill_update_from_user(NMManager *self, NMRfkillType rtype, gboolean enabled)
     gboolean          old_enabled, new_enabled;
 
     /* Don't touch devices if asleep/networking disabled */
-    if (manager_sleeping(self))
+    if (manager_is_disabled(self))
         return;
 
     _LOGD(LOGD_RFKILL,
@@ -4079,7 +4085,7 @@ add_device(NMManager *self, NMDevice *device, GError **error)
 
     nm_device_set_unmanaged_by_user_settings(device, TRUE);
 
-    nm_device_set_unmanaged_flags(device, NM_UNMANAGED_SLEEPING, manager_sleeping(self));
+    nm_device_set_unmanaged_flags(device, NM_UNMANAGED_MANAGER_DISABLED, manager_is_disabled(self));
 
     dbus_path = nm_dbus_object_export(NM_DBUS_OBJECT(device));
     _LOG2I(LOGD_DEVICE, device, "new %s device (%s)", type_desc, dbus_path);
@@ -7299,7 +7305,7 @@ device_sleep_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
     case NM_DEVICE_STATE_DISCONNECTED:
         _LOGD(LOGD_SUSPEND, "sleep: unmanaging device %s", nm_device_get_ip_iface(device));
         nm_device_set_unmanaged_by_flags_queue(device,
-                                               NM_UNMANAGED_SLEEPING,
+                                               NM_UNMANAGED_MANAGER_DISABLED,
                                                NM_UNMAN_FLAG_OP_SET_UNMANAGED,
                                                NM_DEVICE_STATE_REASON_SLEEPING);
         break;
@@ -7321,24 +7327,26 @@ _handle_device_takedown(NMManager *self,
                         gboolean   suspending,
                         gboolean   is_shutdown)
 {
+    gboolean            is_sleep = suspending || is_shutdown;
+    NMDeviceStateReason reason =
+        is_sleep ? NM_DEVICE_STATE_REASON_SLEEPING : NM_DEVICE_STATE_REASON_NETWORKING_OFF;
+
     nm_device_notify_sleeping(device);
 
     if (nm_device_is_activating(device)
         || nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) {
-        _LOGD(LOGD_SUSPEND,
+        _LOGD(is_sleep ? LOGD_SUSPEND : LOGD_CORE,
               "%s: wait disconnection of device %s",
-              is_shutdown ? "shutdown" : "sleep",
+              is_sleep ? (is_shutdown ? "shutdown" : "sleep") : "networking off",
               nm_device_get_ip_iface(device));
 
         if (sleep_devices_add(self, device, suspending))
-            nm_device_queue_state(device,
-                                  NM_DEVICE_STATE_DEACTIVATING,
-                                  NM_DEVICE_STATE_REASON_SLEEPING);
+            nm_device_queue_state(device, NM_DEVICE_STATE_DEACTIVATING, reason);
     } else {
         nm_device_set_unmanaged_by_flags(device,
-                                         NM_UNMANAGED_SLEEPING,
+                                         NM_UNMANAGED_MANAGER_DISABLED,
                                          NM_UNMAN_FLAG_OP_SET_UNMANAGED,
-                                         NM_DEVICE_STATE_REASON_SLEEPING);
+                                         reason);
     }
 }
 
@@ -7352,8 +7360,10 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
     suspending          = sleeping_changed && priv->sleeping;
     waking_from_suspend = sleeping_changed && !priv->sleeping;
 
-    if (manager_sleeping(self)) {
-        _LOGD(LOGD_SUSPEND, "sleep: %s...", suspending ? "sleeping" : "disabling");
+    if (manager_is_disabled(self)) {
+        _LOGD(suspending ? LOGD_SUSPEND : LOGD_CORE,
+              "%s...",
+              suspending ? "sleep: sleeping" : "networking: disabling");
 
         /* FIXME: are there still hardware devices that need to be disabled around
          * suspend/resume?
@@ -7379,7 +7389,9 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
             _handle_device_takedown(self, device, suspending, FALSE);
         }
     } else {
-        _LOGD(LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling");
+        _LOGD(waking_from_suspend ? LOGD_SUSPEND : LOGD_CORE,
+              "%s...",
+              waking_from_suspend ? "sleep: waking up" : "networking: re-enabling");
 
         sleep_devices_clear(self);
 
@@ -7393,7 +7405,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
                  */
                 if (device_is_wake_on_lan(priv->platform, device))
                     nm_device_set_unmanaged_by_flags(device,
-                                                     NM_UNMANAGED_SLEEPING,
+                                                     NM_UNMANAGED_MANAGER_DISABLED,
                                                      NM_UNMAN_FLAG_OP_SET_UNMANAGED,
                                                      NM_DEVICE_STATE_REASON_SLEEPING);
 
@@ -7421,10 +7433,12 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
             guint               i;
 
             if (nm_device_is_software(device)
-                && !nm_device_get_unmanaged_flags(device, NM_UNMANAGED_SLEEPING)) {
+                && !nm_device_get_unmanaged_flags(device, NM_UNMANAGED_MANAGER_DISABLED)) {
                 /* DHCP leases of software devices could have gone stale
                  * so we need to renew them. */
-                nm_device_update_dynamic_ip_setup(device, "wake up");
+                nm_device_update_dynamic_ip_setup(device,
+                                                  waking_from_suspend ? "wake up"
+                                                                      : "networking on");
                 continue;
             }
 
@@ -7455,7 +7469,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
                     ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED
                     : NM_DEVICE_STATE_REASON_NOW_MANAGED;
             nm_device_set_unmanaged_by_flags(device,
-                                             NM_UNMANAGED_SLEEPING,
+                                             NM_UNMANAGED_MANAGER_DISABLED,
                                              NM_UNMAN_FLAG_OP_SET_MANAGED,
                                              reason);
         }
@@ -8818,6 +8832,41 @@ nm_manager_emit_device_ifindex_changed(NMManager *self, NMDevice *device)
     g_signal_emit(self, signals[DEVICE_IFINDEX_CHANGED], 0, device);
 }
 
+void
+nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled)
+{
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+    gboolean          state_changed, state;
+
+    /* Only IPv4 supported for the moment */
+    if (addr_family != AF_INET)
+        return;
+
+    if (enabled) {
+        g_return_if_fail(priv->shared_connections_ip4_count < G_MAXUINT);
+        priv->shared_connections_ip4_count++;
+        state_changed = priv->shared_connections_ip4_count == 1;
+    } else {
+        g_return_if_fail(priv->shared_connections_ip4_count > 0);
+        priv->shared_connections_ip4_count--;
+        state_changed = priv->shared_connections_ip4_count == 0;
+    }
+
+    if (state_changed) {
+        state = priv->shared_connections_ip4_count > 0;
+        _LOGD(LOGD_SHARING, "sharing-ipv4 state change %d -> %d", !state, state);
+        g_signal_emit(self, signals[SHARING_IPV4_CHANGED], 0, state);
+    }
+}
+
+gboolean
+nm_manager_get_sharing_ipv4(NMManager *self)
+{
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+
+    return priv->shared_connections_ip4_count > 0;
+}
+
 /*****************************************************************************/
 
 NM_DEFINE_SINGLETON_REGISTER(NMManager);
@@ -9921,6 +9970,17 @@ nm_manager_class_init(NMManagerClass *manager_class)
                                                    G_TYPE_NONE,
                                                    1,
                                                    NM_TYPE_DEVICE);
+
+    signals[SHARING_IPV4_CHANGED] = g_signal_new(NM_MANAGER_SHARING_IPV4_CHANGED,
+                                                 G_OBJECT_CLASS_TYPE(object_class),
+                                                 G_SIGNAL_RUN_FIRST,
+                                                 0,
+                                                 NULL,
+                                                 NULL,
+                                                 NULL,
+                                                 G_TYPE_NONE,
+                                                 1,
+                                                 G_TYPE_BOOLEAN);
 }
 
 NMConfig *
diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h
index 3c5213c4..e10ca0d1 100644
--- a/src/core/nm-manager.h
+++ b/src/core/nm-manager.h
@@ -61,6 +61,7 @@
 #define NM_MANAGER_CONFIGURE_QUIT            "configure-quit"
 #define NM_MANAGER_INTERNAL_DEVICE_ADDED     "internal-device-added"
 #define NM_MANAGER_INTERNAL_DEVICE_REMOVED   "internal-device-removed"
+#define NM_MANAGER_SHARING_IPV4_CHANGED      "sharing-ipv4-changed"
 
 GType nm_manager_get_type(void);
 
@@ -212,6 +213,9 @@ struct _NMDnsManager;
 
 struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self);
 
+void     nm_manager_update_shared_connection(NMManager *self, int addr_family, gboolean enabled);
+gboolean nm_manager_get_sharing_ipv4(NMManager *self);
+
 /*****************************************************************************/
 
 void nm_manager_notify_delete_settings_connections(NMManager            *self,
diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c
index fbcee40d..0288795e 100644
--- a/src/core/nm-policy.c
+++ b/src/core/nm-policy.c
@@ -18,7 +18,6 @@
 #include "NetworkManagerUtils.h"
 #include "devices/nm-device.h"
 #include "devices/nm-device-factory.h"
-#include "devices/nm-device-private.h"
 #include "dns/nm-dns-manager.h"
 #include "nm-act-request.h"
 #include "nm-auth-utils.h"
@@ -98,6 +97,7 @@ typedef struct {
     bool updating_dns : 1;
 
     GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */
+
 } NMPolicyPrivate;
 
 struct _NMPolicy {
@@ -1845,7 +1845,7 @@ nm_policy_device_recheck_auto_activate_schedule(NMPolicy *self, NMDevice *device
 
     priv = NM_POLICY_GET_PRIVATE(self);
 
-    if (nm_manager_get_state(priv->manager) == NM_STATE_ASLEEP)
+    if (nm_manager_get_state(priv->manager) == NM_STATE_DISABLED)
         return;
 
     if (!nm_device_autoconnect_allowed(device))
@@ -2084,65 +2084,6 @@ unblock_autoconnect_for_ports_for_sett_conn(NMPolicy *self, NMSettingsConnection
 }
 
 static void
-refresh_forwarding(NMPolicy *self, NMDevice *device, gboolean is_activated_shared_device)
-{
-    NMActiveConnection *ac;
-    NMDevice           *tmp_device;
-    NMPolicyPrivate    *priv = NM_POLICY_GET_PRIVATE(self);
-    const CList        *tmp_lst;
-    gboolean            any_shared_active = false;
-    gint32              default_forwarding_v4;
-    const char         *new_value = NULL;
-
-    /* FIXME: This implementation is still inefficient because refresh_forwarding()
-     * is called every time a device goes up or down, requiring a full scan of all
-     * active connections to determine if any shared connection is active. */
-    nm_manager_for_each_active_connection (priv->manager, ac, tmp_lst) {
-        NMSettingIPConfig *s_ip;
-        NMDevice          *to_device = nm_active_connection_get_device(ac);
-
-        if (to_device) {
-            s_ip = nm_device_get_applied_setting(to_device, NM_TYPE_SETTING_IP4_CONFIG);
-            if (s_ip) {
-                if (nm_streq0(nm_device_get_effective_ip_config_method(to_device, AF_INET),
-                              NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
-                    any_shared_active = true;
-                    break;
-                }
-            }
-        }
-    }
-
-    default_forwarding_v4 = nm_platform_sysctl_get_int32(
-        NM_PLATFORM_GET,
-        NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/conf/default/forwarding"),
-        0);
-
-    new_value = any_shared_active ? "1" : (default_forwarding_v4 ? "1" : "0");
-
-    nm_manager_for_each_device (priv->manager, tmp_device, tmp_lst) {
-        NMDeviceState               state;
-        NMSettingIPConfigForwarding ipv4_forwarding;
-
-        state = nm_device_get_state(tmp_device);
-        if (state != NM_DEVICE_STATE_ACTIVATED)
-            continue;
-
-        ipv4_forwarding = nm_device_get_ipv4_forwarding(tmp_device);
-
-        if (ipv4_forwarding == NM_SETTING_IP_CONFIG_FORWARDING_AUTO
-            || (device == tmp_device && is_activated_shared_device)) {
-            gs_free char *sysctl_value = NULL;
-
-            sysctl_value = nm_device_sysctl_ip_conf_get(tmp_device, AF_INET, "forwarding");
-
-            if (!nm_streq0(sysctl_value, new_value))
-                nm_device_sysctl_ip_conf_set(tmp_device, AF_INET, "forwarding", new_value);
-        }
-    }
-}
-
-static void
 activate_port_or_children_connections(NMPolicy *self,
                                       NMDevice *device,
                                       gboolean  activate_children_connections_only)
@@ -2286,9 +2227,8 @@ device_state_changed(NMDevice           *device,
     NMPolicyPrivate      *priv = user_data;
     NMPolicy             *self = _PRIV_TO_SELF(priv);
     NMActiveConnection   *ac;
-    NMSettingsConnection *sett_conn                  = nm_device_get_settings_connection(device);
-    NMSettingConnection  *s_con                      = NULL;
-    gboolean              is_activated_shared_device = FALSE;
+    NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device);
+    NMSettingConnection  *s_con     = NULL;
 
     switch (nm_device_state_reason_check(reason)) {
     case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED:
@@ -2404,10 +2344,6 @@ device_state_changed(NMDevice           *device,
                 }
             }
         }
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
     case NM_DEVICE_STATE_ACTIVATED:
         if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) {
@@ -2440,20 +2376,11 @@ device_state_changed(NMDevice           *device,
         update_system_hostname(self, "routing and dns", TRUE);
         nm_dns_manager_end_updates(priv->dns_manager, __func__);
 
-        is_activated_shared_device =
-            nm_streq0(nm_device_get_effective_ip_config_method(device, AF_INET),
-                      NM_SETTING_IP4_CONFIG_METHOD_SHARED);
-        refresh_forwarding(self, device, is_activated_shared_device);
-        nm_device_set_refresh_forwarding_done(device, FALSE);
         break;
     case NM_DEVICE_STATE_UNMANAGED:
     case NM_DEVICE_STATE_UNAVAILABLE:
         if (old_state > NM_DEVICE_STATE_DISCONNECTED)
             update_routing_and_dns(self, FALSE, device);
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
     case NM_DEVICE_STATE_DEACTIVATING:
         if (sett_conn) {
@@ -2489,10 +2416,6 @@ device_state_changed(NMDevice           *device,
             }
         }
         ip6_remove_device_prefix_delegations(self, device);
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
     case NM_DEVICE_STATE_DISCONNECTED:
         g_signal_handlers_disconnect_by_func(device, device_dns_lookup_done, self);
@@ -2509,10 +2432,6 @@ device_state_changed(NMDevice           *device,
 
         /* Device is now available for auto-activation */
         nm_policy_device_recheck_auto_activate_schedule(self, device);
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
 
     case NM_DEVICE_STATE_PREPARE:
@@ -2528,10 +2447,6 @@ device_state_changed(NMDevice           *device,
             g_object_weak_unref(G_OBJECT(ac), pending_ac_gone, self);
             g_object_unref(self);
         }
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
     case NM_DEVICE_STATE_IP_CONFIG:
         /* We must have secrets if we got here. */
@@ -2542,10 +2457,6 @@ device_state_changed(NMDevice           *device,
                 sett_conn,
                 NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_FAILED,
                 FALSE);
-        if (!nm_device_get_refresh_forwarding_done(device)) {
-            refresh_forwarding(self, device, FALSE);
-            nm_device_set_refresh_forwarding_done(device, TRUE);
-        }
         break;
     case NM_DEVICE_STATE_SECONDARIES:
         if (sett_conn)