diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index f8b0dad9c8..6e9b04b34f 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -17980,6 +17980,14 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); } break; + case NM_DEVICE_STATE_DEACTIVATING: + /* When deactivating, certain devices are removed/disconnected after the + * STATE_CHANGED signal is sent and before the DHCP release packet + * can be sent. To ensure the release packet is sent, we cleanup DHCP + * before the signal is emitted*/ + _dev_ipdhcpx_cleanup(self, AF_INET, TRUE, FALSE); + _dev_ipdhcpx_cleanup(self, AF_INET6, TRUE, FALSE); + break; case NM_DEVICE_STATE_DISCONNECTED: if (old_state > NM_DEVICE_STATE_DISCONNECTED) { /* Ensure devices that previously assumed a connection now have @@ -18029,6 +18037,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, (guint32) state, (guint32) old_state, (guint32) reason); + g_signal_emit(self, signals[STATE_CHANGED], 0, diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 87dde2c3af..ada26de1bd 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -8146,6 +8146,27 @@ nm_manager_start(NMManager *self, GError **error) return TRUE; } +static int +compare_device_remove_order(const CList *a, const CList *b, const void *user_data) +{ + NMDevice *dev_a = c_list_entry(a, NMDevice, devices_lst); + NMDevice *dev_b = c_list_entry(b, NMDevice, devices_lst); + + gboolean a_has_dhcp = + nm_device_get_dhcp_config(dev_a, AF_INET) || nm_device_get_dhcp_config(dev_a, AF_INET6); + gboolean b_has_dhcp = + nm_device_get_dhcp_config(dev_b, AF_INET) || nm_device_get_dhcp_config(dev_b, AF_INET6); + gboolean a_is_software = nm_device_is_software(dev_a); + gboolean b_is_software = nm_device_is_software(dev_b); + + /* priority: software AND dhcp first, then dhcp only + * then everything else,*/ + uint a_score = a_has_dhcp ? (a_is_software ? 2 : 1) : 0; + uint b_score = b_has_dhcp ? (b_is_software ? 2 : 1) : 0; + + return b_score - a_score; +} + void nm_manager_stop(NMManager *self) { @@ -8167,6 +8188,12 @@ nm_manager_stop(NMManager *self) nm_dbus_manager_stop(nm_dbus_object_get_manager(NM_DBUS_OBJECT(self))); + /* When OVS internal interface or linux bridge holds DHCP, if we delete its + * physical interface first, then we cannot send out DHCP release request + * anymore. To fix that, we need to remove/deactivate software interfaces that + * holds DHCP config first. + */ + c_list_sort(&priv->devices_lst_head, compare_device_remove_order, NULL); while ((device = c_list_first_entry(&priv->devices_lst_head, NMDevice, devices_lst))) remove_device(self, device, TRUE);